diff options
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r-- | bgpd/bgp_attr.c | 287 |
1 files changed, 107 insertions, 180 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5e7536ae..01598c87 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "stream.h" #include "log.h" #include "hash.h" +#include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -116,18 +117,9 @@ cluster_loop_check (struct cluster_list *cluster, struct in_addr originator) static unsigned int cluster_hash_key_make (void *p) { - struct cluster_list * cluster = (struct cluster_list *) p; - unsigned int key = 0; - int length; - caddr_t pnt; + const struct cluster_list *cluster = p; - length = cluster->length; - pnt = (caddr_t) cluster->list; - - while (length) - key += pnt[--length]; - - return key; + return jhash(cluster->list, cluster->length, 0); } static int @@ -258,18 +250,9 @@ transit_unintern (struct transit *transit) static unsigned int transit_hash_key_make (void *p) { - struct transit * transit = (struct transit *) p; - unsigned int key = 0; - int length; - caddr_t pnt; + const struct transit * transit = p; - length = transit->length; - pnt = (caddr_t) transit->val; - - while (length) - key += pnt[--length]; - - return key; + return jhash(transit->val, transit->length, 0); } static int @@ -352,51 +335,46 @@ attr_unknown_count (void) unsigned int attrhash_key_make (void *p) { - struct attr * attr = (struct attr *) p; - unsigned int key = 0; + const struct attr * attr = (struct attr *) p; + uint32_t key = 0; +#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->pathlimit.as) - { - key += attr->pathlimit.ttl; - key += attr->pathlimit.as; - } 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; + MIX(attr->extra->aggregator_as); + MIX(attr->extra->aggregator_addr.s_addr); + MIX(attr->extra->weight); + MIX(attr->extra->mp_nexthop_global_in.s_addr); } if (attr->aspath) - key += aspath_key_make (attr->aspath); + MIX(aspath_key_make (attr->aspath)); if (attr->community) - key += community_hash_make (attr->community); + MIX(community_hash_make (attr->community)); if (attr->extra) { if (attr->extra->ecommunity) - key += ecommunity_hash_make (attr->extra->ecommunity); + MIX(ecommunity_hash_make (attr->extra->ecommunity)); if (attr->extra->cluster) - key += cluster_hash_key_make (attr->extra->cluster); + MIX(cluster_hash_key_make (attr->extra->cluster)); if (attr->extra->transit) - key += transit_hash_key_make (attr->extra->transit); + MIX(transit_hash_key_make (attr->extra->transit)); #ifdef HAVE_IPV6 - { - 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]; - } + MIX(attr->extra->mp_nexthop_len); + key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key); + key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key); #endif /* HAVE_IPV6 */ } @@ -415,9 +393,7 @@ attrhash_cmp (const void *p1, const void *p2) && attr1->aspath == attr2->aspath && attr1->community == attr2->community && attr1->med == attr2->med - && attr1->local_pref == attr2->local_pref - && attr1->pathlimit.ttl == attr2->pathlimit.ttl - && attr1->pathlimit.as == attr2->pathlimit.as) + && attr1->local_pref == attr2->local_pref) { const struct attr_extra *ae1 = attr1->extra; const struct attr_extra *ae2 = attr2->extra; @@ -704,43 +680,6 @@ bgp_attr_flush (struct attr *attr) } } -/* Parse AS_PATHLIMIT attribute in an UPDATE */ -static int -bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) -{ - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - - if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) - || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) - { - zlog (peer->log, LOG_ERR, - "AS-Pathlimit attribute flag isn't transitive %d", flag); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - return -1; - } - - if (length != 5) - { - zlog (peer->log, LOG_ERR, - "AS-Pathlimit length, %u, is not 5", length); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - return -1; - } - - attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer)); - attr->pathlimit.as = stream_getl (BGP_INPUT(peer)); - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); - return 0; -} /* Get origin attribute of the update message. */ static int bgp_attr_origin (struct peer *peer, bgp_size_t length, @@ -807,54 +746,78 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, return 0; } - -/* Parse AS path information. This function is wrapper of - aspath_parse. */ -static int +/* Parse AS path information. This function is wrapper of aspath_parse. + * + * Parses AS_PATH or AS4_PATH. + * + * Returns: if valid: address of struct aspath in the hash of known aspaths, + * with reference count incremented. + * else: NULL + * + * NB: empty AS path (length == 0) is valid. The returned struct aspath will + * have segments == NULL and str == zero length string (unique). + */ +static struct aspath * bgp_attr_aspath (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) + struct attr *attr, u_char flag, u_char *startp, int as4_path) { - bgp_size_t total; + u_char require ; + struct aspath *asp ; - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Check the attribute flags */ + require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS + : 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) { + const char* path_type ; + bgp_size_t total; + + path_type = as4_path ? "AS4_PATH" : "AS_PATH" ; + + if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)) zlog (peer->log, LOG_ERR, - "As-Path attribute flag isn't transitive %d", flag); + "%s attribute flag isn't transitive %d", path_type, flag) ; + + if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, + "%s attribute flag must %sbe optional %d", path_type, + (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - return -1; - } - /* - * peer with AS4 => will get 4Byte ASnums - * otherwise, will get 16 Bit + return NULL ; + } ; + + /* Parse the AS_PATH/AS4_PATH body. + * + * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN + * AS4_PATH 4Byte ASN */ - attr->aspath = aspath_parse (peer->ibuf, length, - CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); + asp = aspath_parse (peer->ibuf, length, + as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ; - /* In case of IBGP, length will be zero. */ - if (! attr->aspath) + if (asp != NULL) + { + attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH + : BGP_ATTR_AS_PATH) ; + } + else { zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); + + /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_AS_PATH); - return -1; - } - - /* Forward pointer. */ -/* stream_forward_getp (peer->ibuf, length);*/ - - /* Set aspath attribute flag. */ - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + } ; - return 0; + return asp ; } static int bgp_attr_aspath_check( struct peer *peer, @@ -912,21 +875,6 @@ static int bgp_attr_aspath_check( struct peer *peer, } -/* 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, struct aspath **as4_path) -{ - *as4_path = aspath_parse (peer->ibuf, length, 1); - - /* Set aspath attribute flag. */ - if (as4_path) - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); - - return 0; -} - /* Nexthop attribute. */ static int bgp_attr_nexthop (struct peer *peer, bgp_size_t length, @@ -1226,13 +1174,16 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, attr->community = NULL; return 0; } - else - { - attr->community = - community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length); - stream_forward_getp (peer->ibuf, length); - } + + 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 -1; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); return 0; @@ -1292,8 +1243,8 @@ int bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, struct bgp_nlri *mp_update) { - u_int16_t afi; - u_char safi; + afi_t afi; + safi_t safi; bgp_size_t nlri_len; size_t start; int ret; @@ -1427,8 +1378,8 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, struct bgp_nlri *mp_withdraw) { struct stream *s; - u_int16_t afi; - u_char safi; + afi_t afi; + safi_t safi; u_int16_t withdraw_len; int ret; @@ -1469,13 +1420,18 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, { if (attr->extra) attr->extra->ecommunity = NULL; + /* Empty extcomm doesn't seem to be invalid per se */ + return 0; } - else - { - (bgp_attr_extra_get (attr))->ecommunity = - ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); - stream_forward_getp (peer->ibuf, length); - } + + (bgp_attr_extra_get (attr))->ecommunity = + 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 -1; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); return 0; @@ -1657,10 +1613,12 @@ 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); + attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0); + ret = attr->aspath ? 0 : -1 ; break; case BGP_ATTR_AS4_PATH: - ret = bgp_attr_as4_path (peer, length, attr, &as4_path ); + as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1); + ret = as4_path ? 0 : -1 ; break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (peer, length, attr, flag, startp); @@ -1698,9 +1656,6 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (peer, length, attr, flag); break; - case BGP_ATTR_AS_PATHLIMIT: - ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp); - break; default: ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); break; @@ -2255,24 +2210,6 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } - /* AS-Pathlimit */ - if (attr->pathlimit.ttl) - { - u_int32_t as = attr->pathlimit.as; - - /* should already have been done in announce_check(), - * but just in case.. - */ - if (!as) - as = peer->local_as; - - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); - stream_putc (s, BGP_ATTR_AS_PATHLIMIT); - stream_putc (s, 5); - stream_putc (s, attr->pathlimit.ttl); - stream_putl (s, as); - } - /* Unknown transit attribute. */ if (attr->extra && attr->extra->transit) stream_put (s, attr->extra->transit->val, attr->extra->transit->length); @@ -2484,16 +2421,6 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, } #endif /* HAVE_IPV6 */ - /* AS-Pathlimit */ - if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT)) - { - stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); - stream_putc (s, BGP_ATTR_AS_PATHLIMIT); - stream_putc (s, 5); - stream_putc (s, attr->pathlimit.ttl); - stream_putl (s, attr->pathlimit.as); - } - /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; stream_putw_at (s, cp, len); |