mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-27 05:28:51 +00:00
bgpd: Rework extended community transitiviness
Extended communities can be transitive or non-transitive. Like other attributes (e.g., MED) non-transitive extended communities SHOULD be sent to the direct peer, but not forward them to eBGP peers next. Before this patch, we never send non-transitive extended attributes to the direct peers at all. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
parent
5ca4656ad7
commit
b4e72bc198
@ -4482,66 +4482,22 @@ static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer,
|
static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer,
|
||||||
struct ecommunity *ecomm,
|
struct ecommunity *ecomm, int attribute)
|
||||||
bool transparent, int attribute)
|
|
||||||
{
|
{
|
||||||
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED ||
|
if (!ecomm || !ecomm->size)
|
||||||
peer->sub_sort == BGP_PEER_EBGP_OAD || transparent) {
|
return;
|
||||||
if (ecomm->size * ecomm->unit_size > 255) {
|
|
||||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
|
if (ecomm->size * ecomm->unit_size > 255) {
|
||||||
BGP_ATTR_FLAG_TRANS |
|
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
|
||||||
BGP_ATTR_FLAG_EXTLEN);
|
stream_putc(s, attribute);
|
||||||
stream_putc(s, attribute);
|
stream_putw(s, ecomm->size * ecomm->unit_size);
|
||||||
stream_putw(s, ecomm->size * ecomm->unit_size);
|
|
||||||
} else {
|
|
||||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
|
|
||||||
BGP_ATTR_FLAG_TRANS);
|
|
||||||
stream_putc(s, attribute);
|
|
||||||
stream_putc(s, ecomm->size * ecomm->unit_size);
|
|
||||||
}
|
|
||||||
stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size);
|
|
||||||
} else {
|
} else {
|
||||||
uint8_t *pnt;
|
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
|
||||||
int tbit;
|
stream_putc(s, attribute);
|
||||||
int ecom_tr_size = 0;
|
stream_putc(s, ecomm->size * ecomm->unit_size);
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < ecomm->size; i++) {
|
|
||||||
pnt = ecomm->val + (i * ecomm->unit_size);
|
|
||||||
tbit = *pnt;
|
|
||||||
|
|
||||||
if (CHECK_FLAG(tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ecom_tr_size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ecom_tr_size) {
|
|
||||||
if (ecom_tr_size * ecomm->unit_size > 255) {
|
|
||||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
|
|
||||||
BGP_ATTR_FLAG_TRANS |
|
|
||||||
BGP_ATTR_FLAG_EXTLEN);
|
|
||||||
stream_putc(s, attribute);
|
|
||||||
stream_putw(s, ecom_tr_size * ecomm->unit_size);
|
|
||||||
} else {
|
|
||||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
|
|
||||||
BGP_ATTR_FLAG_TRANS);
|
|
||||||
stream_putc(s, attribute);
|
|
||||||
stream_putc(s, ecom_tr_size * ecomm->unit_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ecomm->size; i++) {
|
|
||||||
pnt = ecomm->val + (i * ecomm->unit_size);
|
|
||||||
tbit = *pnt;
|
|
||||||
|
|
||||||
if (CHECK_FLAG(tbit,
|
|
||||||
ECOMMUNITY_FLAG_NON_TRANSITIVE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
stream_put(s, pnt, ecomm->unit_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make attribute packet. */
|
/* Make attribute packet. */
|
||||||
@ -4848,19 +4804,11 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct strea
|
|||||||
|
|
||||||
/* Extended IPv6/Communities attributes. */
|
/* Extended IPv6/Communities attributes. */
|
||||||
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) {
|
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) {
|
||||||
bool transparent = CHECK_FLAG(peer->af_flags[afi][safi],
|
|
||||||
PEER_FLAG_RSERVER_CLIENT) &&
|
|
||||||
from &&
|
|
||||||
CHECK_FLAG(from->af_flags[afi][safi],
|
|
||||||
PEER_FLAG_RSERVER_CLIENT);
|
|
||||||
|
|
||||||
if (CHECK_FLAG(attr->flag,
|
if (CHECK_FLAG(attr->flag,
|
||||||
ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
|
ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
|
||||||
struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
|
struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
|
||||||
|
|
||||||
bgp_packet_ecommunity_attribute(s, peer, ecomm,
|
bgp_packet_ecommunity_attribute(s, peer, ecomm, BGP_ATTR_EXT_COMMUNITIES);
|
||||||
transparent,
|
|
||||||
BGP_ATTR_EXT_COMMUNITIES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CHECK_FLAG(attr->flag,
|
if (CHECK_FLAG(attr->flag,
|
||||||
@ -4869,7 +4817,6 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct strea
|
|||||||
bgp_attr_get_ipv6_ecommunity(attr);
|
bgp_attr_get_ipv6_ecommunity(attr);
|
||||||
|
|
||||||
bgp_packet_ecommunity_attribute(s, peer, ecomm,
|
bgp_packet_ecommunity_attribute(s, peer, ecomm,
|
||||||
transparent,
|
|
||||||
BGP_ATTR_IPV6_EXT_COMMUNITIES);
|
BGP_ATTR_IPV6_EXT_COMMUNITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2836,6 +2836,50 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Extended communities can be transitive and non-transitive.
|
||||||
|
* If the extended community is non-transitive, strip it off,
|
||||||
|
* unless it's a locally originated route (static, aggregate,
|
||||||
|
* redistributed, etc.).
|
||||||
|
*/
|
||||||
|
if (from->sort == BGP_PEER_EBGP && peer->sort == BGP_PEER_EBGP &&
|
||||||
|
pi->sub_type == BGP_ROUTE_NORMAL) {
|
||||||
|
struct ecommunity *new_ecomm;
|
||||||
|
struct ecommunity *old_ecomm;
|
||||||
|
|
||||||
|
old_ecomm = bgp_attr_get_ecommunity(attr);
|
||||||
|
if (old_ecomm) {
|
||||||
|
new_ecomm = ecommunity_dup(old_ecomm);
|
||||||
|
if (ecommunity_strip_non_transitive(new_ecomm)) {
|
||||||
|
bgp_attr_set_ecommunity(attr, new_ecomm);
|
||||||
|
if (!old_ecomm->refcnt)
|
||||||
|
ecommunity_free(&old_ecomm);
|
||||||
|
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
|
||||||
|
zlog_debug("%pBP: %pFX stripped non-transitive extended communities",
|
||||||
|
peer, p);
|
||||||
|
} else {
|
||||||
|
ecommunity_free(&new_ecomm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extended link-bandwidth communities are encoded as IPv6
|
||||||
|
* address-specific extended communities.
|
||||||
|
*/
|
||||||
|
old_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
|
||||||
|
if (old_ecomm) {
|
||||||
|
new_ecomm = ecommunity_dup(old_ecomm);
|
||||||
|
if (ecommunity_strip_non_transitive(new_ecomm)) {
|
||||||
|
bgp_attr_set_ipv6_ecommunity(attr, new_ecomm);
|
||||||
|
if (!old_ecomm->refcnt)
|
||||||
|
ecommunity_free(&old_ecomm);
|
||||||
|
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
|
||||||
|
zlog_debug("%pBP: %pFX stripped non-transitive ipv6 extended communities",
|
||||||
|
peer, p);
|
||||||
|
} else {
|
||||||
|
ecommunity_free(&new_ecomm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user