diff options
Diffstat (limited to 'bgpd/bgp_ecommunity.c')
| -rw-r--r-- | bgpd/bgp_ecommunity.c | 71 |
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 */ |
