summaryrefslogtreecommitdiff
path: root/bgpd/bgp_ecommunity.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_ecommunity.c')
-rw-r--r--bgpd/bgp_ecommunity.c71
1 files changed, 58 insertions, 13 deletions
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 547dcdf7f3..df32d75103 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -1408,9 +1408,12 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
"FS:marking %u", *(pnt + 5));
} else
unk_ecom = true;
- } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) {
+ } else if (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE) ||
+ type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) {
sub_type = *pnt++;
- if (sub_type == ECOMMUNITY_LINK_BANDWIDTH)
+ if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE)
+ ecommunity_origin_validation_state_str(encbuf, sizeof(encbuf), pnt);
+ else if (sub_type == ECOMMUNITY_LINK_BANDWIDTH)
ecommunity_lb_str(encbuf, sizeof(encbuf), pnt,
ecom->disable_ieee_floating);
else if (sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH)
@@ -1418,20 +1421,13 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
pnt, len);
else
unk_ecom = true;
- } else if (type == ECOMMUNITY_ENCODE_IP_NON_TRANS) {
+ } else if (CHECK_FLAG(type, ECOMMUNITY_ENCODE_IP_NON_TRANS)) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_NODE_TARGET)
ecommunity_node_target_str(
encbuf, sizeof(encbuf), pnt, format);
else
unk_ecom = true;
- } else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) {
- sub_type = *pnt++;
- if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE)
- ecommunity_origin_validation_state_str(
- encbuf, sizeof(encbuf), pnt);
- else
- unk_ecom = true;
} else {
sub_type = *pnt++;
unk_ecom = true;
@@ -1587,6 +1583,57 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
return true;
}
+static bool ecommunity_non_transitive(uint8_t type)
+{
+ return (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE) ||
+ CHECK_FLAG(type, ECOMMUNITY_ENCODE_IP_NON_TRANS) ||
+ type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS);
+}
+
+/* Delete all non-transitive extended communities */
+bool ecommunity_strip_non_transitive(struct ecommunity *ecom)
+{
+ uint8_t *p, *q, *new;
+ uint32_t c, found = 0;
+
+ if (!ecom || !ecom->val)
+ return false;
+
+ /* Certain extended communities like the Route Target can be present
+ * multiple times, handle that.
+ */
+ c = 0;
+ for (p = ecom->val; c < ecom->size; p += ecom->unit_size, c++)
+ if (ecommunity_non_transitive(*p))
+ found++;
+
+ if (!found)
+ return false;
+
+ /* Handle the case where everything needs to be stripped. */
+ if (found == ecom->size) {
+ XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
+ ecom->size = 0;
+ return true;
+ }
+
+ /* Strip extended communities with non-transitive flag set */
+ new = XMALLOC(MTYPE_ECOMMUNITY_VAL, (ecom->size - found) * ecom->unit_size);
+ q = new;
+ for (c = 0, p = ecom->val; c < ecom->size; c++, p += ecom->unit_size) {
+ if (!ecommunity_non_transitive(*p)) {
+ memcpy(q, p, ecom->unit_size);
+ q += ecom->unit_size;
+ }
+ }
+
+ XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
+ ecom->val = new;
+ ecom->size -= found;
+
+ return true;
+}
+
/*
* Remove specified extended community value from extended community.
* Returns 1 if value was present (and hence, removed), 0 otherwise.
@@ -1883,9 +1930,7 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw)
if (len < ecom->unit_size)
return NULL;
- if ((type == ECOMMUNITY_ENCODE_AS ||
- type == ECOMMUNITY_ENCODE_AS_NON_TRANS) &&
- sub_type == ECOMMUNITY_LINK_BANDWIDTH) {
+ if ((type == ECOMMUNITY_ENCODE_AS) && sub_type == ECOMMUNITY_LINK_BANDWIDTH) {
uint32_t bwval;
pnt += 2; /* bandwidth is encoded as AS:val */