bgpd: Add function to filter extended communities

Support filtering extended communities with a callback. So that we can
strip multiple values in one pass.

Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
This commit is contained in:
Xiao Liang 2025-04-11 15:28:54 +08:00
parent 3da1473093
commit f84e89ec0d
2 changed files with 43 additions and 0 deletions

View file

@ -1712,6 +1712,46 @@ bool ecommunity_strip_non_transitive(struct ecommunity *ecom)
return true;
}
/*
* Filter source Extended Communities Attribute. May return NULL if the result
* is empty, or the source ecommunity, if not modified.
*/
struct ecommunity *ecommunity_filter(struct ecommunity *ecom,
bool (*filter)(uint8_t *, uint8_t, void *), void *arg)
{
struct ecommunity *new;
uint8_t *new_val, *p, *q;
uint32_t c, new_size;
if (!ecom || !ecom->size)
return NULL;
new_val = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ecom->unit_size);
new_size = 0;
for (c = 0, p = ecom->val, q = new_val; c < ecom->size; c++, p += ecom->unit_size) {
if (filter(p, ecom->unit_size, arg)) {
memcpy(q, p, ecom->unit_size);
q += ecom->unit_size;
new_size++;
}
}
if (!new_size) {
XFREE(MTYPE_ECOMMUNITY_VAL, new_val);
return NULL;
}
if (new_size == ecom->size) {
XFREE(MTYPE_ECOMMUNITY_VAL, new_val);
return ecom;
}
new = XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
new->size = new_size;
new->unit_size = ecom->unit_size;
new->val = new_val;
return new;
}
/*
* Remove specified extended community value from extended community.
* Returns 1 if value was present (and hence, removed), 0 otherwise.

View file

@ -405,6 +405,9 @@ extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
uint8_t subtype);
extern struct ecommunity *ecommunity_new(void);
extern bool ecommunity_strip_non_transitive(struct ecommunity *ecom);
extern struct ecommunity *ecommunity_filter(struct ecommunity *ecom,
bool (*filter)(uint8_t *val, uint8_t usize, void *arg),
void *arg);
extern bool ecommunity_del_val(struct ecommunity *ecom,
struct ecommunity_val *eval);
struct bgp_pbr_entry_action;