diff options
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r-- | bgpd/bgp_attr.c | 968 |
1 files changed, 529 insertions, 439 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d43c104f..c5a710c8 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -38,32 +38,32 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" - + /* Attribute strings for logging. */ -static const struct message attr_str [] = -{ - { BGP_ATTR_ORIGIN, "ORIGIN" }, - { BGP_ATTR_AS_PATH, "AS_PATH" }, - { BGP_ATTR_NEXT_HOP, "NEXT_HOP" }, - { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" }, - { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" }, - { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, - { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, - { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, +static const struct message attr_str [] = +{ + { BGP_ATTR_ORIGIN, "ORIGIN" }, + { BGP_ATTR_AS_PATH, "AS_PATH" }, + { BGP_ATTR_NEXT_HOP, "NEXT_HOP" }, + { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" }, + { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" }, + { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, + { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, + { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, - { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" }, + { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" }, { BGP_ATTR_DPA, "DPA" }, { BGP_ATTR_ADVERTISER, "ADVERTISER"} , { BGP_ATTR_RCID_PATH, "RCID_PATH" }, { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" }, - { BGP_ATTR_AS4_PATH, "AS4_PATH" }, - { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, + { BGP_ATTR_AS4_PATH, "AS4_PATH" }, + { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, }; static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); - + static struct hash *cluster_hash; static void * @@ -107,7 +107,7 @@ int cluster_loop_check (struct cluster_list *cluster, struct in_addr originator) { int i; - + for (i = 0; i < cluster->length / 4; i++) if (cluster->list[i].s_addr == originator.s_addr) return 1; @@ -118,7 +118,6 @@ static unsigned int cluster_hash_key_make (void *p) { const struct cluster_list *cluster = p; - return jhash(cluster->list, cluster->length, 0); } @@ -156,7 +155,7 @@ cluster_dup (struct cluster_list *cluster) } else new->list = NULL; - + return new; } #endif @@ -199,7 +198,7 @@ cluster_finish (void) hash_free (cluster_hash); cluster_hash = NULL; } - + /* Unknown transit attribute. */ static struct hash *transit_hash; @@ -250,8 +249,7 @@ transit_unintern (struct transit *transit) static unsigned int transit_hash_key_make (void *p) { - const struct transit * transit = p; - + const struct transit * transit = p ; return jhash(transit->val, transit->length, 0); } @@ -277,7 +275,7 @@ transit_finish (void) hash_free (transit_hash); transit_hash = NULL; } - + /* Attribute hash routines. */ static struct hash *attrhash; @@ -337,18 +335,13 @@ attrhash_key_make (void *p) { const struct attr * attr = (struct attr *) p; uint32_t key = 0; -#define MIX(val) key = jhash_1word(val, key) +#define MIX(val) key = jhash_1word(val, key) MIX(attr->origin); MIX(attr->nexthop.s_addr); MIX(attr->med); MIX(attr->local_pref); - key += attr->origin; - key += attr->nexthop.s_addr; - key += attr->med; - key += attr->local_pref; - if (attr->extra) { MIX(attr->extra->aggregator_as); @@ -356,12 +349,12 @@ attrhash_key_make (void *p) MIX(attr->extra->weight); MIX(attr->extra->mp_nexthop_global_in.s_addr); } - + if (attr->aspath) MIX(aspath_key_make (attr->aspath)); if (attr->community) MIX(community_hash_make (attr->community)); - + if (attr->extra) { if (attr->extra->ecommunity) @@ -397,7 +390,7 @@ attrhash_cmp (const void *p1, const void *p2) { const struct attr_extra *ae1 = attr1->extra; const 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 @@ -439,14 +432,14 @@ attr_show_all_iterator (struct hash_backet *backet, struct vty *vty) { struct attr *attr = backet->data; - vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, - inet_ntoa (attr->nexthop), VTY_NEWLINE); + vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, + safe_inet_ntoa (attr->nexthop), VTY_NEWLINE); } void attr_show_all (struct vty *vty) { - hash_iterate (attrhash, + hash_iterate (attrhash, (void (*)(struct hash_backet *, void *)) attr_show_all_iterator, vty); @@ -469,7 +462,38 @@ bgp_attr_hash_alloc (void *p) return attr; } -/* Internet argument attribute. */ +/*------------------------------------------------------------------------------ + * Internet argument attribute. + * + * 1. "internalise" and increase reference count for each of: + * + * attr->aspath + * attr->community + * attr->extra->ecommunity + * attr->extra->cluster + * attr->extra->transit + * + * Noting that the reference count for each of these is zero if they have not + * yet been internalised. + * + * Each of these pointers is updated to point at either a new entry in the + * relevant attribute store, or at the existing entry. + * + * 2. "internalise" the complete attribute object and increase its reference + * count. + * + * If the attribute collection is new, then this function returns a pointer + * to a brand new attribute object, complete with a copy of the attr->extra. + * + * If the attribute collection is not new, then this function returns a + * pointer to the stored attribute object. + * + * In any event, the pointer returned != pointer passed in. + * + * NB: the incoming attr reference count is ignored. + * + * Note that the original attr object remains with its own attr->extra object. + */ struct attr * bgp_attr_intern (struct attr *attr) { @@ -493,14 +517,14 @@ bgp_attr_intern (struct attr *attr) if (attr->extra) { 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) { @@ -517,21 +541,23 @@ bgp_attr_intern (struct attr *attr) attre->transit->refcnt++; } } - + find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc); find->refcnt++; - + return find; } - -/* Make network statement's attribute. */ +/* Make network statement's attribute. + * + * All elements are interned, but not the attribute set itself. + */ 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 (); @@ -553,15 +579,15 @@ 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; } @@ -577,7 +603,7 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, 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); @@ -613,154 +639,183 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, new = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); - + aspath_unintern (&new->aspath); return new; } /* Unintern just the sub-components of the attr, but not the attr */ -void -bgp_attr_unintern_sub (struct attr *attr) +extern void +bgp_attr_unintern_sub (struct attr *attr, bool free_extra) { /* aspath refcount shoud be decrement. */ if (attr->aspath) aspath_unintern (&attr->aspath); UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH); - + if (attr->community) community_unintern (&attr->community); UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES); - + if (attr->extra) { if (attr->extra->ecommunity) ecommunity_unintern (&attr->extra->ecommunity); UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES); - + if (attr->extra->cluster) cluster_unintern (attr->extra->cluster); UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST); - + if (attr->extra->transit) transit_unintern (attr->extra->transit); - } -} -/* Free bgp attribute and aspath. */ + if (free_extra) + bgp_attr_extra_free (attr) ; + } +} + +/*------------------------------------------------------------------------------ + * Free bgp attribute and aspath. + * + * For all the elements of the given attributes: + * + * if the reference count != 0, decrement it + * if the reference count is now zero, remove from hash table and discard + * stored value. + * + * For the attribute object itself: + * + * decrement the reference count + * if the reference count is now zero, remove from hash table and discard + * stored value. + * + * So... do NOT do this to a set of attributes whose elements have not been + * interned ! + * + * Can do this to an attribute object which has not been interned, because its + * reference count SHOULD be zero. + */ void bgp_attr_unintern (struct attr **attr) { - struct attr *ret; - struct attr tmp; - - /* Decrement attribute reference. */ - (*attr)->refcnt--; - + struct attr tmp ; + struct attr_extra tmp_extra ; + + /* Take copy of attributes so that can unintern sub-objects */ tmp = *(*attr); - + if ((*attr)->extra) { - tmp.extra = bgp_attr_extra_new (); + tmp.extra = &tmp_extra ; memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra)); } - - /* 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); - *attr = NULL; - } - - bgp_attr_unintern_sub (&tmp); -} + /* If reference becomes zero then free attribute object. */ + if ((*attr)->refcnt != 0) + { + --(*attr)->refcnt ; + if ((*attr)->refcnt == 0) + { + struct attr *ret; + ret = hash_release (attrhash, *attr); + assert (ret != NULL); + bgp_attr_extra_free (*attr); + XFREE (MTYPE_ATTR, *attr); /* sets *attr = NULL */ + } ; + } ; + + /* Now the sub-objects */ + bgp_attr_unintern_sub (&tmp, false) ; /* false => don't free extra */ +} + +/*------------------------------------------------------------------------------ + * Release any element whose reference count is zero. + * + * This is used where attributes have been replaced, but not internalised, and + * which are no longer of interest -- typically where a route-map returns DENY. + */ void bgp_attr_flush (struct attr *attr) { - if (attr->aspath && ! attr->aspath->refcnt) + if (attr->aspath && (attr->aspath->refcnt == 0)) aspath_free (attr->aspath); - if (attr->community && ! attr->community->refcnt) + if (attr->community && (attr->community->refcnt == 0)) community_free (attr->community); if (attr->extra) { struct attr_extra *attre = attr->extra; - - if (attre->ecommunity && ! attre->ecommunity->refcnt) + if (attre->ecommunity && (attre->ecommunity->refcnt == 0)) ecommunity_free (&attre->ecommunity); - if (attre->cluster && ! attre->cluster->refcnt) + if (attre->cluster && (attre->cluster->refcnt == 0)) cluster_free (attre->cluster); - if (attre->transit && ! attre->transit->refcnt) + if (attre->transit && (attre->transit->refcnt == 0)) transit_free (attre->transit); } } -/* Implement draft-scudder-idr-optional-transitive behaviour and +/* Implement draft-ietf-idr-optional-transitive behaviour and * avoid resetting sessions for malformed attributes which are * are partial/optional and hence where the error likely was not * introduced by the sending neighbour. */ static bgp_attr_parse_ret_t -bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, - u_char subcode, u_char *startp, bgp_size_t length) +bgp_attr_malformed (struct peer *peer, u_char attr_type, u_char flag, + u_char subcode, u_char *startp, bgp_size_t length) { /* Only relax error handling for eBGP peers */ - if (peer_sort (peer) != BGP_PEER_EBGP) + if (peer_sort (peer) == BGP_PEER_EBGP) { - bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, - startp, length); - return BGP_ATTR_PARSE_ERROR; + switch (attr_type) + { + /* where an optional attribute is inconsequential, e.g. it does not + * affect route selection, and can be safely ignored then any such + * attributes which are malformed should just be ignored and the + * route processed as normal. + */ + case BGP_ATTR_AS4_AGGREGATOR: + case BGP_ATTR_AGGREGATOR: + case BGP_ATTR_ATOMIC_AGGREGATE: + return BGP_ATTR_PARSE_PROCEED; - } - - switch (type) { - /* where an optional attribute is inconsequential, e.g. it does not affect - * route selection, and can be safely ignored then any such attributes - * which are malformed should just be ignored and the route processed as - * normal. - */ - case BGP_ATTR_AS4_AGGREGATOR: - case BGP_ATTR_AGGREGATOR: - case BGP_ATTR_ATOMIC_AGGREGATE: - return BGP_ATTR_PARSE_PROCEED; - - /* Core attributes, particularly ones which may influence route - * selection should always cause session resets - */ - case BGP_ATTR_ORIGIN: - case BGP_ATTR_AS_PATH: - case BGP_ATTR_NEXT_HOP: - case BGP_ATTR_MULTI_EXIT_DISC: - case BGP_ATTR_LOCAL_PREF: - case BGP_ATTR_COMMUNITIES: - case BGP_ATTR_ORIGINATOR_ID: - case BGP_ATTR_CLUSTER_LIST: - case BGP_ATTR_MP_REACH_NLRI: - case BGP_ATTR_MP_UNREACH_NLRI: - case BGP_ATTR_EXT_COMMUNITIES: - bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, - startp, length); - return BGP_ATTR_PARSE_ERROR; - } - - /* Partial optional attributes that are malformed should not cause - * the whole session to be reset. Instead treat it as a withdrawal - * of the routes, if possible. - */ - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS) - && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) - && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - return BGP_ATTR_PARSE_WITHDRAW; - - /* default to reset */ + /* Core attributes, particularly ones which may influence route + * selection should always cause session resets + */ + case BGP_ATTR_ORIGIN: + case BGP_ATTR_AS_PATH: + case BGP_ATTR_NEXT_HOP: + case BGP_ATTR_MULTI_EXIT_DISC: + case BGP_ATTR_LOCAL_PREF: + case BGP_ATTR_COMMUNITIES: + case BGP_ATTR_ORIGINATOR_ID: + case BGP_ATTR_CLUSTER_LIST: + case BGP_ATTR_MP_REACH_NLRI: + case BGP_ATTR_MP_UNREACH_NLRI: + case BGP_ATTR_EXT_COMMUNITIES: + break ; + + /* Partial optional attributes that are malformed should not cause + * the whole session to be reset. Instead treat it as a withdrawal + * of the routes, if possible. + */ + default: + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS) && + CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) && + CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + return BGP_ATTR_PARSE_WITHDRAW; + break ; + } ; + } ; + + /* default to reset */ + bgp_peer_down_error_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode, + startp, length) ; return BGP_ATTR_PARSE_ERROR; -} +} ; /* Get origin attribute of the update message. */ static bgp_attr_parse_ret_t -bgp_attr_origin (struct peer *peer, bgp_size_t length, +bgp_attr_origin (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { bgp_size_t total; @@ -775,11 +830,11 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, attribute (type, length and value). */ if (flag != BGP_ATTR_FLAG_TRANS) { - zlog (peer->log, LOG_ERR, + zlog (peer->log, LOG_ERR, "Origin attribute flag isn't transitive %d", flag); return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* If any recognized attribute has Attribute Length that conflicts @@ -792,8 +847,8 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", length); return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } /* Fetch origin attribute. */ @@ -809,60 +864,87 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", attr->origin); return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_INVAL_ORIGIN, - startp, total); + BGP_NOTIFY_UPDATE_INVAL_ORIGIN, + startp, total); } /* Set oring attribute flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); - return 0; -} - -/* Parse AS path information. This function is wrapper of - aspath_parse. */ -static int -bgp_attr_aspath (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) + return BGP_ATTR_PARSE_PROCEED ; +} + +/*------------------------------------------------------------------------------ + * Parse AS path information. This function is wrapper of aspath_parse. + * + * Parses AS_PATH or AS4_PATH. + * + * Returns: if valid: BGP_ATTR_PARSE_PROCEED + * and sets *p_asp = address of struct aspath in the hash of + * known aspaths, with reference count incremented. + * + * else: whatever bgp_attr_malformed() decides. + * + * NB: empty AS path (length == 0) is valid. The returned struct aspath will + * have segments == NULL and str == zero length string (unique). + */ +static bgp_attr_parse_ret_t +bgp_attr_aspath (struct peer *peer, struct aspath** p_asp, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp, + u_char attr_type) { - bgp_size_t total; + u_char require ; + bool as4_path = (attr_type == BGP_ATTR_AS4_PATH) ; - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Check the attribute flags */ + require = as4_path ? BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL + : BGP_ATTR_FLAG_TRANS ; - /* Flag check. */ - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) - || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require) { - zlog (peer->log, LOG_ERR, - "As-Path attribute flag isn't transitive %d", flag); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } + bgp_size_t total; - /* - * peer with AS4 => will get 4Byte ASnums - * otherwise, will get 16 Bit - */ - attr->aspath = aspath_parse (peer->ibuf, length, - CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); + *p_asp = NULL ; + + if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "%s attribute flag isn't transitive 0x%02X", + as4_path ? "AS4_PATH" : "AS_PATH", flag) ; + + if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "%s attribute flag must %sbe optional 0x%02X", + as4_path ? "AS4_PATH" : "AS_PATH", + (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + return bgp_attr_malformed (peer, attr_type, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } ; - /* In case of IBGP, length will be zero. */ - if (! attr->aspath) + /* Parse the AS_PATH/AS4_PATH body. + * + * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN + * AS4_PATH 4Byte ASN + */ + *p_asp = aspath_parse (peer->ibuf, length, + PEER_CAP_AS4_USE(peer) || as4_path, as4_path) ; + if (*p_asp == NULL) { - zlog (peer->log, LOG_ERR, - "Malformed AS path from %s, length is %d", - peer->host, length); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); - } + zlog (peer->log, LOG_ERR, "Malformed %s from %s, length is %d", + as4_path ? "AS4_PATH" : "AS4_PATH", peer->host, length); - /* Set aspath attribute flag. */ - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + return bgp_attr_malformed (peer, attr_type, flag, + BGP_NOTIFY_UPDATE_MAL_AS_PATH, + NULL, 0); + } ; + + /* Success ! + */ + attr->flag |= ATTR_FLAG_BIT (attr_type) ; return BGP_ATTR_PARSE_PROCEED; -} +} ; static bgp_attr_parse_ret_t bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) @@ -876,30 +958,33 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) */ struct bgp *bgp = peer->bgp; struct aspath *aspath; + bgp_peer_sort_t sort = peer_sort(peer) ; bgp = peer->bgp; - + /* Confederation sanity check. */ - if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || - (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) + if ( ((sort == BGP_PEER_CONFED) && ! aspath_left_confed_check (attr->aspath)) + || ((sort == BGP_PEER_EBGP) && aspath_confed_check (attr->aspath)) ) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + BGP_NOTIFY_UPDATE_MAL_AS_PATH, + NULL, 0); } /* First AS check for EBGP. */ if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) { - if (peer_sort (peer) == BGP_PEER_EBGP + if (sort == BGP_PEER_EBGP && ! aspath_firstas_check (attr->aspath, peer->as)) { zlog (peer->log, LOG_ERR, "%s incorrect first AS (must be %u)", peer->host, peer->as); + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + BGP_NOTIFY_UPDATE_MAL_AS_PATH, + NULL, 0); } } @@ -916,51 +1001,9 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) return BGP_ATTR_PARSE_PROCEED; } -/* Parse AS4 path information. This function is another wrapper of - aspath_parse. */ -static int -bgp_attr_as4_path (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp, - struct aspath **as4_path) -{ - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - - /* Flag check. */ - if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) - || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - { - zlog (peer->log, LOG_ERR, - "As4-Path attribute flag isn't optional/transitive %d", flag); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - - *as4_path = aspath_parse (peer->ibuf, length, 1); - - /* In case of IBGP, length will be zero. */ - if (!*as4_path) - { - zlog (peer->log, LOG_ERR, - "Malformed AS4 path from %s, length is %d", - peer->host, length); - return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); - } - - /* Set aspath attribute flag. */ - if (as4_path) - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); - - return BGP_ATTR_PARSE_PROCEED; -} - /* Nexthop attribute. */ static bgp_attr_parse_ret_t -bgp_attr_nexthop (struct peer *peer, bgp_size_t length, +bgp_attr_nexthop (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { bgp_size_t total; @@ -971,11 +1014,12 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) { - zlog (peer->log, LOG_ERR, + zlog (peer->log, LOG_ERR, "Origin attribute flag isn't transitive %d", flag); + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Check nexthop attribute length. */ @@ -985,8 +1029,8 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, length); return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf); @@ -997,7 +1041,7 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, /* MED atrribute. */ static bgp_attr_parse_ret_t -bgp_attr_med (struct peer *peer, bgp_size_t length, +bgp_attr_med (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { bgp_size_t total; @@ -1007,12 +1051,12 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, /* Length check. */ if (length != 4) { - zlog (peer->log, LOG_ERR, + zlog (peer->log, LOG_ERR, "MED attribute length isn't four [%d]", length); return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } attr->med = stream_getl (peer->ibuf); @@ -1024,7 +1068,7 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, /* Local preference attribute. */ static bgp_attr_parse_ret_t -bgp_attr_local_pref (struct peer *peer, bgp_size_t length, +bgp_attr_local_pref (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { /* If it is contained in an UPDATE message that is received from an @@ -1036,9 +1080,9 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } - if (length == 4) + if (length == 4) attr->local_pref = stream_getl (peer->ibuf); - else + else attr->local_pref = 0; /* Set atomic aggregate flag. */ @@ -1049,7 +1093,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, /* Atomic aggregate. */ static int -bgp_attr_atomic (struct peer *peer, bgp_size_t length, +bgp_attr_atomic (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { if (length != 0) @@ -1057,8 +1101,8 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } /* Set atomic aggregate flag. */ @@ -1074,21 +1118,22 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, { int wantedlen = 6; struct attr_extra *attre = bgp_attr_extra_get (attr); - + /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ - if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) + if ( PEER_CAP_AS4_USE(peer) ) wantedlen = 8; - + if (length != wantedlen) { - zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length); + zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, + length); return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } - - if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) + + if ( PEER_CAP_AS4_USE(peer) ) attre->aggregator_as = stream_getl (peer->ibuf); else attre->aggregator_as = stream_getw (peer->ibuf); @@ -1103,7 +1148,7 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, /* New Aggregator attribute */ static bgp_attr_parse_ret_t bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, + struct attr *attr, u_char flag, as_t *as4_aggregator_as, struct in_addr *as4_aggregator_addr) { @@ -1111,8 +1156,8 @@ bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } *as4_aggregator_as = stream_getl (peer->ibuf); as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); @@ -1132,8 +1177,8 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, int ignore_as4_path = 0; struct aspath *newpath; struct attr_extra *attre = attr->extra; - - if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) + + if ( PEER_CAP_AS4_USE(peer) ) { /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR * if given. @@ -1145,15 +1190,15 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))) zlog_debug ("[AS4] %s %s AS4_PATH", peer->host, "AS4 capable peer, yet it sent"); - + if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) zlog_debug ("[AS4] %s %s AS4_AGGREGATOR", peer->host, "AS4 capable peer, yet it sent"); } - + return BGP_ATTR_PARSE_PROCEED; } - + if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH)) && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))) { @@ -1164,12 +1209,13 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, * But... yeah, paranoia * Take this as a "malformed attribute" */ - zlog (peer->log, LOG_ERR, + zlog (peer->log, LOG_ERR, "%s BGP not AS4 capable peer sent AS4_PATH but" " no AS_PATH, cant do anything here", peer->host); + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_ATTR, - NULL, 0); + BGP_NOTIFY_UPDATE_MAL_ATTR, + NULL, 0); } /* We have a asn16 peer. First, look for AS4_AGGREGATOR @@ -1180,11 +1226,11 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) { assert (attre); - + /* received both. * if the as_number in aggregator is not AS_TRANS, * then AS4_AGGREGATOR and AS4_PATH shall be ignored - * and the Aggregator shall be taken as + * and the Aggregator shall be taken as * info on the aggregating node, and the AS_PATH * shall be taken as the AS_PATH * otherwise @@ -1197,7 +1243,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, { /* ignore */ if ( BGP_DEBUG(as4, AS4)) - zlog_debug ("[AS4] %s BGP not AS4 capable peer" + zlog_debug ("[AS4] %s BGP not AS4 capable peer" " send AGGREGATOR != AS_TRANS and" " AS4_AGGREGATOR, so ignore" " AS4_AGGREGATOR and AS4_PATH", peer->host); @@ -1220,8 +1266,10 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] %s BGP not AS4 capable peer send" " AS4_AGGREGATOR but no AGGREGATOR, will take" - " it as if AGGREGATOR with AS_TRANS had been there", peer->host); - (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator; + " it as if AGGREGATOR with AS_TRANS had been there", + peer->host); + attre = bgp_attr_extra_get (attr) ; + attre->aggregator_as = as4_aggregator; /* sweep it under the carpet and simulate a "good" AGGREGATOR */ attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); } @@ -1239,29 +1287,29 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, /* Community attribute. */ static bgp_attr_parse_ret_t -bgp_attr_community (struct peer *peer, bgp_size_t length, +bgp_attr_community (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { bgp_size_t total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - + if (length == 0) { attr->community = NULL; return BGP_ATTR_PARSE_PROCEED; } - + attr->community = community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length); - + /* XXX: fix community_parse to use stream API and remove this */ stream_forward_getp (peer->ibuf, length); if (!attr->community) return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - startp, total); - + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); return BGP_ATTR_PARSE_PROCEED; @@ -1269,7 +1317,7 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, /* Originator ID attribute. */ static bgp_attr_parse_ret_t -bgp_attr_originator_id (struct peer *peer, bgp_size_t length, +bgp_attr_originator_id (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { if (length != 4) @@ -1277,11 +1325,11 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } - (bgp_attr_extra_get (attr))->originator_id.s_addr + (bgp_attr_extra_get (attr))->originator_id.s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); @@ -1291,7 +1339,7 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, /* Cluster list attribute. */ static bgp_attr_parse_ret_t -bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, +bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { /* Check length. */ @@ -1300,13 +1348,13 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } - (bgp_attr_extra_get (attr))->cluster + (bgp_attr_extra_get (attr))->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length); - + /* XXX: Fix cluster_parse to use stream API and then remove this */ stream_forward_getp (peer->ibuf, length); @@ -1316,7 +1364,7 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, } /* Multiprotocol reachability information parse. */ -int +extern bgp_attr_parse_ret_t bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, struct bgp_nlri *mp_update) { @@ -1327,35 +1375,35 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, int ret; struct stream *s; struct attr_extra *attre = bgp_attr_extra_get(attr); - + /* Set end of packet. */ s = BGP_INPUT(peer); start = stream_get_getp(s); - + /* safe to read statically sized header? */ #define BGP_MP_REACH_MIN_SIZE 5 #define LEN_LEFT (length - (stream_get_getp(s) - start)) if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) { - zlog_info ("%s: %s sent invalid length, %lu", + zlog_info ("%s: %s sent invalid length, %lu", __func__, peer->host, (unsigned long)length); return BGP_ATTR_PARSE_ERROR; } - + /* Load AFI, SAFI. */ afi = stream_getw (s); safi = stream_getc (s); /* Get nexthop length. */ attre->mp_nexthop_len = stream_getc (s); - + if (LEN_LEFT < attre->mp_nexthop_len) { - zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", + zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", __func__, peer->host, attre->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR; } - + /* Nexthop length check. */ switch (attre->mp_nexthop_len) { @@ -1388,7 +1436,9 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, 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, + zlog_debug ("%s got two nexthop %s %s " + "but second one is not a link-local nexthop", + peer->host, inet_ntop (AF_INET6, &attre->mp_nexthop_global, buf1, INET6_ADDRSTRLEN), inet_ntop (AF_INET6, &attre->mp_nexthop_local, @@ -1399,7 +1449,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, break; #endif /* HAVE_IPV6 */ default: - zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", + zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR; } @@ -1410,14 +1460,14 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, __func__, peer->host); return BGP_ATTR_PARSE_ERROR; } - + { - u_char val; + u_char val; if ((val = stream_getc (s))) zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field", peer->host, val); } - + /* must have nrli_len, what is left of the attribute */ nlri_len = LEN_LEFT; if ((!nlri_len) || (nlri_len > STREAM_READABLE(s))) @@ -1426,11 +1476,11 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, __func__, peer->host); return BGP_ATTR_PARSE_ERROR; } - + if (safi != BGP_SAFI_VPNV4) { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); - if (ret < 0) + if (ret < 0) { zlog_info ("%s: (%s) NLRI doesn't pass sanity check", __func__, peer->host); @@ -1450,8 +1500,8 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, } /* Multiprotocol unreachable parse */ -int -bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, +extern bgp_attr_parse_ret_t +bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, struct bgp_nlri *mp_withdraw) { struct stream *s; @@ -1461,14 +1511,14 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, int ret; s = peer->ibuf; - + #define BGP_MP_UNREACH_MIN_SIZE 3 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) return BGP_ATTR_PARSE_ERROR; - + afi = stream_getw (s); safi = stream_getc (s); - + withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; if (safi != BGP_SAFI_VPNV4) @@ -1490,16 +1540,17 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, /* Extended Community attribute. */ static bgp_attr_parse_ret_t -bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, +bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { bgp_size_t total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - + if (length == 0) { if (attr->extra) attr->extra->ecommunity = NULL; + /* Empty extcomm doesn't seem to be invalid per se */ return BGP_ATTR_PARSE_PROCEED; } @@ -1508,12 +1559,12 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); - + if (!attr->extra->ecommunity) - return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, - flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - startp, total); - + return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, flag, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); return BGP_ATTR_PARSE_PROCEED; @@ -1531,9 +1582,9 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Unknown attribute is received (type %d, length %d)", peer->host, type, length); - + if (BGP_DEBUG (events, EVENTS)) - zlog (peer->log, LOG_DEBUG, + zlog (peer->log, LOG_DEBUG, "Unknown attribute type %d length %d is received", type, length); /* Forward read pointer of input stream. */ @@ -1549,8 +1600,8 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { return bgp_attr_malformed (peer, type, flag, - BGP_NOTIFY_UPDATE_UNREC_ATTR, - startp, total); + BGP_NOTIFY_UPDATE_UNREC_ATTR, + startp, total); } /* Unrecognized non-transitive optional attributes must be quietly @@ -1571,7 +1622,7 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, transit = attre->transit; if (transit->val) - transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, + transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, transit->length + total); else transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total); @@ -1582,8 +1633,25 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, return BGP_ATTR_PARSE_PROCEED; } -/* Read attribute of update packet. This function is called from - bgp_update() in bgpd.c. */ +/*------------------------------------------------------------------------------ + * Read attribute of update packet. + * + * This function is called from bgp_update() in bgpd.c. + * + * NB: expects the structures pointed to by: + * + * attr + * mp_update + * mp_withdraw + * + * to be zeroised on entry to this function. + * + * Any elements in attr or attr->extra will be internalised as they are set. + * (So their reference counts will *not* be zero.) + * + * However, the attr object itself is NOT internalised. + * (So its reference count will be zero.) + */ bgp_attr_parse_ret_t bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) @@ -1606,7 +1674,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, /* End pointer of BGP attribute. */ endp = BGP_INPUT_PNT (peer) + size; - + /* Get attributes to the end of attribute length. */ while (BGP_INPUT_PNT (peer) < endp) { @@ -1614,14 +1682,15 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN) { /* XXX warning: long int format, int arg (arg 5) */ - zlog (peer->log, LOG_WARNING, + zlog (peer->log, LOG_WARNING, "%s error BGP attribute length %lu is smaller than min len", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + if (as4_path != NULL) + aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } @@ -1634,42 +1703,44 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) { - zlog (peer->log, LOG_WARNING, + zlog (peer->log, LOG_WARNING, "%s Extended length set, but just %lu bytes of attr header", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + if (as4_path != NULL) + aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } - /* Check extended attribue length bit. */ + /* Check extended attribute length bit. */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) length = stream_getw (BGP_INPUT (peer)); else length = stream_getc (BGP_INPUT (peer)); - - /* If any attribute appears more than once in the UPDATE - message, then the Error Subcode is set to Malformed Attribute - List. */ + /* If any attribute appears more than once in the UPDATE + * message, then the Error Subcode is set to Malformed Attribute + * List. + */ if (CHECK_BITMAP (seen, type)) { zlog (peer->log, LOG_WARNING, "%s error BGP attribute type %d appears twice in a message", peer->host, type); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + if (as4_path != NULL) + aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } /* Set type to bitmap to check duplicate attribute. `type' is - unsigned char so it never overflow bitmap range. */ - + * unsigned char so it never overflow bitmap range. + */ SET_BITMAP (seen, type); /* Overflow check. */ @@ -1677,11 +1748,15 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (attr_endp > endp) { - zlog (peer->log, LOG_WARNING, - "%s BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + zlog (peer->log, LOG_WARNING, + "%s BGP type %d length %d is too large, " + "attribute total length is %d. attr_endp is %p. endp is %p", + peer->host, type, length, size, attr_endp, endp); + + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + if (as4_path != NULL) + aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } @@ -1692,12 +1767,14 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_origin (peer, length, attr, flag, startp); break; case BGP_ATTR_AS_PATH: - ret = bgp_attr_aspath (peer, length, attr, flag, startp); - break; + ret = bgp_attr_aspath (peer, &attr->aspath, length, attr, flag, + startp, BGP_ATTR_AS_PATH); + break; case BGP_ATTR_AS4_PATH: - ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path); + ret = bgp_attr_aspath (peer, &as4_path, length, attr, flag, + startp, BGP_ATTR_AS4_PATH); break; - case BGP_ATTR_NEXT_HOP: + case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (peer, length, attr, flag, startp); break; case BGP_ATTR_MULTI_EXIT_DISC: @@ -1714,7 +1791,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, break; case BGP_ATTR_AS4_AGGREGATOR: ret = bgp_attr_as4_aggregator (peer, length, attr, flag, - &as4_aggregator, + &as4_aggregator, &as4_aggregator_addr); break; case BGP_ATTR_COMMUNITIES: @@ -1739,101 +1816,109 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); break; } - + /* If hard error occured immediately return to the caller. */ if (ret == BGP_ATTR_PARSE_ERROR) { zlog (peer->log, LOG_WARNING, - "%s: Attribute %s, parse error", - peer->host, + "%s: Attribute %s, parse error", + peer->host, LOOKUP (attr_str, type)); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); - if (as4_path) + + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + if (as4_path != NULL) aspath_unintern (&as4_path); return ret; } + if (ret == BGP_ATTR_PARSE_WITHDRAW) { - zlog (peer->log, LOG_WARNING, "%s: Attribute %s, parse error - treating as withdrawal", peer->host, LOOKUP (attr_str, type)); - if (as4_path) + + if (as4_path != NULL) aspath_unintern (&as4_path); return ret; } - + /* Check the fetched length. */ if (BGP_INPUT_PNT (peer) != attr_endp) { - zlog (peer->log, LOG_WARNING, - "%s: BGP attribute %s, fetch error", + zlog (peer->log, LOG_WARNING, + "%s: BGP attribute %s, fetch error", peer->host, LOOKUP (attr_str, type)); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - if (as4_path) + + if (type == BGP_ATTR_AS_PATH) + { + zlog (peer->log, LOG_WARNING, + "%s: is %sAS4", + peer->host, + PEER_CAP_AS4_USE(peer) ? "" : "NOT ") ; + } ; + + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + if (as4_path != NULL) aspath_unintern (&as4_path); - return BGP_ATTR_PARSE_ERROR; + return BGP_ATTR_PARSE_ERROR; } } /* Check final read pointer is same as end pointer. */ if (BGP_INPUT_PNT (peer) != endp) { - zlog (peer->log, LOG_WARNING, + zlog (peer->log, LOG_WARNING, "%s BGP attribute %s, length mismatch", peer->host, LOOKUP (attr_str, type)); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - if (as4_path) + + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + if (as4_path != NULL) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } - /* + /* * At this place we can see whether we got AS4_PATH and/or * AS4_AGGREGATOR from a 16Bit peer and act accordingly. * We can not do this before we've read all attributes because * the as4 handling does not say whether AS4_PATH has to be sent * after AS_PATH or not - and when AS4_AGGREGATOR will be send * in relationship to AGGREGATOR. + * * So, to be defensive, we are not relying on any order and read * all attributes first, including these 32bit ones, and now, * afterwards, we look what and if something is to be done for as4. */ - if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path, - as4_aggregator, &as4_aggregator_addr)) - { - if (as4_path) - aspath_unintern (&as4_path); - return BGP_ATTR_PARSE_ERROR; - } + ret = bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path, + as4_aggregator, &as4_aggregator_addr) ; /* At this stage, we have done all fiddling with as4, and the * resulting info is in attr->aggregator resp. attr->aspath * so we can chuck as4_aggregator and as4_path alltogether in * order to save memory - */ - if (as4_path) - { - aspath_unintern (&as4_path); /* unintern - it is in the hash */ - /* The flag that we got this is still there, but that does not - * do any trouble - */ - } - /* + * * The "rest" of the code does nothing with as4_aggregator. * there is no memory attached specifically which is not part * of the attr. * so ignoring just means do nothing. */ - /* - * Finally do the checks on the aspath we did not do yet + if (as4_path != NULL) + { + /* The flag that we got this is still there, but that does not + * do any trouble + */ + aspath_unintern (&as4_path); + as4_path = NULL ; + } ; + + if (ret != BGP_ATTR_PARSE_PROCEED) + return ret; + + /* Finally do the checks on the aspath we did not do yet * because we waited for a potentially synthesized aspath. */ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) @@ -1855,7 +1940,7 @@ int bgp_attr_check (struct peer *peer, struct attr *attr) { u_char type = 0; - + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) type = BGP_ATTR_ORIGIN; @@ -1871,18 +1956,18 @@ bgp_attr_check (struct peer *peer, struct attr *attr) if (type) { - zlog (peer->log, LOG_WARNING, + zlog (peer->log, LOG_WARNING, "%s Missing well-known attribute %d.", peer->host, type); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MISS_ATTR, - &type, 1); + + bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MISS_ATTR, + &type, 1); return BGP_ATTR_PARSE_ERROR; } return BGP_ATTR_PARSE_PROCEED; } - + int stream_put_prefix (struct stream *, struct prefix *); /* Make attribute packet. */ @@ -1897,7 +1982,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, struct aspath *aspath; int send_as4_path = 0; int send_as4_aggregator = 0; - int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0; + int use32bit = PEER_CAP_AS4_USE(peer) ; + bgp_peer_sort_t sort ; if (! bgp) bgp = bgp_get_default (); @@ -1914,11 +2000,13 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, /* AS path attribute. */ /* If remote-peer is EBGP */ - if (peer_sort (peer) == BGP_PEER_EBGP + sort = peer_sort(peer) ; + + if (sort == BGP_PEER_EBGP && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) || attr->aspath->segments == NULL) && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) - { + { aspath = aspath_dup (attr->aspath); if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) @@ -1935,7 +2023,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, aspath = aspath_add_seq (aspath, peer->change_local_as); } } - else if (peer_sort (peer) == BGP_PEER_CONFED) + else if (sort == BGP_PEER_CONFED) { /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ aspath = aspath_dup (attr->aspath); @@ -1958,13 +2046,13 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, aspath_sizep = stream_get_endp (s); stream_putw (s, 0); stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit)); - - /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs + + /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs * in the path */ if (!use32bit && aspath_has_as4 (aspath)) send_as4_path = 1; /* we'll do this later, at the correct place */ - + /* Nexthop attribute. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) { @@ -1992,8 +2080,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } /* Local preference. */ - if (peer_sort (peer) == BGP_PEER_IBGP || - peer_sort (peer) == BGP_PEER_CONFED) + if ((sort == BGP_PEER_IBGP) || (sort == BGP_PEER_CONFED)) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_LOCAL_PREF); @@ -2013,11 +2100,11 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) { assert (attr->extra); - + /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); - + if (use32bit) { /* AS4 capable peer */ @@ -2028,12 +2115,12 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, { /* 2-byte AS peer */ stream_putc (s, 6); - + /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */ if ( attr->extra->aggregator_as > 65535 ) { stream_putw (s, BGP_AS_TRANS); - + /* we have to send AS4_AGGREGATOR, too. * we'll do that later in order to send attributes in ascending * order. @@ -2047,18 +2134,19 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } /* Community attribute. */ - if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) { if (attr->community->size * 4 > 255) { - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putw (s, attr->community->size * 4); } else { - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putc (s, attr->community->size * 4); } @@ -2066,9 +2154,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } /* Route Reflector. */ - if (peer_sort (peer) == BGP_PEER_IBGP - && from - && peer_sort (from) == BGP_PEER_IBGP) + if ( (sort == BGP_PEER_IBGP) && (from != NULL) + && (peer_sort (from) == BGP_PEER_IBGP) ) { /* Originator ID. */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); @@ -2077,13 +2164,13 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) stream_put_in_addr (s, &attr->extra->originator_id); - else + else stream_put_in_addr (s, &from->remote_id); /* Cluster list. */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_CLUSTER_LIST); - + if (attr->extra && attr->extra->cluster) { stream_putc (s, attr->extra->cluster->length + 4); @@ -2092,7 +2179,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_put_in_addr (s, &bgp->cluster_id); else stream_put_in_addr (s, &bgp->router_id); - stream_put (s, attr->extra->cluster->list, + stream_put (s, attr->extra->cluster->list, attr->extra->cluster->length); } else @@ -2112,9 +2199,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, { 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); @@ -2131,7 +2218,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_put (s, &attre->mp_nexthop_global, 16); stream_put (s, &attre->mp_nexthop_local, 16); } - + /* SNPA */ stream_putc (s, 0); @@ -2197,25 +2284,25 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } /* Extended Communities attribute. */ - if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) { struct attr_extra *attre = attr->extra; - + assert (attre); - - if (peer_sort (peer) == BGP_PEER_IBGP - || peer_sort (peer) == BGP_PEER_CONFED) + + if ((sort == BGP_PEER_IBGP) || (sort == BGP_PEER_CONFED)) { 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_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); stream_putw (s, attre->ecommunity->size * 8); } else { - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); stream_putc (s, attre->ecommunity->size * 8); } @@ -2243,13 +2330,14 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, { if (ecom_tr_size * 8 > 255) { - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + 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, ecom_tr_size * 8); } else { - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); stream_putc (s, ecom_tr_size * 8); } @@ -2279,12 +2367,13 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, * Hm, I wonder... confederation things *should* only be at * the beginning of an aspath, right? Then we should use * aspath_delete_confed_seq for this, because it is already - * there! (JK) + * there! (JK) * Folks, talk to me: what is reasonable here!? */ aspath = aspath_delete_confed_seq (aspath); - stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_FLAG_TRANS |BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS4_PATH); aspath_sizep = stream_get_endp (s); stream_putw (s, 0); @@ -2294,7 +2383,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (aspath != attr->aspath) aspath_free (aspath); - if ( send_as4_aggregator ) + if ( send_as4_aggregator ) { assert (attr->extra); @@ -2308,7 +2397,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putl (s, attr->extra->aggregator_as); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } - + /* Unknown transit attribute. */ if (attr->extra && attr->extra->transit) stream_put (s, attr->extra->transit->val, attr->extra->transit->length); @@ -2388,7 +2477,7 @@ bgp_attr_finish (void) /* Make attribute packet. */ void -bgp_dump_routes_attr (struct stream *s, struct attr *attr, +bgp_dump_routes_attr (struct stream *s, struct attr *attr, struct prefix *prefix) { unsigned long cp; @@ -2409,12 +2498,12 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_putc (s, attr->origin); aspath = attr->aspath; - + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS_PATH); aspath_lenp = stream_get_endp (s); stream_putw (s, 0); - + stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1)); /* Nexthop attribute. */ @@ -2461,7 +2550,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, 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_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); stream_putc (s, 8); stream_putl (s, attr->extra->aggregator_as); @@ -2473,7 +2562,8 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, { if (attr->community->size * 4 > 255) { - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putw (s, attr->community->size * 4); } @@ -2493,7 +2583,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, { 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); |