diff options
Diffstat (limited to 'bgpd/bgp_attr.c')
| -rw-r--r-- | bgpd/bgp_attr.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 221386e38d..b7e2f45195 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -119,11 +119,11 @@ static void *cluster_hash_alloc(void *p) /* Cluster list related functions. */ static struct cluster_list *cluster_parse(struct in_addr *pnt, int length) { - struct cluster_list tmp; + struct cluster_list tmp = {}; struct cluster_list *cluster; tmp.length = length; - tmp.list = pnt; + tmp.list = length == 0 ? NULL : pnt; cluster = hash_get(cluster_hash, &tmp, cluster_hash_alloc); cluster->refcnt++; @@ -152,10 +152,16 @@ static bool cluster_hash_cmp(const void *p1, const void *p2) const struct cluster_list *cluster1 = p1; const struct cluster_list *cluster2 = p2; - return (cluster1->length == cluster2->length - && (cluster1->list == cluster2->list - || memcmp(cluster1->list, cluster2->list, cluster1->length) - == 0)); + if (cluster1->list == cluster2->list) + return true; + + if (!cluster1->list || !cluster2->list) + return false; + + if (cluster1->length != cluster2->length) + return false; + + return (memcmp(cluster1->list, cluster2->list, cluster1->length) == 0); } static void cluster_free(struct cluster_list *cluster) @@ -174,14 +180,16 @@ static struct cluster_list *cluster_intern(struct cluster_list *cluster) return find; } -void cluster_unintern(struct cluster_list *cluster) +static void cluster_unintern(struct cluster_list **cluster) { - if (cluster->refcnt) - cluster->refcnt--; + if ((*cluster)->refcnt) + (*cluster)->refcnt--; - if (cluster->refcnt == 0) { - hash_release(cluster_hash, cluster); - cluster_free(cluster); + if ((*cluster)->refcnt == 0) { + void *p = hash_release(cluster_hash, *cluster); + assert(p == *cluster); + cluster_free(*cluster); + *cluster = NULL; } } @@ -1029,7 +1037,7 @@ void bgp_attr_unintern_sub(struct attr *attr) UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)); if (attr->cluster) - cluster_unintern(attr->cluster); + cluster_unintern(&attr->cluster); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)); if (attr->transit) @@ -1824,7 +1832,8 @@ bgp_attr_community(struct bgp_attr_parser_args *args) if (length == 0) { attr->community = NULL; - return BGP_ATTR_PARSE_PROCEED; + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); } attr->community = @@ -1886,7 +1895,7 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args) * malformed, the UPDATE message SHALL be handled using the approach * of "treat-as-withdraw". */ - if (length % 4) { + if (length == 0 || length % 4) { flog_err(EC_BGP_ATTR_LEN, "Bad cluster list length %d", length); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, @@ -2165,11 +2174,11 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args) if (length == 0) { attr->lcommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ - return BGP_ATTR_PARSE_PROCEED; + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); } - attr->lcommunity = - lcommunity_parse((uint8_t *)stream_pnt(peer->curr), length); + attr->lcommunity = lcommunity_parse(stream_pnt(peer->curr), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp(peer->curr, length); @@ -2194,11 +2203,12 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) if (length == 0) { attr->ecommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ - return BGP_ATTR_PARSE_PROCEED; + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); } attr->ecommunity = - ecommunity_parse((uint8_t *)stream_pnt(peer->curr), length); + ecommunity_parse(stream_pnt(peer->curr), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp(peer->curr, length); @@ -2246,6 +2256,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) bgp_attr_extcom_tunnel_type(attr, (bgp_encap_types *)&attr->encap_tunneltype); + /* Extract link bandwidth, if any. */ + (void)ecommunity_linkbw_present(attr->ecommunity, &attr->link_bw); + return BGP_ATTR_PARSE_PROCEED; } |
