Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions bgpd/bgp_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -5735,9 +5735,39 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct strea
stream_putc(s, cluster ? cluster->length + 4 : 4);
}

/* The route reflector has multiple clusters associated with it,
* put the one that has been configured by the user for that peer
* in the cluster-list.
* filtering has been updated to take these new clusters into account
* and prevent loops
*/

/*if the originator of the prefix has a per-neighbor cluster configured*/
Comment thread
PierreNeltner6WIND marked this conversation as resolved.
if (CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) &&
CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID))
stream_put_in_addr(s, &from->cluster[afi][safi]);

/* if the originator of the prefix is a client of the default cluster
* or if from is non-client and prefer global cluster-id is configured
*/
else if (CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) ||
(!CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) &&
CHECK_FLAG(bgp->flags, BGP_FLAG_PREFER_GLOBAL_CLUSTER))) {
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
stream_put_in_addr(s, &bgp->cluster_id);
else
stream_put_in_addr(s, &bgp->router_id);
}

/*if the destination of the id has a per-neighbor cluster configured*/
Comment thread
PierreNeltner6WIND marked this conversation as resolved.
else if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) &&
CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID))
stream_put_in_addr(s, &peer->cluster[afi][safi]);

/* If this peer configuration's parent BGP has
* cluster_id. */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
* cluster_id.
*/
else if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
stream_put_in_addr(s, &bgp->cluster_id);
else
stream_put_in_addr(s, &bgp->router_id);
Expand Down
1 change: 1 addition & 0 deletions bgpd/bgp_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ DEFINE_MTYPE(BGPD, COMMUNITY_LIST_HANDLER, "community-list handler");

DEFINE_MTYPE(BGPD, CLUSTER, "Cluster list");
DEFINE_MTYPE(BGPD, CLUSTER_VAL, "Cluster list val");
DEFINE_MTYPE(BGPD, PER_NEIGHBOR_CLUSTER, "Per-neighbor Cluster");

DEFINE_MTYPE(BGPD, BGP_PROCESS_QUEUE, "BGP Process queue");
DEFINE_MTYPE(BGPD, BGP_CLEAR_NODE_QUEUE, "BGP node clear queue");
Expand Down
1 change: 1 addition & 0 deletions bgpd/bgp_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ DECLARE_MTYPE(COMMUNITY_LIST_HANDLER);

DECLARE_MTYPE(CLUSTER);
DECLARE_MTYPE(CLUSTER_VAL);
DECLARE_MTYPE(PER_NEIGHBOR_CLUSTER);

DECLARE_MTYPE(BGP_PROCESS_QUEUE);
DECLARE_MTYPE(BGP_CLEAR_NODE_QUEUE);
Expand Down
169 changes: 156 additions & 13 deletions bgpd/bgp_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -2055,7 +2055,12 @@ static bool bgp_cluster_filter(struct peer *peer, struct attr *attr)
{
struct in_addr cluster_id;
struct cluster_list *cluster = bgp_attr_get_cluster(attr);
struct cluster *per_neighbor_cluster;

/* when receiving a route with any of the per-neighbor cluster-ids configured
* on the router, the route should be dropped to avoid loop regardless of the
* cluster that originated it
*/
if (cluster) {
if (CHECK_FLAG(peer->bgp->config, BGP_CONFIG_CLUSTER_ID))
cluster_id = peer->bgp->cluster_id;
Expand All @@ -2064,6 +2069,13 @@ static bool bgp_cluster_filter(struct peer *peer, struct attr *attr)

if (cluster_loop_check(cluster, cluster_id))
return true;
if (!CHECK_FLAG(peer->bgp->flags, BGP_FLAG_LOOSE_CLUSTER_LIST_CHECK)) {
frr_each (per_neighbor_cluster_list, &peer->bgp->per_neighbor_clusters,
per_neighbor_cluster) {
if (cluster_loop_check(cluster, per_neighbor_cluster->cluster_id))
return true;
}
}
}
return false;
}
Expand Down Expand Up @@ -2384,6 +2396,123 @@ void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr)
memset(&attr->mp_nexthop_global_in, 0, BGP_ATTR_NHLEN_IPV4);
}


static bool ibgp_reflection_check_from_per_neighbor(struct bgp *bgp, struct peer *from,
struct peer *peer, afi_t afi, safi_t safi)
{
if (!CHECK_FLAG(from->cluster_flags[afi][safi],
CLUSTER_FLAG_CLIENT_TO_CLIENT_INTRA_CLUSTER_CONFIGURED)) {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT))
/* both peers are clients, from is part of a per-neighbor cluster but
* client-to-client reflection isn't configured in that cluster,
* client-to-client reflection is disabled at the bgp instance level
*/
return false;

} else if (CHECK_FLAG(from->cluster_flags[afi][safi],
CLUSTER_FLAG_CLIENT_TO_CLIENT_INTRA_CLUSTER)) {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT)) {
if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID))
/* both peers are clients, from is part of a per-neighbor cluster and
* client-to-client reflection is enabled in that cluster but
* client-to-client reflection is disabled at the bgp instance level
* and peer is part of the global cluster
*/
return false;

if (!IPV4_ADDR_SAME(&from->cluster[afi][safi], &peer->cluster[afi][safi]))
/* both peers are clients, from is part of a per-neighbor cluster and
* client-to-client reflection is enabled in that cluster but
* client-to-client reflection is disabled at the bgp instance level
* and peer is part of another per-neighbor cluster
*/
return false;
}
} else {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT))
/* both peers are clients, from is part of a per-neighbor cluster and
* client-to-client reflection is disabled both in that cluster and
* at the bgp instance level
*/
return false;

if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID)) {
if (IPV4_ADDR_SAME(&from->cluster[afi][safi], &peer->cluster[afi][safi]))
/* both peers are clients, from is part of a per-neighbor cluster and
* client-to-client reflection is disabled in that cluster and both
* peers are part of that cluster
*/
return false;
}
}
return true;
}

static bool ibgp_reflection_check_from_global(struct bgp *bgp, struct peer *from,
struct peer *peer, afi_t afi, safi_t safi)
{
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_CLIENT_TO_CLIENT_GLOBAL_CLUSTER_CONFIGURED)) {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT))
/* both peers are clients, from is part of the global cluster and
* client-to-client reflection is not configured in that cluster but
* client-to-client reflection is disabled at the bgp instance level
*/
return false;
} else if (CHECK_FLAG(bgp->flags, BGP_FLAG_CLIENT_TO_CLIENT_GLOBAL_CLUSTER)) {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT) &&
CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID)) {
/* both peers are clients, from is part of the global cluster and
* client-to-client reflection is enabled in that cluster but
* client-to-client reflection is disabled at the bgp instance level
* and peer is not part of the default cluster
*/

if (!CHECK_FLAG(peer->cluster_flags[afi][safi], CLUSTER_FLAG_GLOBAL))
return false;
}
} else {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_CLIENT_TO_CLIENT))
/* both peers are clients, from is part of the global cluster and
* client-to-client reflection is disabled in that cluster and
* client-to-client reflection is disabled at the bgp instance level
*/
return false;

if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID))
/* both peers are clients, both peer and from are
* part of the global cluster and client-to-client reflection
* is disabled in that cluster
*/
return false;

if (CHECK_FLAG(peer->cluster_flags[afi][safi], CLUSTER_FLAG_GLOBAL))
/* both peers are clients, both peer and from are
* part of the global cluster and client-to-client reflection
* is disabled in that cluster
*/
return false;
}
return true;
}

static bool ibgp_reflection_check(struct bgp *bgp, struct peer *from, struct peer *peer, afi_t afi,
safi_t safi)
{
/* reflection logic is as follows :
* if both peers are in the same cluster, be it global or per-neighbor
* the client-to-client configuration of the said cluster decides if the
* route is reflected or not.
* if there is no client-to-client configuration in that cluster or
* if both peers are from different cluster the bgp level configuration
* applies.
*/
if (CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID)) {
if (!CHECK_FLAG(from->cluster_flags[afi][safi], CLUSTER_FLAG_GLOBAL))
return ibgp_reflection_check_from_per_neighbor(bgp, from, peer, afi, safi);
}
return ibgp_reflection_check_from_global(bgp, from, peer, afi, safi);
}

bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
struct update_subgroup *subgrp,
const struct prefix *p, struct attr *attr,
Expand Down Expand Up @@ -2591,6 +2720,20 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
return false;
}

/* If the attribute has cluster-list and one of the cluster-ids in it is the same as remote
* peer's cluster-id. Only when the loose check cluster-id check is enabled and the peer
* is part of a per-neighbor cluster, otherwise it is filtered when received by the
* route-reflector
*/
if (CHECK_FLAG(bgp->flags, BGP_FLAG_LOOSE_CLUSTER_LIST_CHECK) &&
CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CLUSTER_ID)) {
if (bgp_attr_exists(piattr, BGP_ATTR_CLUSTER_LIST) &&
cluster_loop_check(bgp_attr_get_cluster(piattr), peer->cluster[afi][safi])) {
frrtrace(3, frr_bgp, upd_prefix_filtered_due_to, 4, peer->host, pfxprint);
return false;
}
}

/* ORF prefix-list filter check */
if (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) &&
CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV))
Expand Down Expand Up @@ -2678,23 +2821,23 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
/* IBGP reflection check. */
if (ibgp_to_ibgp && !samepeer_safe) {
/* A route from a Client peer. */
if (CHECK_FLAG(from->af_flags[afi][safi],
PEER_FLAG_REFLECTOR_CLIENT)) {
if (CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) {
/* Reflect to all the Non-Client peers and also to the
Client peers other than the originator. Originator
check
is already done. So there is noting to do. */
/* no bgp client-to-client reflection check. */
if (CHECK_FLAG(bgp->flags,
BGP_FLAG_NO_CLIENT_TO_CLIENT))
if (CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_REFLECTOR_CLIENT))
* Client peers other than the originator. Originator
* check
* is already done. So there is nothing to do.
*/
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) {
/* checks client-to-client reflection policies*/
ret = ibgp_reflection_check(bgp, from, peer, afi, safi);
if (!ret)
return false;
}
} else {
/* A route from a Non-client peer. Reflect to all other
clients. */
if (!CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_REFLECTOR_CLIENT))
* clients.
*/
if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
return false;
}
}
Expand Down
15 changes: 14 additions & 1 deletion bgpd/bgp_updgrp.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
dst->v_routeadv = src->v_routeadv;
dst->flags = src->flags;
dst->af_flags[afi][safi] = src->af_flags[afi][safi];
dst->cluster[afi][safi] = src->cluster[afi][safi];
/*do not need to increment refcount:
*as soon as there is no more peer in the cluster
*there there will be no more peer in the subgroup and
*the subgroup will be deleted
*/
dst->cluster_flags[afi][safi] = src->cluster_flags[afi][safi];
dst->pmax_out[afi][safi] = src->pmax_out[afi][safi];
dst->max_packet_size = src->max_packet_size;
XFREE(MTYPE_BGP_PEER_HOST, dst->host);
Expand Down Expand Up @@ -371,6 +378,8 @@ static unsigned int updgrp_hash_key_make(const void *p)
CHECK_FLAG(peer->flags,
PEER_FLAG_AS_LOOP_DETECTION),
key);
if (CHECK_FLAG(flags, PEER_FLAG_CLUSTER_ID))
key = jhash_1word(peer->cluster[afi][safi].s_addr, key);
if (peer->group)
key = jhash_1word(jhash(peer->group->name,
strlen(peer->group->name), SEED1),
Expand Down Expand Up @@ -582,7 +591,6 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2)
flags2 = pe2->af_flags[afi][safi];
fl1 = &pe1->filter[afi][safi];
fl2 = &pe2->filter[afi][safi];

/* put EBGP and IBGP peers in different update groups */
if (pe1->sort != pe2->sort)
return false;
Expand All @@ -603,6 +611,11 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2)
if ((flags1 & PEER_UPDGRP_AF_FLAGS) != (flags2 & PEER_UPDGRP_AF_FLAGS))
return false;

/*if per neighbor cluster is configured it should match*/
if (CHECK_FLAG(flags1, PEER_FLAG_CLUSTER_ID) && CHECK_FLAG(flags2, PEER_FLAG_CLUSTER_ID) &&
!IPV4_ADDR_SAME(&pe1->cluster[afi][safi], &pe2->cluster[afi][safi]))
return false;

if (pe1->addpath_type[afi][safi] != pe2->addpath_type[afi][safi])
return false;

Expand Down
2 changes: 1 addition & 1 deletion bgpd/bgp_updgrp.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
PEER_FLAG_REMOVE_PRIVATE_AS_ALL | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \
PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE | PEER_FLAG_AS_OVERRIDE | \
PEER_FLAG_CONFIG_ENCAPSULATION_SRV6 | PEER_FLAG_CONFIG_ENCAPSULATION_SRV6_RELAX | \
PEER_FLAG_CONFIG_ENCAPSULATION_MPLS)
PEER_FLAG_CONFIG_ENCAPSULATION_MPLS | PEER_FLAG_CLUSTER_ID)

#define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)

Expand Down
Loading
Loading