Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BMP Peer Distinguisher support #17555

Merged
merged 9 commits into from
Dec 11, 2024
155 changes: 94 additions & 61 deletions bgpd/bgp_bmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,37 +275,33 @@ static inline int bmp_get_peer_type(struct peer *peer)
return bmp_get_peer_type_vrf(peer->bgp->vrf_id);
}

static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi,
uint8_t peer_type,
static inline int bmp_get_peer_distinguisher(struct bgp *bgp, afi_t afi, uint8_t peer_type,
uint64_t *result_ref)
{

/* remove this check when the other peer types get correct peer dist.
*(RFC7854) impl.
* for now, always return no error and 0 peer distinguisher as before
*/
if (peer_type != BMP_PEER_TYPE_LOC_RIB_INSTANCE)
return (*result_ref = 0);
/* use RD if set in VRF config */
struct prefix_rd *prd;

/* sending vrf_id or rd could be turned into an option at some point */
struct bgp *bgp = bmp->targets->bgp;
if (peer_type == BMP_PEER_TYPE_LOCAL_INSTANCE || bgp->vrf_id == VRF_UNKNOWN)
return 1;

/* vrf default => ok, distinguisher 0 */
if (bgp->inst_type == VRF_DEFAULT)
return (*result_ref = 0);

/* use RD if set in VRF config for this AFI */
struct prefix_rd *prd = &bgp->vpn_policy[afi].tovpn_rd;

if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET)) {
prd = &bgp->vpn_policy[AFI_IP].tovpn_rd;
if ((afi == AFI_IP || afi == AFI_UNSPEC) &&
CHECK_FLAG(bgp->vpn_policy[AFI_IP].flags, BGP_VPN_POLICY_TOVPN_RD_SET)) {
memcpy(result_ref, prd->val, sizeof(prd->val));
return 0;
}

/* VRF has no id => error => message should be skipped */
if (bgp->vrf_id == VRF_UNKNOWN)
return 1;
prd = &bgp->vpn_policy[AFI_IP6].tovpn_rd;
if ((afi == AFI_IP6 || afi == AFI_UNSPEC) &&
CHECK_FLAG(bgp->vpn_policy[AFI_IP6].flags, BGP_VPN_POLICY_TOVPN_RD_SET)) {
memcpy(result_ref, prd->val, sizeof(prd->val));
return 0;
}

/* use VRF id converted to ::vrf_id 64bits format */
*result_ref = ((uint64_t)htonl(bgp->vrf_id)) << 32;
Expand Down Expand Up @@ -469,6 +465,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
struct timeval uptime, uptime_real;
uint8_t peer_type;
bool is_locrib = false;
uint64_t peer_distinguisher = 0;

uptime.tv_sec = peer->uptime;
uptime.tv_usec = 0;
Expand All @@ -477,9 +474,12 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
peer_type = bmp_get_peer_type(peer);
if (peer_type == BMP_PEER_TYPE_LOC_RIB_INSTANCE)
is_locrib = true;
else
/* TODO: remove this when other RD and local instances supported */
peer_type = BMP_PEER_TYPE_GLOBAL_INSTANCE;

if (bmp_get_peer_distinguisher(peer->bgp, AFI_UNSPEC, peer_type, &peer_distinguisher)) {
zlog_warn("skipping bmp message for peer %s: can't get peer distinguisher",
peer->host);
return NULL;
}

#define BGP_BMP_MAX_PACKET_SIZE 1024
#define BMP_PEERUP_INFO_TYPE_STRING 0
Expand All @@ -490,7 +490,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)

bmp_common_hdr(s, BMP_VERSION_3,
BMP_TYPE_PEER_UP_NOTIFICATION);
bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, 0, &uptime_real);
bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, peer_distinguisher, &uptime_real);

/* Local Address (16 bytes) */
if (is_locrib)
Expand Down Expand Up @@ -552,9 +552,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)

bmp_common_hdr(s, BMP_VERSION_3,
BMP_TYPE_PEER_DOWN_NOTIFICATION);
bmp_per_peer_hdr(s, peer->bgp, peer, 0,
BMP_PEER_TYPE_GLOBAL_INSTANCE, 0,
&uptime_real);
bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, peer_distinguisher, &uptime_real);

type_pos = stream_get_endp(s);
stream_putc(s, 0); /* placeholder for down reason */
Expand Down Expand Up @@ -608,8 +606,10 @@ static int bmp_send_peerup(struct bmp *bmp)
/* Walk down all peers */
for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) {
s = bmp_peerstate(peer, false);
pullwr_write_stream(bmp->pullwr, s);
stream_free(s);
if (s) {
pullwr_write_stream(bmp->pullwr, s);
stream_free(s);
}
}

return 0;
Expand All @@ -626,10 +626,10 @@ static int bmp_send_peerup_vrf(struct bmp *bmp)
bmp_bgp_update_vrf_status(bmpbgp, vrf_state_unknown);

s = bmp_peerstate(bmpbgp->bgp->peer_self, bmpbgp->vrf_state == vrf_state_down);

pullwr_write_stream(bmp->pullwr, s);
stream_free(s);

if (s) {
pullwr_write_stream(bmp->pullwr, s);
stream_free(s);
}
return 0;
}

Expand All @@ -640,6 +640,9 @@ static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s)
struct bmp_targets *bt;
struct bmp *bmp;

if (!s)
return;

frr_each(bmp_targets, &bmpbgp->targets, bt)
frr_each(bmp_session, &bt->sessions, bmp)
pullwr_write_stream(bmp->pullwr, s);
Expand All @@ -648,6 +651,9 @@ static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s)

static void bmp_send_all_safe(struct bmp_bgp *bmpbgp, struct stream *s)
{
if (!s)
return;

if (!bmpbgp) {
stream_free(s);
return;
Expand Down Expand Up @@ -775,14 +781,24 @@ static void bmp_wrmirror_lost(struct bmp *bmp, struct pullwr *pullwr)
{
struct stream *s;
struct timeval tv;
uint8_t peer_type_flag;
uint64_t peer_distinguisher = 0;

gettimeofday(&tv, NULL);

peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id);

if (bmp_get_peer_distinguisher(bmp->targets->bgp, AFI_UNSPEC, peer_type_flag,
&peer_distinguisher)) {
zlog_warn("skipping bmp message for reason: can't get peer distinguisher");
return;
}

s = stream_new(BGP_MAX_PACKET_SIZE);

bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING);
bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0,
BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv);
bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0, peer_type_flag,
peer_distinguisher, &tv);

stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO);
stream_putw(s, 2);
Expand All @@ -799,6 +815,8 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr)
struct bmp_mirrorq *bmq;
struct peer *peer;
bool written = false;
uint8_t peer_type_flag;
uint64_t peer_distinguisher = 0;

if (bmp->mirror_lost) {
bmp_wrmirror_lost(bmp, pullwr);
Expand All @@ -816,12 +834,20 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr)
goto out;
}

peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id);

if (bmp_get_peer_distinguisher(peer->bgp, AFI_UNSPEC, peer_type_flag, &peer_distinguisher)) {
zlog_warn("skipping bmp message for peer %s: can't get peer distinguisher",
peer->host);
goto out;
}

struct stream *s;
s = stream_new(BGP_MAX_PACKET_SIZE);

bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING);
bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0,
BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &bmq->tv);
bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, peer_type_flag, peer_distinguisher,
&bmq->tv);

/* BMP Mirror TLV. */
stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE);
Expand Down Expand Up @@ -971,8 +997,7 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags,

uint64_t peer_distinguisher = 0;
/* skip this message if peer distinguisher is not available */
if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag,
&peer_distinguisher)) {
if (bmp_get_peer_distinguisher(peer->bgp, afi, peer_type_flag, &peer_distinguisher)) {
zlog_warn(
"skipping bmp message for reason: can't get peer distinguisher");
continue;
Expand Down Expand Up @@ -1100,8 +1125,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,

uint64_t peer_distinguisher = 0;
/* skip this message if peer distinguisher is not available */
if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag,
&peer_distinguisher)) {
if (bmp_get_peer_distinguisher(peer->bgp, afi, peer_type_flag, &peer_distinguisher)) {
zlog_warn(
"skipping bmp message for reason: can't get peer distinguisher");
return;
Expand Down Expand Up @@ -1135,6 +1159,7 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
uint8_t bpi_num_labels, adjin_num_labels;
afi_t afi;
safi_t safi;
uint8_t peer_type_flag;

if (bmp->syncafi == AFI_MAX) {
FOREACH_AFI_SAFI (afi, safi) {
Expand Down Expand Up @@ -1177,6 +1202,8 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
struct bgp_path_info *bpi = NULL, *bpiter;
struct bgp_adj_in *adjin = NULL, *adjiter;

peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id);

if ((afi == AFI_L2VPN && safi == SAFI_EVPN) ||
(safi == SAFI_MPLS_VPN)) {
/* initialize syncrdpos to the first
Expand Down Expand Up @@ -1231,10 +1258,8 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
bmp->remote, afi2str(afi),
safi2str(safi));

bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L,
BMP_PEER_TYPE_GLOBAL_INSTANCE);
bmp_eor(bmp, afi, safi, 0,
BMP_PEER_TYPE_GLOBAL_INSTANCE);
bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L, peer_type_flag);
bmp_eor(bmp, afi, safi, 0, peer_type_flag);
bmp_eor(bmp, afi, safi, 0,
BMP_PEER_TYPE_LOC_RIB_INSTANCE);

Expand Down Expand Up @@ -1318,19 +1343,20 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
bpi_num_labels);
}

if (bpi)
peer_type_flag = bmp_get_peer_type(bpi->peer);

if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) &&
CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY))
bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L,
BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, bpi->attr,
bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, peer_type_flag, bn_p, prd, bpi->attr,
afi, safi, bpi->uptime,
bpi_num_labels ? bpi->extra->labels->label : NULL,
bpi_num_labels);
bpi_num_labels ? bpi->extra->labels->label : NULL, bpi_num_labels);

if (adjin) {
adjin_num_labels = adjin->labels ? adjin->labels->num_labels : 0;
bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd,
adjin->attr, afi, safi, adjin->uptime,
adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
bmp_monitor(bmp, adjin->peer, 0, peer_type_flag, bn_p, prd, adjin->attr, afi, safi,
adjin->uptime, adjin_num_labels ? &adjin->labels->label[0] : NULL,
adjin_num_labels);
}

if (bn)
Expand Down Expand Up @@ -1469,6 +1495,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
struct bgp_dest *bn = NULL;
bool written = false;
uint8_t bpi_num_labels, adjin_num_labels;
uint8_t peer_type_flag;

bqe = bmp_pull(bmp);
if (!bqe)
Expand Down Expand Up @@ -1509,6 +1536,8 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi,
&bqe->p, prd);

peer_type_flag = bmp_get_peer_type(peer);

if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) {
struct bgp_path_info *bpi;

Expand All @@ -1522,12 +1551,9 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)

bpi_num_labels = BGP_PATH_INFO_NUM_LABELS(bpi);

bmp_monitor(bmp, peer, BMP_PEER_FLAG_L,
BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
bpi ? bpi->attr : NULL, afi, safi,
bpi ? bpi->uptime : monotime(NULL),
bpi_num_labels ? bpi->extra->labels->label : NULL,
bpi_num_labels);
bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, peer_type_flag, &bqe->p, prd,
bpi ? bpi->attr : NULL, afi, safi, bpi ? bpi->uptime : monotime(NULL),
bpi_num_labels ? bpi->extra->labels->label : NULL, bpi_num_labels);
written = true;
}

Expand All @@ -1540,9 +1566,8 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
break;
}
adjin_num_labels = adjin && adjin->labels ? adjin->labels->num_labels : 0;
bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
adjin ? adjin->attr : NULL, afi, safi,
adjin ? adjin->uptime : monotime(NULL),
bmp_monitor(bmp, peer, 0, peer_type_flag, &bqe->p, prd, adjin ? adjin->attr : NULL,
afi, safi, adjin ? adjin->uptime : monotime(NULL),
adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
written = true;
}
Expand Down Expand Up @@ -1708,6 +1733,8 @@ static void bmp_stats(struct event *thread)
struct peer *peer;
struct listnode *node;
struct timeval tv;
uint8_t peer_type_flag;
uint64_t peer_distinguisher = 0;

if (bt->stat_msec)
event_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec,
Expand All @@ -1724,8 +1751,14 @@ static void bmp_stats(struct event *thread)

s = stream_new(BGP_MAX_PACKET_SIZE);
bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_STATISTICS_REPORT);
bmp_per_peer_hdr(s, bt->bgp, peer, 0,
BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv);
peer_type_flag = bmp_get_peer_type(peer);
if (bmp_get_peer_distinguisher(peer->bgp, AFI_UNSPEC, peer_type_flag,
&peer_distinguisher)) {
zlog_warn("skipping bmp message for peer %s: can't get peer distinguisher",
peer->host);
continue;
}
bmp_per_peer_hdr(s, bt->bgp, peer, 0, peer_type_flag, peer_distinguisher, &tv);

count_pos = stream_get_endp(s);
stream_putl(s, 0);
Expand Down
18 changes: 5 additions & 13 deletions tests/topotests/bgp_bmp/bgpbmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,6 @@ def bmp_check_for_prefixes(
for k, v in sorted(m.items())
# filter out variable keys
if k not in ["timestamp", "seq", "nxhp_link-local"]
and (
# When policy is loc-rib, the peer-distinguisher is 0:0
# for the default VRF or the RD if any or the 0:<vrf_id>.
# 0:<vrf_id> is used to distinguished. RFC7854 says: "If the
# peer is a "Local Instance Peer", it is set to a unique,
# locally defined value." The value is not tested because it
# is variable.
k != "peer_distinguisher"
or policy != loc_rib
or v == "0:0"
or not v.startswith("0:")
)
}

# build expected JSON files
Expand All @@ -199,7 +187,7 @@ def bmp_check_for_prefixes(


def bmp_check_for_peer_message(
expected_peers, bmp_log_type, bmp_collector, bmp_log_file
expected_peers, bmp_log_type, bmp_collector, bmp_log_file, is_rd_instance=False
):
"""
Check for the presence of a peer up message for the peer
Expand All @@ -218,11 +206,15 @@ def bmp_check_for_peer_message(
# get the list of pairs (prefix, policy, seq) for the given message type
peers = []
for m in messages:
if is_rd_instance and m["peer_distinguisher"] == "0:0":
continue
if (
"peer_ip" in m.keys()
and m["peer_ip"] != "0.0.0.0"
and m["bmp_log_type"] == bmp_log_type
):
if is_rd_instance and m["peer_type"] != "route distinguisher instance":
continue
peers.append(m["peer_ip"])
elif m["policy"] == "loc-rib" and m["bmp_log_type"] == bmp_log_type:
peers.append("0.0.0.0")
Expand Down
Loading
Loading