}
static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer,
- struct ecommunity *ecomm,
- bool transparent, int attribute)
+ struct ecommunity *ecomm, int attribute)
{
- if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED ||
- peer->sub_sort == BGP_PEER_EBGP_OAD || transparent) {
- if (ecomm->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, 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 {
- uint8_t *pnt;
- int tbit;
- int ecom_tr_size = 0;
- 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;
+ if (!ecomm || !ecomm->size)
+ return;
- stream_put(s, pnt, ecomm->unit_size);
- }
- }
+ if (ecomm->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, 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);
}
/* Make attribute packet. */
/* Extended IPv6/Communities attributes. */
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,
ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
- bgp_packet_ecommunity_attribute(s, peer, ecomm,
- transparent,
- BGP_ATTR_EXT_COMMUNITIES);
+ bgp_packet_ecommunity_attribute(s, peer, ecomm, BGP_ATTR_EXT_COMMUNITIES);
}
if (CHECK_FLAG(attr->flag,
bgp_attr_get_ipv6_ecommunity(attr);
bgp_packet_ecommunity_attribute(s, peer, ecomm,
- transparent,
BGP_ATTR_IPV6_EXT_COMMUNITIES);
}
}
}
}
+ /* 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;
}