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.c68
1 files changed, 63 insertions, 5 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 27be7787f3..8817263cef 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -84,6 +84,7 @@ static const struct message attr_str[] = {
#endif
{BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
{BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
+ {BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
{0}};
static const struct message attr_flag_str[] = {
@@ -662,6 +663,8 @@ unsigned int attrhash_key_make(const void *p)
MIX(lcommunity_hash_make(attr->lcommunity));
if (attr->ecommunity)
MIX(ecommunity_hash_make(attr->ecommunity));
+ if (attr->ipv6_ecommunity)
+ MIX(ecommunity_hash_make(attr->ipv6_ecommunity));
if (attr->cluster)
MIX(cluster_hash_key_make(attr->cluster));
if (attr->transit)
@@ -700,6 +703,7 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& attr1->label_index == attr2->label_index
&& attr1->mp_nexthop_len == attr2->mp_nexthop_len
&& attr1->ecommunity == attr2->ecommunity
+ && attr1->ipv6_ecommunity == attr2->ipv6_ecommunity
&& attr1->lcommunity == attr2->lcommunity
&& attr1->cluster == attr2->cluster
&& attr1->transit == attr2->transit
@@ -725,7 +729,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
&& attr1->distance == attr2->distance
&& srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
- && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn))
+ && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)
+ && attr1->srte_color == attr2->srte_color)
return true;
}
@@ -829,6 +834,15 @@ struct attr *bgp_attr_intern(struct attr *attr)
else
attr->ecommunity->refcnt++;
}
+
+ if (attr->ipv6_ecommunity) {
+ if (!attr->ipv6_ecommunity->refcnt)
+ attr->ipv6_ecommunity =
+ ecommunity_intern(attr->ipv6_ecommunity);
+ else
+ attr->ipv6_ecommunity->refcnt++;
+ }
+
if (attr->lcommunity) {
if (!attr->lcommunity->refcnt)
attr->lcommunity = lcommunity_intern(attr->lcommunity);
@@ -1034,6 +1048,10 @@ void bgp_attr_unintern_sub(struct attr *attr)
ecommunity_unintern(&attr->ecommunity);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES));
+ if (attr->ipv6_ecommunity)
+ ecommunity_unintern(&attr->ipv6_ecommunity);
+ UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES));
+
if (attr->lcommunity)
lcommunity_unintern(&attr->lcommunity);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES));
@@ -1118,6 +1136,8 @@ void bgp_attr_flush(struct attr *attr)
community_free(&attr->community);
if (attr->ecommunity && !attr->ecommunity->refcnt)
ecommunity_free(&attr->ecommunity);
+ if (attr->ipv6_ecommunity && !attr->ipv6_ecommunity->refcnt)
+ ecommunity_free(&attr->ipv6_ecommunity);
if (attr->lcommunity && !attr->lcommunity->refcnt)
lcommunity_free(&attr->lcommunity);
if (attr->cluster && !attr->cluster->refcnt) {
@@ -1161,7 +1181,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode,
if (bgp_debug_update(peer, NULL, NULL, 1)) {
char attr_str[BUFSIZ] = {0};
- bgp_dump_attr(attr, attr_str, BUFSIZ);
+ bgp_dump_attr(attr, attr_str, sizeof(attr_str));
zlog_debug("%s: attributes: %s", __func__, attr_str);
}
@@ -1201,6 +1221,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode,
case BGP_ATTR_LOCAL_PREF:
case BGP_ATTR_COMMUNITIES:
case BGP_ATTR_EXT_COMMUNITIES:
+ case BGP_ATTR_IPV6_EXT_COMMUNITIES:
case BGP_ATTR_LARGE_COMMUNITIES:
case BGP_ATTR_ORIGINATOR_ID:
case BGP_ATTR_CLUSTER_LIST:
@@ -1286,6 +1307,8 @@ const uint8_t attr_flags_values[] = {
[BGP_ATTR_LARGE_COMMUNITIES] =
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_PREFIX_SID] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_IPV6_EXT_COMMUNITIES] =
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@@ -1609,16 +1632,20 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
external peer, then this attribute MUST be ignored by the
receiving speaker. */
if (peer->sort == BGP_PEER_EBGP) {
- stream_forward_getp(peer->curr, length);
+ STREAM_FORWARD_GETP(peer->curr, length);
return BGP_ATTR_PARSE_PROCEED;
}
- attr->local_pref = stream_getl(peer->curr);
+ STREAM_GETL(peer->curr, attr->local_pref);
/* Set the local-pref flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
return BGP_ATTR_PARSE_PROCEED;
+
+stream_failure:
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
/* Atomic aggregate. */
@@ -2264,6 +2291,34 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
return BGP_ATTR_PARSE_PROCEED;
}
+/* IPv6 Extended Community attribute. */
+static bgp_attr_parse_ret_t
+bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ if (length == 0) {
+ attr->ipv6_ecommunity = NULL;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+ }
+
+ attr->ipv6_ecommunity =
+ ecommunity_parse_ipv6(stream_pnt(peer->curr), length);
+ /* XXX: fix ecommunity_parse to use stream API */
+ stream_forward_getp(peer->curr, length);
+
+ if (!attr->ipv6_ecommunity)
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES);
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/* Parse Tunnel Encap attribute in an UPDATE */
static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
bgp_size_t length, /* IN: attr's length field */
@@ -2973,7 +3028,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
size_t lfl =
CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
/* Rewind to end of flag field */
- stream_forward_getp(BGP_INPUT(peer), -(1 + lfl));
+ stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
/* Type */
stream_get(&ndata[0], BGP_INPUT(peer), 1);
/* Length */
@@ -3082,6 +3137,9 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
case BGP_ATTR_PMSI_TUNNEL:
ret = bgp_attr_pmsi_tunnel(&attr_args);
break;
+ case BGP_ATTR_IPV6_EXT_COMMUNITIES:
+ ret = bgp_attr_ipv6_ext_communities(&attr_args);
+ break;
default:
ret = bgp_attr_unknown(&attr_args);
break;