summaryrefslogtreecommitdiff
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r--bgpd/bgp_attr.c53
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;
}