diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 2e3a0388d0ed..3a4364c5f997 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -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; @@ -467,13 +463,23 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) struct stream *s; size_t len; 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; monotime_to_realtime(&uptime, &uptime_real); - uint8_t peer_type = bmp_get_peer_type(peer); - bool is_locrib = peer_type == BMP_PEER_TYPE_LOC_RIB_INSTANCE; + peer_type = bmp_get_peer_type(peer); + if (peer_type == BMP_PEER_TYPE_LOC_RIB_INSTANCE) + is_locrib = true; + + 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 @@ -484,9 +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, - BMP_PEER_TYPE_GLOBAL_INSTANCE, 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) @@ -548,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 */ @@ -604,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; @@ -622,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; } @@ -636,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); @@ -644,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; @@ -771,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); @@ -795,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); @@ -812,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); @@ -967,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; @@ -1096,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; @@ -1131,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) { @@ -1173,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 @@ -1227,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); @@ -1314,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) @@ -1465,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) @@ -1505,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; @@ -1518,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; } @@ -1536,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; } @@ -1704,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, @@ -1720,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); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 6479126d0637..ca9c428b47b6 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -11,7 +11,6 @@ #include "queue.h" #include "filter.h" #include "stream.h" -#include "jhash.h" #include "frrstr.h" #include "bgpd/bgpd.h" diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f173bd01f20f..204c95022cc9 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1669,9 +1669,18 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, /* attribute changed */ *route_changed = 1; + /* if the asn values are different, copy the asn of + * source vrf to the target (evpn) vrf entry. + */ + if (bgp_vrf->as != bgp_evpn->as) { + new_aspath = aspath_dup(static_attr.aspath); + new_aspath = aspath_add_seq(new_aspath, bgp_vrf->as); + static_attr.aspath = new_aspath; + } /* The attribute has changed. */ /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern(attr); + attr_new = bgp_attr_intern(&static_attr); + bgp_attr_flush(&static_attr); bgp_path_info_set_flag(dest, tmp_pi, BGP_PATH_ATTR_CHANGED); @@ -4212,9 +4221,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, assert(attr); - /* Only type-1, type-2, type-3, type-4 and type-5 - * are supported currently - */ + /* Only EVPN route-types 1-5 are supported currently */ if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE || evp->prefix.route_type == BGP_EVPN_ES_ROUTE @@ -4271,26 +4278,28 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, bgp_evpn_attr_get_esi(pi->attr)); /* - * macip routes (type-2) are imported into VNI and VRF tables. - * IMET route is imported into VNI table. - * prefix routes are imported into VRF table. + * AD/IMET routes (type-1/3) are imported into VNI table. + * MACIP routes (type-2) are imported into VNI and VRF tables. + * Prefix routes (type 5) are imported into VRF table. */ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE || evp->prefix.route_type == BGP_EVPN_AD_ROUTE || evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) { + if (evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE) { + irt = in_vni_rt ? lookup_import_rt(bgp, eval) : NULL; + if (irt) + install_uninstall_route_in_vnis(bgp, afi, safi, evp, pi, + irt->vnis, import); + } - irt = in_vni_rt ? lookup_import_rt(bgp, eval) : NULL; - if (irt) - install_uninstall_route_in_vnis( - bgp, afi, safi, evp, pi, irt->vnis, - import); - - vrf_irt = in_vrf_rt ? lookup_vrf_import_rt(eval) : NULL; - if (vrf_irt) - install_uninstall_route_in_vrfs( - bgp, afi, safi, evp, pi, vrf_irt->vrfs, - import); + if (evp->prefix.route_type != BGP_EVPN_AD_ROUTE && + evp->prefix.route_type != BGP_EVPN_IMET_ROUTE) { + vrf_irt = in_vrf_rt ? lookup_vrf_import_rt(eval) : NULL; + if (vrf_irt) + install_uninstall_route_in_vrfs(bgp, afi, safi, evp, pi, + vrf_irt->vrfs, import); + } /* Also check for non-exact match. * In this, we mask out the AS and diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 958a9c6492b5..338f5cefee0c 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3469,7 +3469,9 @@ static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf, BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6); } - bgp_evpn_install_uninstall_default_route(bgp_vrf, afi, safi, add); + if (is_l3vni_live(bgp_vrf)) + bgp_evpn_install_uninstall_default_route(bgp_vrf, + afi, safi, add); } /* diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index cadef3997423..6ad8a2e8de70 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -662,7 +662,7 @@ static void bgp_llgr_stale_timer_expire(struct event *thread) static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) { struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; struct bgp_table *table; struct attr attr; @@ -677,8 +677,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) - for (pi = bgp_dest_get_bgp_path_info(rm); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(rm); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; @@ -709,8 +709,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) } else { for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) - for (pi = bgp_dest_get_bgp_path_info(dest); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index ca7f73dde993..ecb78c1ce403 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -2167,6 +2167,8 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; struct aspath *new_aspath; + int32_t aspath_loop_count = 0; + struct peer *peer = path_vpn->peer; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); @@ -2227,7 +2229,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); /* Check if leaked route has our asn. If so, don't import it. */ - if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as)) { + if (CHECK_FLAG(peer->af_flags[afi][SAFI_MPLS_VPN], PEER_FLAG_ALLOWAS_IN)) + aspath_loop_count = peer->allowas_in[afi][SAFI_MPLS_VPN]; + if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as) > aspath_loop_count) { for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { if (bpi->extra && bpi->extra->vrfleak && @@ -2513,11 +2517,12 @@ void vpn_leak_to_vrf_update(struct bgp *from_bgp, { struct listnode *mnode, *mnnode; struct bgp *bgp; + const struct prefix *p = bgp_dest_get_prefix(path_vpn->net); int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); if (debug) - zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn); + zlog_debug("%s: start (path_vpn=%p, prefix=%pFX)", __func__, path_vpn, p); /* Loop over VRFs */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5feda7183739..c123c232307c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2587,12 +2587,11 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, if (ret == RMAP_DENYMATCH) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) - zlog_debug( - "%pBP [Update:SEND] %pFX is filtered by route-map '%s'", - peer, p, - bgp_path_suppressed(pi) - ? UNSUPPRESS_MAP_NAME(filter) - : ROUTE_MAP_OUT_NAME(filter)); + zlog_debug("%pBP [Update:SEND] %pFX is filtered by route-map (%s) '%s'", + peer, p, + bgp_path_suppressed(pi) ? "unsuppress-map" : "out", + bgp_path_suppressed(pi) ? UNSUPPRESS_MAP_NAME(filter) + : ROUTE_MAP_OUT_NAME(filter)); bgp_attr_flush(rmap_path.attr); return false; } @@ -7411,7 +7410,7 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, { struct bgp_table *table; struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; /* Do not install the aggregate route if BGP is in the * process of termination. @@ -7422,7 +7421,8 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, table = bgp->rib[afi][safi]; for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (pi->peer == bgp->peer_self && ((pi->type == ZEBRA_ROUTE_BGP && pi->sub_type == BGP_ROUTE_STATIC) @@ -7922,7 +7922,7 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, struct bgp_table *table = bgp->rib[afi][safi]; const struct prefix *dest_p; struct bgp_dest *dest, *top; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; /* We've found a different MED we must revert any suppressed routes. */ top = bgp_node_get(table, p); @@ -7932,7 +7932,8 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, if (dest_p->prefixlen <= p->prefixlen) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; if (pi->sub_type == BGP_ROUTE_AGGREGATE) @@ -8007,7 +8008,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, struct community *community = NULL; struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; uint8_t atomic_aggregate = 0; /* If the bgp instance is being deleted or self peer is deleted @@ -8057,7 +8058,8 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (!bgp_check_advertise(bgp, dest, safi)) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -8214,7 +8216,7 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, struct bgp_table *table; struct bgp_dest *top; struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; table = bgp->rib[afi][safi]; @@ -8227,7 +8229,8 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (dest_p->prefixlen <= p->prefixlen) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 1a66df59fc20..ae741a4809e9 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -582,7 +582,7 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp_dump_attr(attr, attr_str, sizeof(attr_str)); - zlog_debug("%s suppress UPDATE w/ attr: %s", peer->host, + zlog_debug("%s suppress UPDATE %pBD w/ attr: %s", peer->host, dest, attr_str); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 6ff94129dcf5..bb0c69ca56ee 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5228,7 +5228,7 @@ DEFUN (neighbor_peer_group, DEFUN (no_neighbor, no_neighbor_cmd, - "no neighbor [remote-as <(1-4294967295)|internal|external|auto>]>", + "no neighbor [remote-as ]>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 @@ -5307,7 +5307,7 @@ DEFUN (no_neighbor, DEFUN (no_neighbor_interface_config, no_neighbor_interface_config_cmd, - "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]", + "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as ]", NO_STR NEIGHBOR_STR "Interface name\n" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 688dfacaa0b6..d1bf471f5d87 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -744,6 +744,7 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, int ret = 0; struct interface *ifp = NULL; bool v6_ll_avail = true; + bool shared_network_original = peer->shared_network; memset(nexthop, 0, sizeof(struct bgp_nexthop)); @@ -838,9 +839,9 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, if (!v6_ll_avail && !peer->conf_if) v6_ll_avail = true; if (if_lookup_by_ipv4(&remote->sin.sin_addr, peer->bgp->vrf_id)) - peer->shared_network = 1; + peer->shared_network = true; else - peer->shared_network = 0; + peer->shared_network = false; } /* IPv6 connection, fetch and store IPv4 local address if any. */ @@ -903,11 +904,14 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, || if_lookup_by_ipv6(&remote->sin6.sin6_addr, remote->sin6.sin6_scope_id, peer->bgp->vrf_id)) - peer->shared_network = 1; + peer->shared_network = true; else - peer->shared_network = 0; + peer->shared_network = false; } + if (shared_network_original != peer->shared_network) + bgp_peer_bfd_update_source(peer); + /* KAME stack specific treatment. */ #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&nexthop->v6_global) @@ -1187,9 +1191,10 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, ifindex = pi->peer->nexthop.ifp->ifindex; if (!ifindex) { - if (pi->peer->conf_if) - ifindex = pi->peer->ifp->ifindex; - else if (pi->peer->ifname) + if (pi->peer->conf_if) { + if (pi->peer->ifp) + ifindex = pi->peer->ifp->ifindex; + } else if (pi->peer->ifname) ifindex = ifname2ifindex( pi->peer->ifname, pi->peer->bgp->vrf_id); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index f92ae969f8c4..7b21c29ea663 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2158,8 +2158,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, /* When this peer is a member of peer-group. */ if (peer->group) { /* peer-group already has AS number/internal/external */ - if (peer->group->conf->as - || peer->group->conf->as_type) { + if (peer->group->conf->as || peer->group->conf->as_type != AS_UNSPECIFIED) { /* Return peer group's AS number. */ *as = peer->group->conf->as; return BGP_ERR_PEER_GROUP_MEMBER; @@ -2859,6 +2858,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name) group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; + group->conf->as_type = AS_UNSPECIFIED; group->conf->ttl = BGP_DEFAULT_TTL; group->conf->gtsm_hops = BGP_GTSM_HOPS_DISABLED; group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; @@ -5703,7 +5703,7 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (!peer_notify_config_change(peer->connection)) + if (!peer_notify_config_change(member->connection)) bgp_session_reset(member); /* Apply new source configuration to BFD session. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index df55d879e71d..bb56fd355a05 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1330,7 +1330,7 @@ struct peer { union sockunion *su_local; /* Sockunion of local address. */ union sockunion *su_remote; /* Sockunion of remote address. */ - int shared_network; /* Is this peer shared same network. */ + bool shared_network; /* Is this peer shared same network. */ struct bgp_nexthop nexthop; /* Nexthop */ /* Roles in bgp session */ diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 5e22c4cb72b5..45142f7d8396 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -167,15 +167,7 @@ as early as possible, i.e. the first 2-week window. For reference, the expected release schedule according to the above is: -+---------+------------+------------+------------+ -| Release | 2024-03-12 | 2024-07-02 | 2024-11-05 | -+---------+------------+------------+------------+ -| RC | 2024-02-27 | 2024-06-18 | 2024-10-22 | -+---------+------------+------------+------------+ -| dev/X.Y | 2024-02-13 | 2024-06-04 | 2024-10-08 | -+---------+------------+------------+------------+ -| freeze | 2024-01-30 | 2024-05-21 | 2024-09-24 | -+---------+------------+------------+------------+ +.. graphviz:: ../figures/releases.dot Here is the hint on how to get the dates easily: diff --git a/doc/figures/releases.dot b/doc/figures/releases.dot new file mode 100644 index 000000000000..57d35987f853 --- /dev/null +++ b/doc/figures/releases.dot @@ -0,0 +1,44 @@ +digraph ReleaseTimeline { + rankdir=LR; + node [shape=box, style=rounded, fontsize=10, width=1.5, fontname="Helvetica"]; + + subgraph cluster_dev { + label="Development"; + style=dashed; + color=blue; + node [fillcolor=lightblue, style=filled]; + "dev/X.Y"; + } + + subgraph cluster_rc { + label="Release Candidate"; + style=dashed; + color=orange; + node [fillcolor=orange, style=filled]; + "RC"; + } + + subgraph cluster_stable { + label="Stable Release"; + style=dashed; + color=green; + node [fillcolor=lightgreen, style=filled]; + "release"; + } + + // Release steps with actions + "freeze" [label="Freeze", shape=ellipse, style=dotted, fontcolor=red]; + "dev/X.Y" [label="dev/X.Y\n(Development)", fillcolor=lightblue]; + "RC" [label="RC\n(Release Candidate)", fillcolor=orange]; + "release" [label="Release\n(Final)", fillcolor=lightgreen]; + + // Connect the steps with actions + "freeze" -> "dev/X.Y" [label=" "]; + "dev/X.Y" -> "RC" [label=" "]; + "RC" -> "release" [label=" "]; + + // Date connections (freeze -> dev/X.Y -> RC -> release) + "2025-01-21" -> "2025-02-04" -> "2025-02-18" -> "2025-03-04"; + "2025-05-20" -> "2025-06-03" -> "2025-06-17" -> "2025-07-01"; + "2025-09-23" -> "2025-10-07" -> "2025-10-21" -> "2025-11-04"; +} diff --git a/doc/user/filter.rst b/doc/user/filter.rst index c1146e50aa2b..be63095166fa 100644 --- a/doc/user/filter.rst +++ b/doc/user/filter.rst @@ -9,9 +9,7 @@ defined, it can be applied in any direction. IP Access List ============== -.. clicmd:: access-list NAME [seq (1-4294967295)] permit IPV4-NETWORK - -.. clicmd:: access-list NAME [seq (1-4294967295)] deny IPV4-NETWORK +.. clicmd:: access-list NAME [seq (1-4294967295)] seq seq `number` can be set either automatically or manually. In the @@ -35,6 +33,29 @@ IP Access List access-list filter permit 10.0.0.0/8 access-list filter seq 13 permit 10.0.0.0/7 +.. clicmd:: access-list NAME [seq (1-4294967295)] ip + + The extended access-list syntax enables filtering on both source and destination + IP addresses (or source and group, if used for multicast boundaries). The + source address is first in order in the command. + + If providing a mask, note that the access-lists use wildcard masks (inverse + matching logic of subnet masks). If specifying ``host``, only the single address + given will be matched. + + A basic example is as follows: + + .. code-block:: frr + + access-list filter seq 5 permit ip host 10.0.20.2 232.1.1.0 0.0.0.128 + access-list filter seq 10 deny ip 10.0.20.0 0.0.0.255 232.1.1.0 0.0.0.255 + access-list filter seq 15 permit ip any any + + .. note :: + + If an access-list is specified but no match is found, the default verdict + is deny. + .. clicmd:: show access-list [json] Display all IPv4 or IPv6 access lists. diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 0fe53247b05e..322159e44a57 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -6,9 +6,9 @@ PIM PIM -- Protocol Independent Multicast -*pimd* supports pim-sm as well as igmp v2 and v3. pim is -vrf aware and can work within the context of vrf's in order to -do S,G mrouting. Additionally PIM can be used in the EVPN underlay +*pimd* supports PIM-SM as well as IGMP v2 and v3. PIM is +VRF aware and can work within the context of VRFs in order to +do S,G mrouting. Additionally, PIM can be used in the EVPN underlay network for optimizing forwarding of overlay BUM traffic. .. note:: @@ -348,10 +348,46 @@ is in a vrf, enter the interface command with the vrf keyword at the end. .. clicmd:: ip multicast boundary oil WORD - Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join - or IGMP report is received on this interface and the Group is denied by the + Set a PIM multicast boundary, based upon the WORD prefix-list. If a PIM join + or IGMP report is received on this interface and the group is denied by the prefix-list, PIM will ignore the join or report. + .. code-block:: frr + + prefix-list multicast-acl seq 5 permit 232.1.1.1/32 + prefix-list multicast-acl seq 10 deny 232.1.1.0/24 + prefix-list multicast-acl seq 15 permit any + ! + interface r1-eth0 + ip pim + ip igmp + ip multicast boundary oil multicast-acl + exit + +.. clicmd:: ip multicast boundary ACCESS-LIST + + Set a PIM multicast boundary, based upon the ACCESS-LIST. If a PIM join + or IGMP report is received on this interface and the (S,G) tuple is denied by the + access-list, PIM will ignore the join or report. + + To filter on both source and group, the extended access-list syntax must be used. + + If both a prefix-list and access-list are configured for multicast boundaries, + the prefix-list will be evaluated first (and must have a terminating "permit any" + in order to also evaluate against the access-list). + + .. code-block:: frr + + access-list multicast-acl seq 5 permit ip host 10.0.20.2 host 232.1.1.1 + access-list multicast-acl seq 10 deny ip 10.0.20.0 0.0.0.255 232.1.1.0 0.0.0.255 + access-list multicast-acl seq 15 permit ip any any + ! + interface r1-eth0 + ip pim + ip igmp + ip multicast boundary pim-acl + exit + .. clicmd:: ip igmp last-member-query-count (1-255) Set the IGMP last member query count. The default value is 2. 'no' form of @@ -467,6 +503,10 @@ Commands available for MSDP The filtering will only take effect starting from the command application. +.. clicmd:: msdp peer A.B.C.D sa-limit + + Configure the maximum number of SAs to learn from peer. + .. clicmd:: msdp peer A.B.C.D password WORD Use MD5 authentication to connect with the remote peer. @@ -478,6 +518,14 @@ Commands available for MSDP To apply it immediately call `clear ip msdp peer A.B.C.D`. +.. clicmd:: msdp originator-id A.B.C.D + + Use the specified originator ID instead of the multicast RP group. + +.. clicmd:: msdp shutdown + + Shutdown the MSDP sessions in this PIM instance. + .. _show-pim-information: diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index b862ba9f505c..9b9298c1cd99 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -526,16 +526,6 @@ commands in relationship to VRF. Here is an extract of some of those commands: The network administrator can however decide to provision this command in configuration file to provide more clarity about the intended configuration. -.. clicmd:: netns NAMESPACE - - This command is based on VRF configuration mode. This command is available - when *Zebra* is run in :option:`-n` mode. This command reflects which *Linux - network namespace* is to be mapped with *Zebra* VRF. It is to be noted that - *Zebra* creates and detects added/suppressed VRFs from the Linux environment - (in fact, those managed with iproute2). The network administrator can however - decide to provision this command in configuration file to provide more clarity - about the intended configuration. - .. clicmd:: show ip route vrf VRF The show command permits dumping the routing table associated to the VRF. If diff --git a/lib/bfd.c b/lib/bfd.c index 4535fc123378..bc4b1c5b51e6 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -32,6 +32,8 @@ enum bfd_session_event { BSE_UNINSTALL, /** Install the BFD session configuration. */ BSE_INSTALL, + /** We should install but it couldn't because of a error talking to zebra */ + BSE_VALID_FOR_INSTALL, }; /** @@ -527,6 +529,10 @@ static void _bfd_sess_send(struct event *t) vrf_id_to_name(bsp->args.vrf_id), bsp->args.vrf_id, bsp->lastev == BSE_INSTALL ? "installed" : "uninstalled"); + + bsp->installed = false; + if (bsp->lastev == BSE_INSTALL) + bsp->lastev = BSE_VALID_FOR_INSTALL; } } @@ -883,7 +889,7 @@ int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS) /* Replay all activated peers. */ TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { /* Skip not installed sessions. */ - if (!bsp->installed) + if (!bsp->installed && bsp->lastev != BSE_VALID_FOR_INSTALL) continue; /* We are reconnecting, so we must send installation. */ diff --git a/lib/routemap.c b/lib/routemap.c index 120731fa61d4..7aaa5d3be8d9 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -875,6 +875,28 @@ void route_map_walk_update_list(void (*route_map_update_fn)(char *name)) } } +static const char *route_map_action_reason2str(enum route_map_action_reason reason) +{ + switch (reason) { + case route_map_action_none: + return "none"; + case route_map_action_map_null: + return "route-map is null"; + case route_map_action_no_index: + return "no index"; + case route_map_action_next_deny: + return "next statement is deny"; + case route_map_action_exit: + return "exit policy"; + case route_map_action_goto_null: + return "goto index is null"; + case route_map_action_index_deny: + return "deny index"; + } + + return "Invalid reason"; +} + /* Return route map's type string. */ static const char *route_map_type_str(enum route_map_type type) { @@ -2554,6 +2576,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, RUSAGE_T mbefore, mafter; RUSAGE_T ibefore, iafter; unsigned long cputime; + enum route_map_action_reason reason = route_map_action_none; if (recursion > RMAP_RECURSION_LIMIT) { if (map) @@ -2571,6 +2594,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, if (map) map->applied++; ret = RMAP_DENYMATCH; + reason = route_map_action_map_null; goto route_map_apply_end; } @@ -2614,6 +2638,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, ret = RMAP_PERMITMATCH; else ret = RMAP_DENYMATCH; + reason = route_map_action_no_index; goto route_map_apply_end; } @@ -2701,12 +2726,15 @@ route_map_result_t route_map_apply_ext(struct route_map *map, } /* If nextrm returned 'deny', finish. */ - if (ret == RMAP_DENYMATCH) + if (ret == RMAP_DENYMATCH) { + reason = route_map_action_next_deny; goto route_map_apply_end; + } } switch (index->exitpolicy) { case RMAP_EXIT: + reason = route_map_action_exit; goto route_map_apply_end; case RMAP_NEXT: continue; @@ -2722,6 +2750,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, } if (next == NULL) { /* No clauses match! */ + reason = route_map_action_goto_null; goto route_map_apply_end; } } @@ -2730,6 +2759,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, /* 'deny' */ { ret = RMAP_DENYMATCH; + reason = route_map_action_index_deny; goto route_map_apply_end; } } @@ -2741,9 +2771,9 @@ route_map_result_t route_map_apply_ext(struct route_map *map, route_map_apply_end: if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))) - zlog_debug("Route-map: %s, prefix: %pFX, result: %s", - (map ? map->name : "null"), prefix, - route_map_result_str(ret)); + zlog_debug("Route-map: %s, prefix: %pFX, result: %s, reason: %s", + (map ? map->name : "null"), prefix, route_map_result_str(ret), + route_map_action_reason2str(reason)); if (pref) { if (index != NULL && ret == RMAP_PERMITMATCH) diff --git a/lib/routemap.h b/lib/routemap.h index e0f738502b9e..8dcc17ecc307 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -29,6 +29,17 @@ extern uint32_t rmap_debug; /* Route map's type. */ enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY }; +/* Route-map's action reason */ +enum route_map_action_reason { + route_map_action_none, + route_map_action_map_null, + route_map_action_no_index, + route_map_action_next_deny, + route_map_action_exit, + route_map_action_goto_null, + route_map_action_index_deny, +}; + typedef enum { RMAP_DENYMATCH, RMAP_PERMITMATCH diff --git a/lib/sockopt.c b/lib/sockopt.c index 74bc034ccd75..003ddb72dc2d 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -19,7 +19,7 @@ #define HAVE_BSD_STRUCT_IP_MREQ_HACK #endif -void setsockopt_so_recvbuf(int sock, int size) +int setsockopt_so_recvbuf(int sock, int size) { int orig_req = size; @@ -34,9 +34,11 @@ void setsockopt_so_recvbuf(int sock, int size) flog_err(EC_LIB_SOCKET, "%s: fd %d: SO_RCVBUF set to %d (requested %d)", __func__, sock, size, orig_req); + + return size; } -void setsockopt_so_sendbuf(const int sock, int size) +int setsockopt_so_sendbuf(const int sock, int size) { int orig_req = size; @@ -51,6 +53,8 @@ void setsockopt_so_sendbuf(const int sock, int size) flog_err(EC_LIB_SOCKET, "%s: fd %d: SO_SNDBUF set to %d (requested %d)", __func__, sock, size, orig_req); + + return size; } int getsockopt_so_sendbuf(const int sock) diff --git a/lib/sockopt.h b/lib/sockopt.h index e6fb78d5e4ef..cbf988cbe718 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -12,8 +12,8 @@ extern "C" { #endif -extern void setsockopt_so_recvbuf(int sock, int size); -extern void setsockopt_so_sendbuf(const int sock, int size); +extern int setsockopt_so_recvbuf(int sock, int size); +extern int setsockopt_so_sendbuf(const int sock, int size); extern int getsockopt_so_sendbuf(const int sock); extern int getsockopt_so_recvbuf(const int sock); diff --git a/lib/vty.c b/lib/vty.c index 256a3bb3f538..1d04e75bf445 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -43,6 +43,7 @@ #include "northbound_cli.h" #include "printfrr.h" #include "json.h" +#include "sockopt.h" #include #include @@ -352,7 +353,7 @@ int vty_out(struct vty *vty, const char *format, ...) * put the data of collective vty->obuf Linked List items on the * socket and free the vty->obuf data. */ - if (vty->vty_buf_size_accumulated >= VTY_MAX_INTERMEDIATE_FLUSH) { + if (vty->vty_buf_size_accumulated >= vty->buf_size_intermediate) { vty->vty_buf_size_accumulated = 0; vtysh_flush(vty); } @@ -2157,15 +2158,15 @@ static void vtysh_accept(struct event *thread) * Increasing the SEND socket buffer size so that the socket can hold * before sending it to VTY shell. */ - ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbufsize, - sizeof(sndbufsize)); - if (ret < 0) { + ret = setsockopt_so_sendbuf(sock, sndbufsize); + if (ret <= 0) { flog_err(EC_LIB_SOCKET, "Cannot set socket %d send buffer size, %s", sock, safe_strerror(errno)); close(sock); return; } + set_cloexec(sock); #ifdef VTYSH_DEBUG @@ -2173,6 +2174,13 @@ static void vtysh_accept(struct event *thread) #endif /* VTYSH_DEBUG */ vty = vty_new(); + + vty->buf_size_set = ret; + if (vty->buf_size_set < VTY_MAX_INTERMEDIATE_FLUSH) + vty->buf_size_intermediate = vty->buf_size_set / 2; + else + vty->buf_size_intermediate = VTY_MAX_INTERMEDIATE_FLUSH; + vty->fd = sock; vty->wfd = sock; vty->type = VTY_SHELL_SERV; diff --git a/lib/vty.h b/lib/vty.h index e511e8e79ae4..be54159aa95d 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -237,6 +237,9 @@ struct vty { bool mgmt_locked_candidate_ds; bool mgmt_locked_running_ds; uint64_t vty_buf_size_accumulated; + + int buf_size_set; + uint64_t buf_size_intermediate; }; static inline void vty_push_context(struct vty *vty, int node, uint64_t id) diff --git a/lib/zclient.c b/lib/zclient.c index 557d9c3eb9b4..063944fd3b23 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -4693,6 +4693,9 @@ void zclient_redistribute_default(int command, struct zclient *zclient, zebra_redistribute_default_send(command, zclient, afi, vrf_id); } +#define ZCLIENT_QUICK_RECONNECT 1 +#define ZCLIENT_SLOW_RECONNECT 5 +#define ZCLIENT_SWITCH_TO_SLOW 30 static void zclient_event(enum zclient_event event, struct zclient *zclient) { switch (event) { @@ -4702,11 +4705,13 @@ static void zclient_event(enum zclient_event event, struct zclient *zclient) break; case ZCLIENT_CONNECT: if (zclient_debug) - zlog_debug( - "zclient connect failures: %d schedule interval is now %d", - zclient->fail, zclient->fail < 3 ? 10 : 60); + zlog_debug("zclient connect failures: %d schedule interval is now %d", + zclient->fail, + zclient->fail < ZCLIENT_SWITCH_TO_SLOW ? ZCLIENT_QUICK_RECONNECT + : ZCLIENT_SLOW_RECONNECT); event_add_timer(zclient->master, zclient_connect, zclient, - zclient->fail < 3 ? 10 : 60, + zclient->fail < ZCLIENT_SWITCH_TO_SLOW ? ZCLIENT_QUICK_RECONNECT + : ZCLIENT_SLOW_RECONNECT, &zclient->t_connect); break; case ZCLIENT_READ: diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 8f7a46377c86..ea0e2e4eaf10 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -732,6 +732,14 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group, bool installed) pbr_map_check(pbrms, false); } + + /* + * vrf_unchanged pbrms have no nhg but their + * installation is contingent on other sequences which + * may... + */ + if (pbrms->vrf_unchanged) + pbr_map_check(pbrms, false); } } } diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index b44169c522f1..acfb0c3af3e0 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -449,7 +449,7 @@ static void gm_sg_update(struct gm_sg *sg, bool has_expired) * this data structure. */ if (sg->oil) - pim_channel_oil_del(sg->oil, __func__); + sg->oil = pim_channel_oil_del(sg->oil, __func__); /* multiple paths can lead to the last state going away; * t_sg_expire can still be running if we're arriving from diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c index 3b46e7fb2bde..caed914a87fb 100644 --- a/pimd/pim_autorp.c +++ b/pimd/pim_autorp.c @@ -1508,12 +1508,14 @@ void pim_autorp_init(struct pim_instance *pim) autorp->discovery_holdtime = DEFAULT_AUTORP_DISCOVERY_HOLDTIME; cand_addrsel_clear(&(autorp->mapping_agent_addrsel)); + pim->autorp = autorp; + if (!pim_autorp_socket_enable(autorp)) { - zlog_warn("%s: AutoRP failed to initialize", __func__); + zlog_warn("%s: AutoRP failed to initialize, feature will not work correctly", + __func__); return; } - pim->autorp = autorp; if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP Initialized", __func__); diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 75104141ae8e..1efdebdee1b7 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -480,9 +480,7 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) pend = bsm_rpinfos_first(bsgrp_node->partial_bsrp_list); - if (!pim_get_all_mcast_group(&group_all)) - return; - + pim_get_all_mcast_group(&group_all); rp_all = pim_rp_find_match_group(pim, &group_all); rn = route_node_lookup(pim->rp_table, &bsgrp_node->group); @@ -729,9 +727,7 @@ void pim_bsm_clear(struct pim_instance *pim) pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info); - if (!pim_get_all_mcast_group(&g_all)) - return; - + pim_get_all_mcast_group(&g_all); rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a2a4c3493108..205f1f95ea61 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -5871,6 +5871,21 @@ DEFUN(interface_no_ip_pim_boundary_oil, return pim_process_no_ip_pim_boundary_oil_cmd(vty); } +DEFPY_YANG(interface_ip_pim_boundary_acl, + interface_ip_pim_boundary_acl_cmd, + "[no] ip multicast boundary ACCESSLIST4_NAME$name", + NO_STR + IP_STR + "Generic multicast configuration options\n" + "Define multicast boundary\n" + "Access-list to filter OIL with by source and group\n") +{ + nb_cli_enqueue_change(vty, "./multicast-boundary-acl", + (!!no ? NB_OP_DESTROY : NB_OP_MODIFY), name); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL); +} + DEFUN (interface_ip_mroute, interface_ip_mroute_cmd, "ip mroute INTERFACE A.B.C.D [A.B.C.D]", @@ -7560,6 +7575,65 @@ DEFPY_ATTR(no_ip_pim_msdp_mesh_group, return ret; } +DEFPY(msdp_shutdown, + msdp_shutdown_cmd, + "[no] msdp shutdown", + NO_STR + CFG_MSDP_STR + "Shutdown MSDP operation\n") +{ + char xpath_value[XPATH_MAXLEN]; + + snprintf(xpath_value, sizeof(xpath_value), "./msdp/shutdown"); + if (no) + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(msdp_peer_sa_limit, msdp_peer_sa_limit_cmd, + "[no] msdp peer A.B.C.D$peer sa-limit ![(1-4294967294)$sa_limit]", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP peer address\n" + "Limit amount of SA\n" + "Maximum number of SA\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./sa-limit", NB_OP_MODIFY, sa_limit_str); + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(msdp_originator_id, msdp_originator_id_cmd, + "[no] msdp originator-id ![A.B.C.D$originator_id]", + NO_STR + CFG_MSDP_STR + "Configure MSDP RP originator\n" + "MSDP RP originator identifier\n") +{ + char xpath_value[XPATH_MAXLEN]; + + snprintf(xpath_value, sizeof(xpath_value), "./msdp/originator-id"); + if (no) + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, originator_id_str); + + return nb_cli_apply_changes(vty, NULL); +} + static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) { @@ -8954,6 +9028,9 @@ void pim_cmd_init(void) install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd); install_element(PIM_NODE, &msdp_log_neighbor_changes_cmd); install_element(PIM_NODE, &msdp_log_sa_changes_cmd); + install_element(PIM_NODE, &msdp_shutdown_cmd); + install_element(PIM_NODE, &msdp_peer_sa_limit_cmd); + install_element(PIM_NODE, &msdp_originator_id_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd); @@ -8999,6 +9076,7 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_no_ip_pim_hello_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_boundary_oil_cmd); install_element(INTERFACE_NODE, &interface_no_ip_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ip_pim_boundary_acl_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_query_generate_cmd); // Static mroutes NEB diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 20e3ba184ba8..bd7164c9b972 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -38,6 +38,7 @@ #include "pim_igmp_join.h" #include "pim_vxlan.h" #include "pim_tib.h" +#include "pim_util.h" #include "pim6_mld.h" @@ -215,7 +216,6 @@ void pim_if_delete(struct interface *ifp) if (pim_ifp->bfd_config.profile) XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile); - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = NULL; @@ -1258,6 +1258,14 @@ static int gm_join_sock(const char *ifname, ifindex_t ifindex, { int join_fd; + if (pim_is_group_filtered(pim_ifp, &group_addr, &source_addr)) { + if (PIM_DEBUG_GM_EVENTS) { + zlog_debug("%s: join failed for (S,G)=(%pPAs,%pPAs) due to multicast boundary filtering", + __func__, &source_addr, &group_addr); + } + return -1; + } + pim_ifp->igmp_ifstat_joins_sent++; join_fd = pim_socket_raw(IPPROTO_GM); @@ -1464,8 +1472,7 @@ static void pim_if_gm_join_del_all(struct interface *ifp) return; for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) - pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr, - GM_JOIN_STATIC); + pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr, ij->join_type); } ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr, diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 95bac084d2bb..90a81a21d026 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -133,8 +133,10 @@ struct pim_interface { uint32_t pim_dr_priority; /* config */ int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ - /* boundary prefix-list */ - char *boundary_oil_plist; + /* boundary prefix-list (group) */ + struct prefix_list *boundary_oil_plist; + /* boundary access-list (source and group) */ + struct access_list *boundary_acl; /* Turn on Active-Active for this interface */ bool activeactive; diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 1ba9bc45a20b..12f424248f9f 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -666,7 +666,7 @@ static int igmp_v1_recv_report(struct gm_sock *igmp, struct in_addr from, memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); - if (pim_is_group_filtered(ifp->info, &group_addr)) + if (pim_is_group_filtered(ifp->info, &group_addr, NULL)) return -1; /* non-existent group is created as INCLUDE {empty} */ diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c index 944dffdc3389..720a4944fef5 100644 --- a/pimd/pim_igmpv2.c +++ b/pimd/pim_igmpv2.c @@ -134,6 +134,9 @@ int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from, ifp->name, group_str); } + if (pim_is_group_filtered(pim_ifp, &group_addr, NULL)) + return -1; + /* * RFC 4604 * section 2.2.1 diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 2c5ad4d44b1b..7348d8130f2c 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -9,6 +9,8 @@ #include "memory.h" #include "if.h" #include "lib_errors.h" +#include "plist.h" +#include "plist_int.h" #include "pimd.h" #include "pim_instance.h" @@ -507,6 +509,8 @@ static void allow(struct gm_sock *igmp, struct in_addr from, struct in_addr *src_addr; src_addr = sources + i; + if (pim_is_group_filtered(igmp->interface->info, &group_addr, src_addr)) + continue; source = igmp_get_source_by_addr(group, *src_addr, NULL); if (!source) @@ -646,7 +650,7 @@ void igmpv3_report_isex(struct gm_sock *igmp, struct in_addr from, on_trace(__func__, ifp, from, group_addr, num_sources, sources); - if (pim_is_group_filtered(ifp->info, &group_addr)) + if (pim_is_group_filtered(ifp->info, &group_addr, NULL)) return; /* non-existent group is created as INCLUDE {empty} */ @@ -1809,12 +1813,14 @@ static bool igmp_pkt_grp_addr_ok(struct interface *ifp, const char *from_str, pim_ifp = ifp->info; /* determine filtering status for group */ - if (pim_is_group_filtered(pim_ifp, &grp)) { + if (pim_is_group_filtered(pim_ifp, &grp, NULL)) { if (PIM_DEBUG_GM_PACKETS) { - zlog_debug( - "Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s", - &grp.s_addr, from_str, ifp->name, - pim_ifp->boundary_oil_plist); + zlog_debug("Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s or access-list %s", + &grp.s_addr, from_str, ifp->name, + (pim_ifp->boundary_oil_plist ? pim_ifp->boundary_oil_plist->name + : "(not found)"), + (pim_ifp->boundary_acl ? pim_ifp->boundary_acl->name + : "(not found)")); } return false; } @@ -1943,11 +1949,9 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from, sizeof(struct in_addr)); if (PIM_DEBUG_GM_PACKETS) { - zlog_debug( - " Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%pI4", - from_str, ifp->name, i, rec_type, - rec_auxdatalen, rec_num_sources, - &rec_group); + zlog_debug(" Recv IGMP report v3 (type %d) from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%pI4", + rec_type, from_str, ifp->name, i, rec_type, rec_auxdatalen, + rec_num_sources, &rec_group); } /* Scan sources */ diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 4e4e5a6ce8f9..5649e49835f9 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -53,7 +53,9 @@ static void pim_instance_terminate(struct pim_instance *pim) pim_oil_terminate(pim); +#if PIM_IPV == 4 pim_msdp_exit(pim); +#endif /* PIM_IPV == 4 */ close(pim->reg_sock); @@ -91,7 +93,9 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) pim->spt.switchover = PIM_SPT_IMMEDIATE; pim->spt.plist = NULL; +#if PIM_IPV == 4 pim_msdp_init(pim, router->master); +#endif /* PIM_IPV == 4 */ pim_vxlan_init(pim); snprintf(hash_name, sizeof(hash_name), "PIM %s RPF Hash", vrf->name); @@ -126,11 +130,6 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) if (pim->reg_sock < 0) assert(0); - /* MSDP global timer defaults. */ - pim->msdp.hold_time = PIM_MSDP_PEER_HOLD_TIME; - pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME; - pim->msdp.connection_retry = PIM_MSDP_PEER_CONNECT_RETRY_TIME; - #if PIM_IPV == 4 pim_autorp_init(pim); #endif diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index dab7ed269828..93acb5e9fd6b 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -150,7 +150,9 @@ struct pim_instance { struct rb_pim_oil_head channel_oil_head; +#if PIM_IPV == 4 struct pim_msdp msdp; +#endif /* PIM_IPV == 4 */ struct pim_vxlan_instance vxlan; struct pim_autorp *autorp; @@ -225,7 +227,4 @@ extern struct pim_router *router; struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id); -extern bool pim_msdp_log_neighbor_events(const struct pim_instance *pim); -extern bool pim_msdp_log_sa_events(const struct pim_instance *pim); - #endif diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 2feafabb4dff..7796e8b95169 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -245,7 +245,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, uint16_t msg_num_pruned_sources; int source; struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL; - bool filtered = false; + bool group_filtered = false; memset(&sg, 0, sizeof(sg)); addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf); @@ -275,7 +275,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, &src_addr, ifp->name); /* boundary check */ - filtered = pim_is_group_filtered(pim_ifp, &sg.grp); + group_filtered = pim_is_group_filtered(pim_ifp, &sg.grp, NULL); /* Scan joined sources */ for (source = 0; source < msg_num_joined_sources; ++source) { @@ -287,8 +287,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, buf += addr_offset; - /* if we are filtering this group, skip the join */ - if (filtered) + /* if we are filtering this group or (S,G), skip the join */ + if (group_filtered || pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) continue; recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr, @@ -312,10 +312,6 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, buf += addr_offset; - /* if we are filtering this group, skip the prune */ - if (filtered) - continue; - recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr, &sg, msg_source_flags); /* @@ -361,7 +357,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, } } } - if (starg_ch && !filtered) + if (starg_ch && !group_filtered) pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0); starg_ch = NULL; } /* scan groups */ diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 9d290c3c6f2b..96eb5f48f523 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -35,6 +35,7 @@ #include "pim_sock.h" #include "pim_vxlan.h" #include "pim_msg.h" +#include "pim_util.h" static void mroute_read_on(struct pim_instance *pim); static int pim_upstream_mroute_update(struct channel_oil *c_oil, @@ -271,7 +272,9 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg) *oil_incoming_vif(up->channel_oil) >= MAXVIFS) { pim_upstream_mroute_iif_update(up->channel_oil, __func__); } - pim_register_join(up); + + if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) + pim_register_join(up); /* if we have receiver, inherit from parent */ pim_upstream_inherited_olist_decide(pim_ifp->pim, up); @@ -632,7 +635,8 @@ int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf, pim_upstream_keep_alive_timer_start( up, pim_ifp->pim->keep_alive_time); up->channel_oil->cc.pktcnt++; - pim_register_join(up); + if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) + pim_register_join(up); pim_upstream_inherited_olist(pim_ifp->pim, up); if (!up->channel_oil->installed) pim_upstream_mroute_add(up->channel_oil, __func__); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index a536ab6fe031..b428520b894a 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -31,8 +31,6 @@ #include "pim_msdp_packet.h" #include "pim_msdp_socket.h" -// struct pim_msdp pim_msdp, *msdp = &pim_msdp; - static void pim_msdp_peer_listen(struct pim_msdp_peer *mp); static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start); static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start); @@ -46,6 +44,26 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa, static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2); static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr); +void pim_msdp_originator_id(struct pim_instance *pim, const struct prefix *group, + struct in_addr *originator_id) +{ + struct rp_info *rp_info; + + originator_id->s_addr = INADDR_ANY; + + /* Originator ID was configured, use it. */ + if (pim->msdp.originator_id.s_addr != INADDR_ANY) { + *originator_id = pim->msdp.originator_id; + return; + } + + rp_info = pim_rp_find_match_group(pim, group); + if (rp_info) { + *originator_id = rp_info->rp.rpf_addr; + return; + } +} + /************************ SA cache management ******************************/ /* RFC-3618:Sec-5.1 - global active source advertisement timer */ static void pim_msdp_sa_adv_timer_cb(struct event *t) @@ -356,9 +374,17 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp) { struct pim_msdp_sa *sa; - struct rp_info *rp_info; struct prefix grp; + /* Check peer SA limit. */ + if (mp && mp->sa_limit && mp->sa_cnt >= mp->sa_limit) { + if (pim_msdp_log_sa_events(pim)) + zlog_debug("MSDP peer %pI4 reject SA (%pI4, %pI4): SA limit %u of %u", + &mp->peer, &sg->src, &sg->grp, mp->sa_cnt, mp->sa_limit); + + return; + } + sa = pim_msdp_sa_add(pim, sg, rp); if (!sa) { return; @@ -388,12 +414,7 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, /* send an immediate SA update to peers */ pim_addr_to_prefix(&grp, sa->sg.grp); - rp_info = pim_rp_find_match_group(pim, &grp); - if (rp_info) { - sa->rp = rp_info->rp.rpf_addr; - } else { - sa->rp = pim->msdp.originator_id; - } + pim_msdp_originator_id(pim, &grp, &sa->rp); pim_msdp_pkt_sa_tx_one(sa); } sa->flags &= ~PIM_MSDP_SAF_STALE; @@ -734,6 +755,10 @@ static void pim_msdp_peer_state_chg_log(struct pim_msdp_peer *mp) * a tcp connection will be made */ static void pim_msdp_peer_connect(struct pim_msdp_peer *mp) { + /* Stop here if we are shutdown. */ + if (mp->pim->msdp.shutdown) + return; + mp->state = PIM_MSDP_CONNECTING; if (pim_msdp_log_neighbor_events(mp->pim)) pim_msdp_peer_state_chg_log(mp); @@ -744,6 +769,10 @@ static void pim_msdp_peer_connect(struct pim_msdp_peer *mp) /* 11.2.A3: passive peer - just listen for connections */ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp) { + /* Stop here if we are shutdown. */ + if (mp->pim->msdp.shutdown) + return; + mp->state = PIM_MSDP_LISTEN; if (pim_msdp_log_neighbor_events(mp->pim)) pim_msdp_peer_state_chg_log(mp); @@ -998,8 +1027,6 @@ struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim, mp->peer = *peer; pim_inet4_dump("", mp->peer, mp->key_str, sizeof(mp->key_str)); mp->local = *local; - /* XXX: originator_id setting needs to move to the mesh group */ - pim->msdp.originator_id = *local; if (mesh_group_name) mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name); @@ -1255,10 +1282,21 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty) char src_str[INET_ADDRSTRLEN]; int count = 0; + if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME || + pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME || + pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { + vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, pim->msdp.keep_alive); + if (pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) + vty_out(vty, " %u", pim->msdp.connection_retry); + vty_out(vty, "\n"); + } + if (pim_msdp_log_neighbor_events(pim)) vty_out(vty, " msdp log neighbor-events\n"); if (pim_msdp_log_sa_events(pim)) vty_out(vty, " msdp log sa-events\n"); + if (pim->msdp.shutdown) + vty_out(vty, " msdp shutdown\n"); if (SLIST_EMPTY(&pim->msdp.mglist)) return count; @@ -1308,9 +1346,18 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) vty_out(vty, " msdp peer %pI4 sa-filter %s out\n", &mp->peer, mp->acl_out); + if (mp->sa_limit) + vty_out(vty, " msdp peer %pI4 sa-limit %u\n", &mp->peer, mp->sa_limit); + written = true; } + if (pim->msdp.originator_id.s_addr != INADDR_ANY) + vty_out(vty, " msdp originator-id %pI4\n", &pim->msdp.originator_id); + + if (pim->msdp.shutdown) + vty_out(vty, " msdp shutdown\n"); + return written; } @@ -1350,6 +1397,11 @@ void pim_msdp_init(struct pim_instance *pim, struct event_loop *master) pim->msdp.sa_list = list_new(); pim->msdp.sa_list->del = (void (*)(void *))pim_msdp_sa_free; pim->msdp.sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp; + + /* MSDP global timer defaults. */ + pim->msdp.hold_time = PIM_MSDP_PEER_HOLD_TIME; + pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME; + pim->msdp.connection_retry = PIM_MSDP_PEER_CONNECT_RETRY_TIME; } /* counterpart to MSDP init; XXX: unused currently */ @@ -1431,3 +1483,61 @@ struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim, return mbr; } + +/* MSDP on RP needs to know if a source is registerable to this RP */ +static void pim_upstream_msdp_reg_timer(struct event *t) +{ + struct pim_upstream *up = EVENT_ARG(t); + struct pim_instance *pim = up->channel_oil->pim; + + /* source is no longer active - pull the SA from MSDP's cache */ + pim_msdp_sa_local_del(pim, &up->sg); +} + +void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) +{ + EVENT_OFF(up->t_msdp_reg_timer); + event_add_timer(router->master, pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD, + &up->t_msdp_reg_timer); + + pim_msdp_sa_local_update(up); +} + +void pim_msdp_shutdown(struct pim_instance *pim, bool state) +{ + struct pim_msdp_peer *peer; + struct listnode *node; + + /* Same value nothing to do. */ + if (pim->msdp.shutdown == state) + return; + + if (state) { + pim->msdp.shutdown = true; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, peer)) { + /* Stop the tcp connection and shutdown all timers */ + pim_msdp_peer_stop_tcp_conn(peer, true); + + /* Stop listening socket if any. */ + event_cancel(&peer->auth_listen_ev); + if (peer->auth_listen_sock != -1) + close(peer->auth_listen_sock); + + /* Disable and remove listener flag. */ + UNSET_FLAG(pim->msdp.flags, PIM_MSDPF_ENABLE | PIM_MSDPF_LISTENER); + } + } else { + pim->msdp.shutdown = false; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, peer)) { + /* Start connection again. */ + if (PIM_MSDP_PEER_IS_LISTENER(peer)) + pim_msdp_peer_listen(peer); + else + pim_msdp_peer_connect(peer); + + SET_FLAG(pim->msdp.flags, PIM_MSDPF_ENABLE); + } + } +} diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 0a7c74e438e7..4edb6e6166ec 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -152,6 +152,9 @@ struct pim_msdp_peer { char *acl_in; /** SA output access list name. */ char *acl_out; + + /** SA maximum amount. */ + uint32_t sa_limit; }; struct pim_msdp_mg_mbr { @@ -216,6 +219,9 @@ struct pim_msdp { uint32_t keep_alive; /** MSDP global connection retry period. */ uint32_t connection_retry; + + /** MSDP operation state. */ + bool shutdown; }; #define PIM_MSDP_PEER_READ_ON(mp) \ @@ -229,8 +235,6 @@ struct pim_msdp { #define PIM_MSDP_PEER_READ_OFF(mp) event_cancel(&mp->t_read) #define PIM_MSDP_PEER_WRITE_OFF(mp) event_cancel(&mp->t_write) -#if PIM_IPV != 6 -// struct pim_msdp *msdp; struct pim_instance; void pim_msdp_init(struct pim_instance *pim, struct event_loop *master); void pim_msdp_exit(struct pim_instance *pim); @@ -257,6 +261,8 @@ void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg); enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim, const char *mesh_group_name); +extern void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up); + /** * Allocates a new mesh group data structure under PIM instance. */ @@ -327,49 +333,25 @@ void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, */ void pim_msdp_peer_restart(struct pim_msdp_peer *mp); -#else /* PIM_IPV == 6 */ -static inline void pim_msdp_init(struct pim_instance *pim, - struct event_loop *master) -{ -} - -static inline void pim_msdp_exit(struct pim_instance *pim) -{ -} - -static inline void pim_msdp_i_am_rp_changed(struct pim_instance *pim) -{ -} - -static inline void pim_msdp_up_join_state_changed(struct pim_instance *pim, - struct pim_upstream *xg_up) -{ -} - -static inline void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg) -{ -} - -static inline void pim_msdp_sa_local_update(struct pim_upstream *up) -{ -} - -static inline void pim_msdp_sa_local_del(struct pim_instance *pim, - pim_sgaddr *sg) -{ -} - -static inline int pim_msdp_config_write(struct pim_instance *pim, - struct vty *vty) -{ - return 0; -} - -static inline bool pim_msdp_peer_config_write(struct vty *vty, - struct pim_instance *pim) -{ - return false; -} -#endif /* PIM_IPV == 6 */ +/** + * Toggle MSDP functionality administrative state. + * + * \param pim PIM instance we want to shutdown. + * \param state shutdown state. + */ +void pim_msdp_shutdown(struct pim_instance *pim, bool state); + +/** + * Get the configured originator ID for the SA RP field or the RP for the group. + * + * \param[in] pim PIM instance that MSDP connection belongs to. + * \param[in] group Multicast group. + * \param[out] originator_id Originator output value. + */ +void pim_msdp_originator_id(struct pim_instance *pim, const struct prefix *group, + struct in_addr *originator_id); + +extern bool pim_msdp_log_neighbor_events(const struct pim_instance *pim); +extern bool pim_msdp_log_sa_events(const struct pim_instance *pim); #endif diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index f66a941ee312..8c821cb5e548 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -367,53 +367,6 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa) stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr); } -static bool msdp_cisco_match(const struct filter *filter, - const struct in_addr *source, - const struct in_addr *group) -{ - const struct filter_cisco *cfilter = &filter->u.cfilter; - uint32_t source_addr; - uint32_t group_addr; - - group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; - - if (cfilter->extended) { - source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; - if (group_addr == cfilter->mask.s_addr && - source_addr == cfilter->addr.s_addr) - return true; - } else if (group_addr == cfilter->addr.s_addr) - return true; - - return false; -} - -static enum filter_type msdp_access_list_apply(struct access_list *access, - const struct in_addr *source, - const struct in_addr *group) -{ - struct filter *filter; - struct prefix group_prefix; - - if (access == NULL) - return FILTER_DENY; - - for (filter = access->head; filter; filter = filter->next) { - if (filter->cisco) { - if (msdp_cisco_match(filter, source, group)) - return filter->type; - } else { - group_prefix.family = AF_INET; - group_prefix.prefixlen = IPV4_MAX_BITLEN; - group_prefix.u.prefix4.s_addr = group->s_addr; - if (access_list_apply(access, &group_prefix)) - return filter->type; - } - } - - return FILTER_DENY; -} - bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, const struct pim_msdp_sa *sa) { @@ -425,7 +378,7 @@ bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, /* Find access list and test it. */ acl = access_list_lookup(AFI_IP, mp->acl_out); - if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) + if (pim_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) return true; return false; @@ -456,7 +409,6 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, { struct listnode *sanode; struct pim_msdp_sa *sa; - struct rp_info *rp_info; struct prefix group_all; struct in_addr rp; int sa_count; @@ -467,14 +419,8 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, zlog_debug(" sa gen %d", local_cnt); } - rp = pim->msdp.originator_id; - if (pim_get_all_mcast_group(&group_all)) { - rp_info = pim_rp_find_match_group(pim, &group_all); - if (rp_info) { - rp = rp_info->rp.rpf_addr; - } - } - + pim_get_all_mcast_group(&group_all); + pim_msdp_originator_id(pim, &group_all, &rp); local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, rp); for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { @@ -504,8 +450,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, zlog_debug(" sa gen for remainder %d", local_cnt); } - local_cnt = pim_msdp_pkt_sa_fill_hdr( - pim, local_cnt, rp); + local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, rp); } } @@ -641,7 +586,7 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) /* Filter incoming SA with configured access list. */ if (mp->acl_in) { acl = access_list_lookup(AFI_IP, mp->acl_in); - if (msdp_access_list_apply(acl, &sg.src, &sg.grp) == FILTER_DENY) { + if (pim_access_list_apply(acl, &sg.src, &sg.grp) == FILTER_DENY) { if (pim_msdp_log_sa_events(mp->pim)) zlog_info("MSDP peer %pI4 filter SA in (%pI4, %pI4)", &mp->peer, &sg.src, &sg.grp); diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index c5a9c7f05562..6b6c0e877949 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -141,6 +141,19 @@ const struct frr_yang_module_info frr_pim_info = { .modify = pim_msdp_log_sa_events_modify, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/originator-id", + .cbs = { + .modify = pim_msdp_originator_id_modify, + .destroy = pim_msdp_originator_id_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/shutdown", + .cbs = { + .modify = pim_msdp_shutdown_modify, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups", .cbs = { @@ -202,6 +215,13 @@ const struct frr_yang_module_info frr_pim_info = { .destroy = pim_msdp_peer_authentication_key_destroy, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-limit", + .cbs = { + .modify = pim_msdp_peer_sa_limit_modify, + .destroy = pim_msdp_peer_sa_limit_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", .cbs = { @@ -346,6 +366,13 @@ const struct frr_yang_module_info frr_pim_info = { .destroy = lib_interface_pim_address_family_multicast_boundary_oil_destroy, } }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-acl", + .cbs = { + .modify = lib_interface_pim_address_family_multicast_boundary_acl_modify, + .destroy = lib_interface_pim_address_family_multicast_boundary_acl_destroy, + } + }, { .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/mroute", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 8412ef4a6e5a..c50fdb2000d8 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -56,6 +56,9 @@ int pim_msdp_keep_alive_modify(struct nb_cb_modify_args *args); int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args); int pim_msdp_log_neighbor_events_modify(struct nb_cb_modify_args *args); int pim_msdp_log_sa_events_modify(struct nb_cb_modify_args *args); +int pim_msdp_originator_id_modify(struct nb_cb_modify_args *args); +int pim_msdp_originator_id_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_shutdown_modify(struct nb_cb_modify_args *args); int pim_msdp_mesh_group_create(struct nb_cb_create_args *args); int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args); int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args); @@ -75,6 +78,8 @@ int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args); int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args); int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_sa_limit_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_limit_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( @@ -139,6 +144,8 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( struct nb_cb_modify_args *args); int lib_interface_pim_address_family_multicast_boundary_oil_destroy( struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_multicast_boundary_acl_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_multicast_boundary_acl_destroy(struct nb_cb_destroy_args *args); int lib_interface_pim_address_family_mroute_create( struct nb_cb_create_args *args); int lib_interface_pim_address_family_mroute_destroy( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index e594a150fd2f..cf9ae21cc067 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1008,6 +1008,40 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss return NB_OK; } +pim6_msdp_err(pim_msdp_hold_time_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_keep_alive_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_connection_retry_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_mesh_group_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_mesh_group_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_mesh_group_source_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_mesh_group_source_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_mesh_group_members_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_mesh_group_members_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_in_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_in_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_out_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_out_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_peer_sa_limit_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_sa_limit_destroy, nb_cb_destroy_args); +pim6_msdp_err( + routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, + nb_cb_modify_args); +pim6_msdp_err( + routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy, + nb_cb_destroy_args); +pim6_msdp_err( + routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, + nb_cb_create_args); +pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_log_neighbor_events_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_log_sa_events_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_originator_id_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_originator_id_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_shutdown_modify, nb_cb_modify_args); + +#if PIM_IPV != 6 /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/hold-time @@ -1081,25 +1115,6 @@ int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args) return NB_OK; } -pim6_msdp_err(pim_msdp_mesh_group_destroy, nb_cb_destroy_args); -pim6_msdp_err(pim_msdp_mesh_group_create, nb_cb_create_args); -pim6_msdp_err(pim_msdp_mesh_group_source_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_mesh_group_source_destroy, nb_cb_destroy_args); -pim6_msdp_err(pim_msdp_mesh_group_members_create, nb_cb_create_args); -pim6_msdp_err(pim_msdp_mesh_group_members_destroy, nb_cb_destroy_args); -pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, - nb_cb_modify_args); -pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy, - nb_cb_destroy_args); -pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, - nb_cb_create_args); -pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); -pim6_msdp_err(pim_msdp_log_neighbor_events_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_log_sa_events_modify, nb_cb_modify_args); - -#if PIM_IPV != 6 /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/log-neighbor-events @@ -1158,6 +1173,76 @@ int pim_msdp_log_sa_events_modify(struct nb_cb_modify_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/originator-id + */ +int pim_msdp_originator_id_modify(struct nb_cb_modify_args *args) +{ + struct pim_instance *pim; + struct vrf *vrf; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ipv4(&pim->msdp.originator_id, args->dnode, NULL); + break; + } + + return NB_OK; +} + +int pim_msdp_originator_id_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_instance *pim; + struct vrf *vrf; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->msdp.originator_id.s_addr = INADDR_ANY; + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/shutdown + */ +int pim_msdp_shutdown_modify(struct nb_cb_modify_args *args) +{ + struct pim_instance *pim; + struct vrf *vrf; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim_msdp_shutdown(pim, yang_dnode_get_bool(args->dnode, NULL)); + break; + } + + return NB_OK; +} + /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups @@ -1462,7 +1547,6 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms return NB_OK; } -#endif /* PIM_IPV != 6 */ /* * XPath: @@ -1552,6 +1636,49 @@ int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-limit + */ +int pim_msdp_peer_sa_limit_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + mp->sa_limit = yang_dnode_get_uint32(args->dnode, NULL); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_limit_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + mp->sa_limit = 0; + break; + } + + return NB_OK; +} +#endif /* PIM_IPV != 6 */ + /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag */ @@ -2363,7 +2490,6 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( { struct interface *ifp; struct pim_interface *pim_ifp; - const char *plist; const struct lyd_node *if_dnode; switch (args->event) { @@ -2371,7 +2497,12 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( if_dnode = yang_dnode_get_parent(args->dnode, "interface"); if (!is_pim_interface(if_dnode)) { snprintf(args->errmsg, args->errmsg_len, - "Pim not enabled on this interface"); + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + if (!prefix_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL))) { + snprintf(args->errmsg, args->errmsg_len, + "%% Specified prefix-list not found"); return NB_ERR_VALIDATION; } break; @@ -2381,13 +2512,8 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - plist = yang_dnode_get_string(args->dnode, NULL); - - if (pim_ifp->boundary_oil_plist) - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); - pim_ifp->boundary_oil_plist = - XSTRDUP(MTYPE_PIM_INTERFACE, plist); + prefix_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL)); break; } @@ -2417,8 +2543,72 @@ int lib_interface_pim_address_family_multicast_boundary_oil_destroy( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - if (pim_ifp->boundary_oil_plist) - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); + pim_ifp->boundary_oil_plist = NULL; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-acl + */ +int lib_interface_pim_address_family_multicast_boundary_acl_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + if (!access_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL))) { + snprintf(args->errmsg, args->errmsg_len, + "%% Specified access-list not found"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->boundary_acl = + access_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int lib_interface_pim_address_family_multicast_boundary_acl_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->boundary_acl = NULL; break; } @@ -2635,13 +2825,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp else if (yang_dnode_get(args->dnode, "prefix-list")) { plist = yang_dnode_get_string(args->dnode, "./prefix-list"); - if (!pim_get_all_mcast_group(&group)) { - flog_err( - EC_LIB_DEVELOPMENT, - "Unable to convert 224.0.0.0/4 to prefix"); - return NB_ERR_INCONSISTENCY; - } - + pim_get_all_mcast_group(&group); result = pim_no_rp_cmd_worker(pim, rp_addr, group, plist, args->errmsg, args->errmsg_len); @@ -2733,11 +2917,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp pim = vrf->info; plist = yang_dnode_get_string(args->dnode, NULL); yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); - if (!pim_get_all_mcast_group(&group)) { - flog_err(EC_LIB_DEVELOPMENT, - "Unable to convert 224.0.0.0/4 to prefix"); - return NB_ERR_INCONSISTENCY; - } + pim_get_all_mcast_group(&group); return pim_rp_cmd_worker(pim, rp_addr, group, plist, args->errmsg, args->errmsg_len); } @@ -2764,11 +2944,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp pim = vrf->info; yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); plist = yang_dnode_get_string(args->dnode, NULL); - if (!pim_get_all_mcast_group(&group)) { - flog_err(EC_LIB_DEVELOPMENT, - "Unable to convert 224.0.0.0/4 to prefix"); - return NB_ERR_INCONSISTENCY; - } + pim_get_all_mcast_group(&group); return pim_no_rp_cmd_worker(pim, rp_addr, group, plist, args->errmsg, args->errmsg_len); break; diff --git a/pimd/pim_register.c b/pimd/pim_register.c index b149b5a2a97c..f776a59b7fd8 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -709,7 +709,10 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr, // inherited_olist(S,G,rpt) // This is taken care of by the kernel for us } + +#if PIM_IPV == 4 pim_upstream_msdp_reg_timer_start(upstream); +#endif /* PIM_IPV == 4 */ } else { if (PIM_DEBUG_PIM_REG) { if (!i_am_rp) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index e6de991a1435..44cc00622668 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -97,14 +97,7 @@ void pim_rp_init(struct pim_instance *pim) rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); - if (!pim_get_all_mcast_group(&rp_info->group)) { - flog_err(EC_LIB_DEVELOPMENT, - "Unable to convert all-multicast prefix"); - list_delete(&pim->rp_list); - route_table_finish(pim->rp_table); - XFREE(MTYPE_PIM_RP, rp_info); - return; - } + pim_get_all_mcast_group(&rp_info->group); rp_info->rp.rpf_addr = PIMADDR_ANY; listnode_add(pim->rp_list, rp_info); @@ -343,7 +336,9 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, */ void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim) { +#if PIM_IPV == 4 pim_msdp_i_am_rp_changed(pim); +#endif /* PIM_IPV == 4 */ pim_upstream_reeval_use_rpt(pim); } @@ -522,11 +517,7 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist); } else { - - if (!pim_get_all_mcast_group(&group_all)) { - XFREE(MTYPE_PIM_RP, rp_info); - return PIM_GROUP_BAD_ADDRESS; - } + pim_get_all_mcast_group(&group_all); rp_all = pim_rp_find_match_group(pim, &group_all); /* @@ -706,9 +697,10 @@ void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr, struct prefix group; int result; - if (group_range == NULL) - result = pim_get_all_mcast_group(&group); - else + if (group_range == NULL) { + result = 0; + pim_get_all_mcast_group(&group); + } else result = str2prefix(group_range, &group); if (!result) { @@ -787,9 +779,7 @@ int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, &nht_p); pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info); - if (!pim_get_all_mcast_group(&g_all)) - return PIM_RP_BAD_ADDRESS; - + pim_get_all_mcast_group(&g_all); rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { @@ -1030,7 +1020,9 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp) } if (i_am_rp_changed) { +#if PIM_IPV == 4 pim_msdp_i_am_rp_changed(pim); +#endif /* PIM_IPV == 4 */ pim_upstream_reeval_use_rpt(pim); } } @@ -1072,7 +1064,9 @@ void pim_i_am_rp_re_evaluate(struct pim_instance *pim) } if (i_am_rp_changed) { +#if PIM_IPV == 4 pim_msdp_i_am_rp_changed(pim); +#endif /* PIM_IPV == 4 */ pim_upstream_reeval_use_rpt(pim); } } diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c index e21793b8caaf..2786ba440d15 100644 --- a/pimd/pim_tib.c +++ b/pimd/pim_tib.c @@ -115,13 +115,8 @@ bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, return false; } - if (!*oilp) { + if (!*oilp) *oilp = tib_sg_oil_setup(pim, sg, oif); -#if PIM_IPV == 6 - if (pim_embedded_rp_is_embedded(&sg.grp)) - (*oilp)->oil_ref_count--; -#endif /* PIM_IPV == 6 */ - } if (!*oilp) return false; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 7417f311377f..8aa61b687dbc 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -178,7 +178,9 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, { struct listnode *node, *nnode; struct pim_ifchannel *ch; +#if PIM_IPV == 4 bool notify_msdp = false; +#endif /* PIM_IPV == 4 */ if (PIM_DEBUG_PIM_TRACE) zlog_debug( @@ -206,12 +208,14 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, if (up->join_state == PIM_UPSTREAM_JOINED) { pim_jp_agg_single_upstream_send(&up->rpf, up, 0); +#if PIM_IPV == 4 if (pim_addr_is_any(up->sg.src)) { /* if a (*, G) entry in the joined state is being * deleted we * need to notify MSDP */ notify_msdp = true; } +#endif /* PIM_IPV == 4 */ } join_timer_stop(up); @@ -221,7 +225,9 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, if (!pim_addr_is_any(up->sg.src)) { if (pim->upstream_sg_wheel) wheel_remove_item(pim->upstream_sg_wheel, up); +#if PIM_IPV == 4 notify_msdp = true; +#endif /* PIM_IPV == 4 */ } pim_mroute_del(up->channel_oil, __func__); @@ -241,9 +247,11 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, rb_pim_upstream_del(&pim->upstream_head, up); +#if PIM_IPV == 4 if (notify_msdp) { pim_msdp_up_del(pim, &up->sg); } +#endif /* PIM_IPV == 4 */ /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT * and assign up->upstream_addr as INADDR_ANY. @@ -723,7 +731,9 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, if (old_state != PIM_UPSTREAM_JOINED) { int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags); +#if PIM_IPV == 4 pim_msdp_up_join_state_changed(pim, up); +#endif /* PIM_IPV == 4 */ if (pim_upstream_could_register(up)) { PIM_UPSTREAM_FLAG_SET_FHR(up->flags); if (!old_fhr @@ -753,8 +763,10 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, if (!pim_addr_is_any(up->sg.src)) up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; +#if PIM_IPV == 4 if (old_state == PIM_UPSTREAM_JOINED) pim_msdp_up_join_state_changed(pim, up); +#endif /* PIM_IPV == 4 */ if (old_state != new_state) { old_use_rpt = @@ -1424,8 +1436,10 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc( */ } +#if PIM_IPV == 4 /* source is no longer active - pull the SA from MSDP's cache */ pim_msdp_sa_local_del(pim, &up->sg); +#endif /* PIM_IPV == 4 */ /* JoinDesired can change when KAT is started or stopped */ pim_upstream_update_join_desired(pim, up); @@ -1493,32 +1507,15 @@ void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time) event_add_timer(router->master, pim_upstream_keep_alive_timer, up, time, &up->t_ka_timer); +#if PIM_IPV == 4 /* any time keepalive is started against a SG we will have to * re-evaluate our active source database */ pim_msdp_sa_local_update(up); +#endif /* PIM_IPV == 4 */ /* JoinDesired can change when KAT is started or stopped */ pim_upstream_update_join_desired(up->pim, up); } -/* MSDP on RP needs to know if a source is registerable to this RP */ -static void pim_upstream_msdp_reg_timer(struct event *t) -{ - struct pim_upstream *up = EVENT_ARG(t); - struct pim_instance *pim = up->channel_oil->pim; - - /* source is no longer active - pull the SA from MSDP's cache */ - pim_msdp_sa_local_del(pim, &up->sg); -} - -void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) -{ - EVENT_OFF(up->t_msdp_reg_timer); - event_add_timer(router->master, pim_upstream_msdp_reg_timer, up, - PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer); - - pim_msdp_sa_local_update(up); -} - /* * 4.2.1 Last-Hop Switchover to the SPT * diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 8b4a35be398c..1d4b2128a8f7 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -350,7 +350,6 @@ int pim_upstream_inherited_olist(struct pim_instance *pim, int pim_upstream_empty_inherited_olist(struct pim_upstream *up); void pim_upstream_find_new_rpf(struct pim_instance *pim); -void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up); void pim_upstream_init(struct pim_instance *pim); void pim_upstream_terminate(struct pim_instance *pim); diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 657e84ae50aa..0aea24058730 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -9,7 +9,10 @@ #include "log.h" #include "prefix.h" #include "plist.h" +#include "plist_int.h" +#include "pimd.h" +#include "pim_instance.h" #include "pim_util.h" /* @@ -126,34 +129,105 @@ int pim_is_group_224_4(struct in_addr group_addr) return prefix_match(&group_all, &group); } -bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp) +static bool pim_cisco_match(const struct filter *filter, const struct in_addr *source, + const struct in_addr *group) { - struct prefix grp_pfx; - struct prefix_list *pl; + const struct filter_cisco *cfilter = &filter->u.cfilter; + uint32_t source_addr; + uint32_t group_addr; - if (!pim_ifp->boundary_oil_plist) + group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; + + if (cfilter->extended) { + source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; + if (group_addr == cfilter->mask.s_addr && source_addr == cfilter->addr.s_addr) + return true; + } else if (group_addr == cfilter->addr.s_addr) + return true; + + return false; +} + +enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source, + const struct in_addr *group) +{ + struct filter *filter; + struct prefix group_prefix = {}; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) { + if (filter->cisco) { + if (pim_cisco_match(filter, source, group)) + return filter->type; + } + } + + group_prefix.family = AF_INET; + group_prefix.prefixlen = IPV4_MAX_BITLEN; + group_prefix.u.prefix4.s_addr = group->s_addr; + return access_list_apply(access, &group_prefix); +} + +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src) +{ + bool is_filtered = false; +#if PIM_IPV == 4 + struct prefix grp_pfx = {}; + pim_addr any_src = PIMADDR_ANY; + + if (!pim_ifp->boundary_oil_plist && !pim_ifp->boundary_acl) return false; pim_addr_to_prefix(&grp_pfx, *grp); - pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist); - return pl ? prefix_list_apply_ext(pl, NULL, &grp_pfx, true) == - PREFIX_DENY - : false; + /* Filter if either group or (S,G) are denied */ + if (pim_ifp->boundary_oil_plist) { + is_filtered = prefix_list_apply_ext(pim_ifp->boundary_oil_plist, NULL, &grp_pfx, + true) == PREFIX_DENY; + if (is_filtered && PIM_DEBUG_EVENTS) { + zlog_debug("Filtering group %pI4 per prefix-list %s", grp, + pim_ifp->boundary_oil_plist->name); + } + } + if (!is_filtered && pim_ifp->boundary_acl) { + /* If src not provided, set to "any" (*)? */ + if (!src) + src = &any_src; + /* S,G filtering using extended access-list syntax */ + is_filtered = pim_access_list_apply(pim_ifp->boundary_acl, src, grp) == FILTER_DENY; + if (is_filtered && PIM_DEBUG_EVENTS) { + if (pim_addr_is_any(*src)) { + zlog_debug("Filtering (S,G)=(*, %pI4) per access-list %s", grp, + pim_ifp->boundary_acl->name); + } else { + zlog_debug("Filtering (S,G)=(%pI4, %pI4) per access-list %s", src, + grp, pim_ifp->boundary_acl->name); + } + } + } +#endif + return is_filtered; } /* This function returns all multicast group */ -int pim_get_all_mcast_group(struct prefix *prefix) +void pim_get_all_mcast_group(struct prefix *prefix) { + memset(prefix, 0, sizeof(*prefix)); + #if PIM_IPV == 4 - if (!str2prefix("224.0.0.0/4", prefix)) - return 0; + /* Precomputed version of: `str2prefix("224.0.0.0/4", prefix);` */ + prefix->family = AF_INET; + prefix->prefixlen = 4; + prefix->u.prefix4.s_addr = htonl(0xe0000000); #else - if (!str2prefix("FF00::0/8", prefix)) - return 0; + /* Precomputed version of: `str2prefix("FF00::0/8", prefix)` */ + prefix->family = AF_INET6; + prefix->prefixlen = 8; + prefix->u.prefix6.s6_addr[0] = 0xff; #endif - return 1; } bool pim_addr_is_multicast(pim_addr addr) diff --git a/pimd/pim_util.h b/pimd/pim_util.h index c882fe4878a3..a3d944b82b96 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -10,6 +10,7 @@ #include #include +#include "lib/filter.h" #include "checksum.h" #include "pimd.h" @@ -22,7 +23,9 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size); int pim_is_group_224_0_0_0_24(struct in_addr group_addr); int pim_is_group_224_4(struct in_addr group_addr); -bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp); -int pim_get_all_mcast_group(struct prefix *prefix); +enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source, + const struct in_addr *group); +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src); +void pim_get_all_mcast_group(struct prefix *prefix); bool pim_addr_is_multicast(pim_addr addr); #endif /* PIM_UTIL_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 4d83593c17d2..fc9781b239c5 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -12,6 +12,8 @@ #include "vty.h" #include "vrf.h" #include "plist.h" +#include "plist_int.h" +#include "filter.h" #include "pimd.h" #include "pim_vty.h" @@ -178,8 +180,10 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) int writes = 0; struct pim_ssm *ssm = pim->ssm_info; +#if PIM_IPV == 4 writes += pim_msdp_peer_config_write(vty, pim); writes += pim_msdp_config_write(pim, vty); +#endif /* PIM_IPV == 4 */ if (!pim->send_v6_secondary) { vty_out(vty, " no send-v6-secondary\n"); @@ -271,17 +275,6 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) } } - if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME - || pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME - || pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { - vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, - pim->msdp.keep_alive); - if (pim->msdp.connection_retry - != PIM_MSDP_PEER_CONNECT_RETRY_TIME) - vty_out(vty, " %u", pim->msdp.connection_retry); - vty_out(vty, "\n"); - } - return writes; } @@ -342,6 +335,9 @@ static int gm_config_write(struct vty *vty, int writes, struct listnode *node; struct gm_join *ij; for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) { + if (ij->join_type == GM_JOIN_PROXY) + continue; + if (pim_addr_is_any(ij->source_addr)) vty_out(vty, " ip igmp join-group %pPAs\n", &ij->group_addr); @@ -412,6 +408,9 @@ static int gm_config_write(struct vty *vty, int writes, struct gm_join *ij; for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) { + if (ij->join_type == GM_JOIN_PROXY) + continue; + if (pim_addr_is_any(ij->source_addr)) vty_out(vty, " ipv6 mld join-group %pPAs\n", &ij->group_addr); @@ -486,7 +485,13 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp, /* boundary */ if (pim_ifp->boundary_oil_plist) { vty_out(vty, " " PIM_AF_NAME " multicast boundary oil %s\n", - pim_ifp->boundary_oil_plist); + pim_ifp->boundary_oil_plist->name); + ++writes; + } + + if (pim_ifp->boundary_acl) { + vty_out(vty, " " PIM_AF_NAME " multicast boundary %s\n", + pim_ifp->boundary_acl->name); ++writes; } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index ce4d85a2c848..f0ec3c6b6e82 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -426,7 +426,6 @@ static void pim_zebra_connected(struct zclient *zclient) static void pim_zebra_capabilities(struct zclient_capabilities *cap) { - router->mlag_role = cap->role; router->multipath = cap->ecmp; } diff --git a/pimd/pimd.c b/pimd/pimd.c index a390378a5abf..c1de58550a39 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -17,6 +17,7 @@ #include "vrf.h" #include "lib_errors.h" #include "bfd.h" +#include "filter.h" #include "pimd.h" #if PIM_IPV == 4 @@ -147,6 +148,7 @@ void pim_terminate(void) prefix_list_add_hook(NULL); prefix_list_delete_hook(NULL); prefix_list_reset(); + access_list_reset(); pim_vxlan_terminate(); pim_vrf_terminate(); diff --git a/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf index 1aab1d1372e8..0fe6f1c1c4ca 100644 --- a/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf @@ -5,9 +5,11 @@ router bgp 100 no bgp ebgp-requires-policy neighbor 172.16.1.1 remote-as 100 neighbor 172.16.1.1 timers 3 10 + neighbor 172.16.1.1 timers connect 1 neighbor 172.16.1.1 bfd profile fasttx neighbor 2001:db8:2::2 remote-as 200 neighbor 2001:db8:2::2 timers 3 10 + neighbor 2001:db8:2::2 timers connect 1 neighbor 2001:db8:2::2 ebgp-multihop 2 neighbor 2001:db8:2::2 bfd profile slowtx address-family ipv4 unicast diff --git a/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf index 65647b39e51d..d1168d93bc32 100644 --- a/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf @@ -2,6 +2,7 @@ router bgp 100 bgp router-id 10.254.254.3 neighbor 172.16.1.2 remote-as 100 neighbor 172.16.1.2 timers 3 10 + neighbor 172.16.1.2 timers connect 1 neighbor 172.16.1.2 bfd profile DOES_NOT_EXIST address-family ipv4 unicast redistribute connected diff --git a/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf index 12d68270f8af..1a8e6bb94dc7 100644 --- a/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf @@ -5,6 +5,7 @@ router bgp 200 no bgp ebgp-requires-policy neighbor 2001:db8:1::2 remote-as 100 neighbor 2001:db8:1::2 timers 3 10 + neighbor 2001:db8:1::2 timers connect 1 neighbor 2001:db8:1::2 ebgp-multihop 2 neighbor 2001:db8:1::2 bfd profile DOES_NOT_EXIST address-family ipv4 unicast diff --git a/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf b/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf index c7cf4a527f9e..69be4b541d23 100644 --- a/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf @@ -19,8 +19,10 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor 10.0.0.2 remote-as 65001 neighbor 10.0.0.2 timers 3 10 + neighbor 10.0.0.2 timers connect 1 neighbor 10.0.1.2 remote-as internal neighbor 10.0.1.2 timers 3 10 + neighbor 10.0.1.2 timers connect 1 address-family ipv4 unicast redistribute connected aggregate-address 192.168.0.0/24 matching-MED-only diff --git a/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf b/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf index acacd8652657..418624aed41e 100644 --- a/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf +++ b/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65000 neighbor 10.0.1.1 remote-as internal neighbor 10.0.1.1 timers 3 10 + neighbor 10.0.1.1 timers connect 1 address-family ipv4 unicast redistribute connected exit-address-family diff --git a/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf b/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf index 002a5c78c0f7..a6e24b221bf0 100644 --- a/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf +++ b/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf @@ -3,4 +3,5 @@ router bgp 65534 no bgp ebgp-requires-policy neighbor 10.0.0.2 remote-as external neighbor 10.0.0.2 timers 3 10 + neighbor 10.0.0.2 timers connect 1 ! diff --git a/tests/topotests/bgp_aspath_zero/r1/bgpd.conf b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf index 002a5c78c0f7..a6e24b221bf0 100644 --- a/tests/topotests/bgp_aspath_zero/r1/bgpd.conf +++ b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf @@ -3,4 +3,5 @@ router bgp 65534 no bgp ebgp-requires-policy neighbor 10.0.0.2 remote-as external neighbor 10.0.0.2 timers 3 10 + neighbor 10.0.0.2 timers connect 1 ! diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py new file mode 100644 index 000000000000..eac78a63f767 --- /dev/null +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright 2023, 6wind +import json +import os + +from lib import topotest +from lib.topogen import get_topogen +from lib.topolog import logger + +# remember the last sequence number of the logging messages +SEQ = 0 + + +def bmp_reset_seq(): + global SEQ + SEQ = 0 + + +def get_bmp_messages(bmp_collector, bmp_log_file): + """ + Read the BMP logging messages. + """ + messages = [] + text_output = bmp_collector.run(f"cat {bmp_log_file}") + + for m in text_output.splitlines(): + # some output in the bash can break the message decoding + try: + messages.append(json.loads(m)) + except Exception as e: + logger.warning(str(e) + " message: {}".format(str(m))) + continue + + if not messages: + logger.error("Bad BMP log format, check your BMP server") + + return messages + + +def bmp_update_seq(bmp_collector, bmp_log_file): + global SEQ + + messages = get_bmp_messages(bmp_collector, bmp_log_file) + + if len(messages): + SEQ = messages[-1]["seq"] + + +def bmp_update_expected_files( + bmp_actual, + expected_prefixes, + bmp_log_type, + policy, + step, + bmp_client, + bmp_log_folder, +): + tgen = get_topogen() + + with open( + f"{bmp_log_folder}/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w" + ) as json_file: + json.dump(bmp_actual, json_file, indent=4) + + out = bmp_client.vtysh_cmd("show bgp vrf vrf1 ipv4 json", isjson=True) + filtered_out = { + "routes": { + prefix: route_info + for prefix, route_info in out["routes"].items() + if prefix in expected_prefixes + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" in pfx: + continue + filtered_out["routes"][pfx] = None + + # ls {bmp_log_folder}/tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done + with open( + f"{bmp_log_folder}/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w" + ) as json_file: + json.dump(filtered_out, json_file, indent=4) + + out = tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv6 json", isjson=True) + filtered_out = { + "routes": { + prefix: route_info + for prefix, route_info in out["routes"].items() + if prefix in expected_prefixes + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" not in pfx: + continue + filtered_out["routes"][pfx] = None + + with open( + f"{bmp_log_folder}/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w" + ) as json_file: + json.dump(filtered_out, json_file, indent=4) + + +def bmp_check_for_prefixes( + expected_prefixes, + bmp_log_type, + policy, + step, + bmp_collector, + bmp_log_folder, + bmp_client, + expected_json_path, + update_expected_json, + loc_rib, +): + """ + Check for the presence of the given prefixes in the BMP server logs with + the given message type and the set policy. + + """ + global SEQ + + bmp_log_file = f"{bmp_log_folder}/bmp.log" + # we care only about the new messages + messages = [ + m + for m in sorted( + get_bmp_messages(bmp_collector, bmp_log_file), key=lambda d: d["seq"] + ) + if m["seq"] > SEQ + ] + + # create empty initial files + # for step in $(seq 1); do + # for i in "update" "withdraw"; do + # for j in "pre-policy" "post-policy" "loc-rib"; do + # echo '{"null": {}}'> bmp-$i-$j-step$step.json + # done + # done + # done + + ref_file = f"{expected_json_path}/bmp-{bmp_log_type}-{policy}-step{step}.json" + expected = json.loads(open(ref_file).read()) + + # Build actual json from logs + actual = {} + for m in messages: + if ( + "bmp_log_type" in m.keys() + and "ip_prefix" in m.keys() + and m["ip_prefix"] in expected_prefixes + and m["bmp_log_type"] == bmp_log_type + and m["policy"] == policy + ): + policy_dict = actual.setdefault(m["policy"], {}) + bmp_log_type_dict = policy_dict.setdefault(m["bmp_log_type"], {}) + + # Add or update the ip_prefix dictionary with filtered key-value pairs + bmp_log_type_dict[m["ip_prefix"]] = { + k: v + for k, v in sorted(m.items()) + # filter out variable keys + if k not in ["timestamp", "seq", "nxhp_link-local"] + } + + # build expected JSON files + if ( + update_expected_json + and actual + and set(actual.get(policy, {}).get(bmp_log_type, {}).keys()) + == set(expected_prefixes) + ): + bmp_update_expected_files( + actual, + expected_prefixes, + bmp_log_type, + policy, + step, + bmp_client, + bmp_log_folder, + ) + + return topotest.json_cmp(actual, expected, exact=True) + + +def bmp_check_for_peer_message( + 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 + """ + global SEQ + + # we care only about the new messages + messages = [ + m + for m in sorted( + get_bmp_messages(bmp_collector, bmp_log_file), key=lambda d: d["seq"] + ) + if m["seq"] > SEQ + ] + + # 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") + + # check for prefixes + for ep in expected_peers: + if ep not in peers: + msg = "The peer {} is not present in the {} log messages." + logger.debug(msg.format(ep, bmp_log_type)) + return False + + SEQ = messages[-1]["seq"] + return True diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json similarity index 91% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-loc-rib-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json index ba31bf1d5df7..d6c87dd4fdaa 100644 --- a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-loc-rib-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json @@ -10,6 +10,7 @@ "origin": "IGP", "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "444:1", "peer_type": "loc-rib instance", "policy": "loc-rib" }, @@ -23,6 +24,7 @@ "origin": "IGP", "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "555:1", "peer_type": "loc-rib instance", "policy": "loc-rib", "safi": 1 diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json similarity index 82% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-post-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json index d5d9d6518265..04e01623dfc0 100644 --- a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-post-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json @@ -10,9 +10,9 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy" }, "2111::1111/128": { @@ -25,9 +25,9 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy", "safi": 1 } diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json similarity index 82% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-pre-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json index e11badc040a9..760ee0409ab4 100644 --- a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-pre-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json @@ -10,9 +10,9 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy" }, "2111::1111/128": { @@ -25,9 +25,9 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy", "safi": 1 } diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json similarity index 89% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-loc-rib-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json index 37ddc09ff85b..6a82f7af1af9 100644 --- a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-loc-rib-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json @@ -7,6 +7,7 @@ "is_filtered": false, "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "444:1", "peer_type": "loc-rib instance", "policy": "loc-rib" }, @@ -17,6 +18,7 @@ "is_filtered": false, "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "555:1", "peer_type": "loc-rib instance", "policy": "loc-rib", "safi": 1 diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json similarity index 78% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-post-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json index de84307a4e6b..f57b1a51cefb 100644 --- a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-post-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json @@ -7,9 +7,9 @@ "ipv6": false, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy" }, "2111::1111/128": { @@ -19,9 +19,9 @@ "ipv6": true, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy", "safi": 1 } diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json similarity index 78% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-pre-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json index 1c34498b7a38..a52308c7892e 100644 --- a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-pre-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json @@ -7,9 +7,9 @@ "ipv6": false, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy" }, "2111::1111/128": { @@ -19,9 +19,9 @@ "ipv6": true, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy", "safi": 1 } diff --git a/tests/topotests/bgp_bmp/r1/bgpd.conf b/tests/topotests/bgp_bmp/r1/frr.conf similarity index 91% rename from tests/topotests/bgp_bmp/r1/bgpd.conf rename to tests/topotests/bgp_bmp/r1/frr.conf index 485c2170967c..f7cb669b3dd2 100644 --- a/tests/topotests/bgp_bmp/r1/bgpd.conf +++ b/tests/topotests/bgp_bmp/r1/frr.conf @@ -1,3 +1,10 @@ +interface r1-eth0 + ip address 192.0.2.1/24 +! +interface r1-eth1 + ip address 192.168.0.1/24 + ipv6 address 192:168::1/64 +! router bgp 65501 bgp router-id 192.168.0.1 bgp log-neighbor-changes @@ -41,7 +48,7 @@ router bgp 65501 exit-address-family ! router bgp 65501 vrf vrf1 - bgp router_id 192.168.0.1 + bgp router-id 192.168.0.1 bgp log-neighbor-changes address-family ipv4 unicast label vpn export 101 diff --git a/tests/topotests/bgp_bmp/r1/zebra.conf b/tests/topotests/bgp_bmp/r1/zebra.conf deleted file mode 100644 index 0b523c9e18d8..000000000000 --- a/tests/topotests/bgp_bmp/r1/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -interface r1-eth0 - ip address 192.0.2.1/24 -! -interface r1-eth1 - ip address 192.168.0.1/24 - ipv6 address 192:168::1/64 -! diff --git a/tests/topotests/bgp_bmp_vrf/r1/bgpd.conf b/tests/topotests/bgp_bmp/r1vrf/frr.conf similarity index 82% rename from tests/topotests/bgp_bmp_vrf/r1/bgpd.conf rename to tests/topotests/bgp_bmp/r1vrf/frr.conf index 961e20498b2e..87066934588e 100644 --- a/tests/topotests/bgp_bmp_vrf/r1/bgpd.conf +++ b/tests/topotests/bgp_bmp/r1vrf/frr.conf @@ -1,3 +1,10 @@ +interface r1vrf-eth0 + ip address 192.0.2.1/24 +! +interface r1vrf-eth1 + ip address 192.168.0.1/24 + ipv6 address 192:168::1/64 +! router bgp 65501 vrf vrf1 bgp router-id 192.168.0.1 bgp log-neighbor-changes @@ -15,14 +22,15 @@ router bgp 65501 vrf vrf1 bmp monitor ipv6 unicast loc-rib exit ! - address-family ipv4 unicast + rd vpn export 444:1 neighbor 192.168.0.2 activate neighbor 192.168.0.2 soft-reconfiguration inbound no neighbor 192:168::2 activate exit-address-family ! address-family ipv6 unicast + rd vpn export 555:1 neighbor 192:168::2 activate neighbor 192:168::2 soft-reconfiguration inbound exit-address-family diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-update-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-update-step1.json similarity index 91% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-update-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-update-step1.json index 038c87ca9dd0..dc0228db61f0 100644 --- a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-update-step1.json +++ b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-update-step1.json @@ -9,7 +9,6 @@ "nexthops": [ { "ip": "192.168.0.2", - "hostname": "r2", "afi": "ipv4", "used": true } diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-withdraw-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-withdraw-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-withdraw-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-withdraw-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-update-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-update-step1.json similarity index 88% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-update-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-update-step1.json index db34220149e2..64c8622ab523 100644 --- a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-update-step1.json +++ b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-update-step1.json @@ -9,12 +9,10 @@ "nexthops": [ { "ip": "192:168::2", - "hostname": "r2", "afi": "ipv6", "scope": "global" }, { - "hostname": "r2", "afi": "ipv6", "scope": "link-local", "used": true diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-withdraw-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-withdraw-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-withdraw-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-withdraw-step1.json diff --git a/tests/topotests/bgp_bmp/r2/bgpd.conf b/tests/topotests/bgp_bmp/r2/frr.conf similarity index 87% rename from tests/topotests/bgp_bmp/r2/bgpd.conf rename to tests/topotests/bgp_bmp/r2/frr.conf index 40e2cd5bbcb9..250071f48477 100644 --- a/tests/topotests/bgp_bmp/r2/bgpd.conf +++ b/tests/topotests/bgp_bmp/r2/frr.conf @@ -1,3 +1,11 @@ +interface r2-eth0 + ip address 192.168.0.2/24 + ipv6 address 192:168::2/64 +! +interface r2-eth1 + ip address 172.31.0.2/24 + ipv6 address 172:31::2/64 +! router bgp 65502 bgp router-id 192.168.0.2 bgp log-neighbor-changes diff --git a/tests/topotests/bgp_bmp/r2/zebra.conf b/tests/topotests/bgp_bmp/r2/zebra.conf deleted file mode 100644 index 9d82bfe2df5c..000000000000 --- a/tests/topotests/bgp_bmp/r2/zebra.conf +++ /dev/null @@ -1,8 +0,0 @@ -interface r2-eth0 - ip address 192.168.0.2/24 - ipv6 address 192:168::2/64 -! -interface r2-eth1 - ip address 172.31.0.2/24 - ipv6 address 172:31::2/64 -! diff --git a/tests/topotests/bgp_bmp_vrf/r2/bgpd.conf b/tests/topotests/bgp_bmp/r2vrf/frr.conf similarity index 74% rename from tests/topotests/bgp_bmp_vrf/r2/bgpd.conf rename to tests/topotests/bgp_bmp/r2vrf/frr.conf index 7c8255a17563..5268190dec21 100644 --- a/tests/topotests/bgp_bmp_vrf/r2/bgpd.conf +++ b/tests/topotests/bgp_bmp/r2vrf/frr.conf @@ -1,3 +1,11 @@ +interface r2vrf-eth0 + ip address 192.168.0.2/24 + ipv6 address 192:168::2/64 +! +interface r2vrf-eth1 + ip address 172.31.0.2/24 + ipv6 address 172:31::2/64 +! router bgp 65502 bgp router-id 192.168.0.2 bgp log-neighbor-changes diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py deleted file mode 100644 index 658ad2b99a2c..000000000000 --- a/tests/topotests/bgp_bmp/test_bgp_bmp.py +++ /dev/null @@ -1,476 +0,0 @@ -#!/usr/bin/env python -# SPDX-License-Identifier: ISC - -# Copyright 2023 6WIND S.A. -# Authored by Farid Mihoub -# - -""" -test_bgp_bmp.py: Test BGP BMP functionalities - - +------+ +------+ +------+ - | | | | | | - | BMP1 |------------| R1 |---------------| R2 | - | | | | | | - +------+ +------+ +------+ - -Setup two routers R1 and R2 with one link configured with IPv4 and -IPv6 addresses. -Configure BGP in R1 and R2 to exchange prefixes from -the latter to the first router. -Setup a link between R1 and the BMP server, activate the BMP feature in R1 -and ensure the monitored BGP sessions logs are well present on the BMP server. -""" - -from functools import partial -from ipaddress import ip_network -import json -import os -import pytest -import sys - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join("../")) -sys.path.append(os.path.join("../lib/")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger - -pytestmark = [pytest.mark.bgpd] - -# remember the last sequence number of the logging messages -SEQ = 0 - -PRE_POLICY = "pre-policy" -POST_POLICY = "post-policy" -LOC_RIB = "loc-rib" - -UPDATE_EXPECTED_JSON = False -DEBUG_PCAP = False - - -def build_topo(tgen): - tgen.add_router("r1") - tgen.add_router("r2") - tgen.add_bmp_server("bmp1", ip="192.0.2.10", defaultRoute="via 192.0.2.1") - - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["bmp1"]) - - tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "r1-eth1", "r2-eth0") - - -def setup_module(mod): - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - - if DEBUG_PCAP: - tgen.gears["r1"].run("rm /tmp/bmp.pcap") - tgen.gears["r1"].run( - "tcpdump -nni r1-eth0 -s 0 -w /tmp/bmp.pcap &", stdout=None - ) - - for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, "{}/bgpd.conf".format(rname)), - "-M bmp", - ) - - tgen.start_router() - - logger.info("starting BMP servers") - for bmp_name, server in tgen.get_bmp_servers().items(): - server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) - - -def teardown_module(_mod): - tgen = get_topogen() - tgen.stop_topology() - - -def test_bgp_convergence(): - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - result = verify_bgp_convergence_from_running_config(tgen, dut="r1") - assert result is True, "BGP is not converging" - - -def get_bmp_messages(): - """ - Read the BMP logging messages. - """ - messages = [] - tgen = get_topogen() - text_output = tgen.gears["bmp1"].run( - "cat {}".format(os.path.join(tgen.logdir, "bmp1", "bmp.log")) - ) - - for m in text_output.splitlines(): - # some output in the bash can break the message decoding - try: - messages.append(json.loads(m)) - except Exception as e: - logger.warning(str(e) + " message: {}".format(str(m))) - continue - - if not messages: - logger.error("Bad BMP log format, check your BMP server") - - return messages - - -def update_seq(): - global SEQ - - messages = get_bmp_messages() - - if len(messages): - SEQ = messages[-1]["seq"] - - -def update_expected_files(bmp_actual, expected_prefixes, bmp_log_type, policy, step): - tgen = get_topogen() - - with open(f"/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w") as json_file: - json.dump(bmp_actual, json_file, indent=4) - - if step == 2: # vpn - rd = "444:2" - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv4 vpn json", isjson=True) - filtered_out = { - "routes": { - "routeDistinguishers": { - rd: { - prefix: route_info - for prefix, route_info in out["routes"] - .get("routeDistinguishers", {}) - .get(rd, {}) - .items() - if prefix in expected_prefixes - } - } - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" in pfx: - continue - filtered_out["routes"]["routeDistinguishers"][rd][pfx] = None - - # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done - with open( - f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w" - ) as json_file: - json.dump(filtered_out, json_file, indent=4) - - rd = "555:2" - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv6 vpn json", isjson=True) - filtered_out = { - "routes": { - "routeDistinguishers": { - rd: { - prefix: route_info - for prefix, route_info in out["routes"] - .get("routeDistinguishers", {}) - .get(rd, {}) - .items() - if prefix in expected_prefixes - } - } - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" not in pfx: - continue - filtered_out["routes"]["routeDistinguishers"][rd][pfx] = None - with open( - f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w" - ) as json_file: - json.dump(filtered_out, json_file, indent=4) - - return - - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv4 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" in pfx: - continue - filtered_out["routes"][pfx] = None - - # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done - with open(f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv6 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" not in pfx: - continue - filtered_out["routes"][pfx] = None - with open(f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - -def check_for_prefixes(expected_prefixes, bmp_log_type, policy, step): - """ - Check for the presence of the given prefixes in the BMP server logs with - the given message type and the set policy. - - """ - global SEQ - - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # create empty initial files - # for step in $(seq 2); do - # for i in "update" "withdraw"; do - # for j in "pre-policy" "post-policy" "loc-rib"; do - # echo '{"null": {}}'> bmp-$i-$j-step$step.json - # done - # done - # done - - ref_file = f"{CWD}/bmp1/bmp-{bmp_log_type}-{policy}-step{step}.json" - expected = json.loads(open(ref_file).read()) - - # Build actual json from logs - actual = {} - for m in messages: - if ( - "bmp_log_type" in m.keys() - and "ip_prefix" in m.keys() - and m["ip_prefix"] in expected_prefixes - and m["bmp_log_type"] == bmp_log_type - and m["policy"] == policy - ): - policy_dict = actual.setdefault(m["policy"], {}) - bmp_log_type_dict = policy_dict.setdefault(m["bmp_log_type"], {}) - - # Add or update the ip_prefix dictionary with filtered key-value pairs - bmp_log_type_dict[m["ip_prefix"]] = { - k: v - 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:. - # 0: 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 - if ( - UPDATE_EXPECTED_JSON - and actual - and set(actual.get(policy, {}).get(bmp_log_type, {}).keys()) - == set(expected_prefixes) - ): - update_expected_files(actual, expected_prefixes, bmp_log_type, policy, step) - - return topotest.json_cmp(actual, expected, exact=True) - - -def check_for_peer_message(expected_peers, bmp_log_type): - """ - Check for the presence of a peer up message for the peer - """ - global SEQ - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # get the list of pairs (prefix, policy, seq) for the given message type - peers = [ - m["peer_ip"] - for m in messages - if "peer_ip" in m.keys() and m["bmp_log_type"] == bmp_log_type - ] - - # check for prefixes - for ep in expected_peers: - if ep not in peers: - msg = "The peer {} is not present in the {} log messages." - logger.debug(msg.format(ep, bmp_log_type)) - return False - - SEQ = messages[-1]["seq"] - return True - - -def configure_prefixes(tgen, node, asn, safi, prefixes, vrf=None, update=True): - """ - Configure the bgp prefixes. - """ - withdraw = "no " if not update else "" - vrf = " vrf {}".format(vrf) if vrf else "" - for p in prefixes: - ip = ip_network(p) - cmd = [ - "conf t\n", - "router bgp {}{}\n".format(asn, vrf), - "address-family ipv{} {}\n".format(ip.version, safi), - "{}network {}\n".format(withdraw, ip), - "exit-address-family\n", - ] - logger.debug("setting prefix: ipv{} {} {}".format(ip.version, safi, ip)) - tgen.gears[node].vtysh_cmd("".join(cmd)) - - -def _test_prefixes(policy, vrf=None, step=0): - """ - Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. - Check if the previous actions are logged in the BMP server with the right - message type and the right policy. - """ - tgen = get_topogen() - - safi = "vpn" if vrf else "unicast" - - prefixes = ["172.31.0.15/32", "2001::1111/128"] - - for type in ("update", "withdraw"): - update_seq() - - configure_prefixes( - tgen, "r2", 65502, "unicast", prefixes, vrf=vrf, update=(type == "update") - ) - - logger.info(f"checking for prefixes {type}") - - for ipver in [4, 6]: - if UPDATE_EXPECTED_JSON: - continue - ref_file = "{}/r1/show-bgp-ipv{}-{}-step{}.json".format( - CWD, ipver, type, step - ) - expected = json.loads(open(ref_file).read()) - - test_func = partial( - topotest.router_json_cmp, - tgen.gears["r1"], - f"show bgp ipv{ipver} {safi} json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = f"r1: BGP IPv{ipver} convergence failed" - assert res is None, assertmsg - - # check - test_func = partial(check_for_prefixes, prefixes, type, policy, step) - success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assert success, "Checking the updated prefixes has failed ! %s" % res - - -def test_bmp_server_logging(): - """ - Assert the logging of the bmp server. - """ - - def check_for_log_file(): - tgen = get_topogen() - output = tgen.gears["bmp1"].run( - "ls {}".format(os.path.join(tgen.logdir, "bmp1")) - ) - if "bmp.log" not in output: - return False - return True - - success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) - assert success, "The BMP server is not logging" - - -def test_peer_up(): - """ - Checking for BMP peers up messages - """ - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers up messages") - - test_func = partial(check_for_peer_message, peers, "peer up") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -def test_bmp_bgp_unicast(): - """ - Add/withdraw bgp unicast prefixes and check the bmp logs. - """ - logger.info("*** Unicast prefixes pre-policy logging ***") - _test_prefixes(PRE_POLICY, step=1) - logger.info("*** Unicast prefixes post-policy logging ***") - _test_prefixes(POST_POLICY, step=1) - logger.info("*** Unicast prefixes loc-rib logging ***") - _test_prefixes(LOC_RIB, step=1) - - -def test_bmp_bgp_vpn(): - # check for the prefixes in the BMP server logging file - logger.info("***** VPN prefixes pre-policy logging *****") - _test_prefixes(PRE_POLICY, vrf="vrf1", step=2) - logger.info("***** VPN prefixes post-policy logging *****") - _test_prefixes(POST_POLICY, vrf="vrf1", step=2) - logger.info("***** VPN prefixes loc-rib logging *****") - _test_prefixes(LOC_RIB, vrf="vrf1", step=2) - - -def test_peer_down(): - """ - Checking for BMP peers down messages - """ - tgen = get_topogen() - - tgen.gears["r2"].vtysh_cmd("clear bgp *") - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers down messages") - - test_func = partial(check_for_peer_message, peers, "peer down") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py new file mode 100644 index 000000000000..be3e07929a0f --- /dev/null +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright 2023 6WIND S.A. +# Authored by Farid Mihoub +# + +""" +test_bgp_bmp.py: Test BGP BMP functionalities + + +------+ +------+ +------+ + | | | | | | + | BMP1 |------------| R1 |---------------| R2 | + | | | | | | + +------+ +------+ +------+ + +Setup two routers R1 and R2 with one link configured with IPv4 and +IPv6 addresses. +Configure BGP in R1 and R2 to exchange prefixes from +the latter to the first router. +Setup a link between R1 and the BMP server, activate the BMP feature in R1 +and ensure the monitored BGP sessions logs are well present on the BMP server. +""" + +from functools import partial +import json +import os +import pytest +import sys + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.bgp import verify_bgp_convergence_from_running_config +from lib.bgp import bgp_configure_prefixes +from .bgpbmp import ( + bmp_check_for_prefixes, + bmp_check_for_peer_message, + bmp_update_seq, +) +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + +PRE_POLICY = "pre-policy" +POST_POLICY = "post-policy" +LOC_RIB = "loc-rib" + +UPDATE_EXPECTED_JSON = False +DEBUG_PCAP = False + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_bmp_server("bmp1", ip="192.0.2.10", defaultRoute="via 192.0.2.1") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["bmp1"]) + + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "r1-eth1", "r2-eth0") + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + if DEBUG_PCAP: + pcap_file = os.path.join(tgen.logdir, "r1/bmp.pcap") + tgen.gears["r1"].run( + "tcpdump -nni r1-eth0 -s 0 -w {} &".format(pcap_file), stdout=None + ) + + for rname, router in tgen.routers().items(): + logger.info("Loading router %s" % rname) + router.load_frr_config( + os.path.join(CWD, "{}/frr.conf".format(rname)), + [(TopoRouter.RD_ZEBRA, None), (TopoRouter.RD_BGP, "-M bmp")], + ) + + tgen.start_router() + + logger.info("starting BMP servers") + for bmp_name, server in tgen.get_bmp_servers().items(): + server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) + + +def teardown_module(_mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_convergence(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + result = verify_bgp_convergence_from_running_config(tgen, dut="r1") + assert result is True, "BGP is not converging" + + +def _test_prefixes(policy, vrf=None, step=0): + """ + Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. + Check if the previous actions are logged in the BMP server with the right + message type and the right policy. + """ + tgen = get_topogen() + + safi = "vpn" if vrf else "unicast" + + prefixes = ["172.31.0.15/32", "2001::1111/128"] + + for type in ("update", "withdraw"): + bmp_update_seq(tgen.gears["bmp1"], os.path.join(tgen.logdir, "bmp1", "bmp.log")) + + bgp_configure_prefixes( + tgen.gears["r2"], + 65502, + "unicast", + prefixes, + vrf=vrf, + update=(type == "update"), + ) + + logger.info(f"checking for prefixes {type}") + + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1/show-bgp-ipv{}-{}-step{}.json".format( + CWD, ipver, type, step + ) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + f"show bgp ipv{ipver} {safi} json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = f"r1: BGP IPv{ipver} convergence failed" + assert res is None, assertmsg + + # check + test_func = partial( + bmp_check_for_prefixes, + prefixes, + type, + policy, + step, + tgen.gears["bmp1"], + os.path.join(tgen.logdir, "bmp1"), + tgen.gears["r1"], + f"{CWD}/bmp1", + UPDATE_EXPECTED_JSON, + LOC_RIB, + ) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the updated prefixes has failed ! %s" % res + + +def test_bmp_server_logging(): + """ + Assert the logging of the bmp server. + """ + + def check_for_log_file(): + tgen = get_topogen() + output = tgen.gears["bmp1"].run( + "ls {}".format(os.path.join(tgen.logdir, "bmp1")) + ) + if "bmp.log" not in output: + return False + return True + + success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) + assert success, "The BMP server is not logging" + + +def test_peer_up(): + """ + Checking for BMP peers up messages + """ + + tgen = get_topogen() + peers = ["192.168.0.2", "192:168::2", "0.0.0.0"] + + logger.info("checking for BMP peers up messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1"], + os.path.join(tgen.logdir, "bmp1", "bmp.log"), + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +def test_bmp_bgp_unicast(): + """ + Add/withdraw bgp unicast prefixes and check the bmp logs. + """ + logger.info("*** Unicast prefixes pre-policy logging ***") + _test_prefixes(PRE_POLICY, step=1) + logger.info("*** Unicast prefixes post-policy logging ***") + _test_prefixes(POST_POLICY, step=1) + logger.info("*** Unicast prefixes loc-rib logging ***") + _test_prefixes(LOC_RIB, step=1) + + +def test_bmp_bgp_vpn(): + # check for the prefixes in the BMP server logging file + logger.info("***** VPN prefixes pre-policy logging *****") + _test_prefixes(PRE_POLICY, vrf="vrf1", step=2) + logger.info("***** VPN prefixes post-policy logging *****") + _test_prefixes(POST_POLICY, vrf="vrf1", step=2) + logger.info("***** VPN prefixes loc-rib logging *****") + _test_prefixes(LOC_RIB, vrf="vrf1", step=2) + + +def test_peer_down(): + """ + Checking for BMP peers down messages + """ + tgen = get_topogen() + + tgen.gears["r2"].vtysh_cmd("clear bgp *") + + peers = ["192.168.0.2", "192:168::2"] + + logger.info("checking for BMP peers down messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer down", + tgen.gears["bmp1"], + os.path.join(tgen.logdir, "bmp1", "bmp.log"), + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py new file mode 100644 index 000000000000..f16ff2b4458b --- /dev/null +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright 2023 6WIND S.A. +# Authored by Farid Mihoub +# + +""" +test_bgp_bmp.py: Test BGP BMP functionalities + + +------+ +------+ +------+ + | | | | | | + | BMP1 |------------| R1 |---------------| R2 | + | | | | | | + +------+ +------+ +------+ + +Setup two routers R1 and R2 with one link configured with IPv4 and +IPv6 addresses. +Configure BGP in R1 and R2 to exchange prefixes from +the latter to the first router. +Setup a link between R1 and the BMP server, activate the BMP feature in R1 +and ensure the monitored BGP sessions logs are well present on the BMP server. +""" + +from functools import partial +import json +import os +import platform +import pytest +import sys + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.bgp import verify_bgp_convergence_from_running_config +from lib.bgp import bgp_configure_prefixes +from .bgpbmp import ( + bmp_check_for_prefixes, + bmp_check_for_peer_message, + bmp_update_seq, + bmp_reset_seq, +) + + +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + +PRE_POLICY = "pre-policy" +POST_POLICY = "post-policy" +LOC_RIB = "loc-rib" + +UPDATE_EXPECTED_JSON = False +DEBUG_PCAP = False + + +def build_topo(tgen): + tgen.add_router("r1vrf") + tgen.add_router("r2vrf") + tgen.add_bmp_server("bmp1vrf", ip="192.0.2.10", defaultRoute="via 192.0.2.1") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1vrf"]) + switch.add_link(tgen.gears["bmp1vrf"]) + + tgen.add_link(tgen.gears["r1vrf"], tgen.gears["r2vrf"], "r1vrf-eth1", "r2vrf-eth0") + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + tgen.net["r1vrf"].cmd( + """ +ip link add vrf1 type vrf table 10 +ip link set vrf1 up +ip link set r1vrf-eth1 master vrf1 +""" + ) + bmp_reset_seq() + if DEBUG_PCAP: + pcap_file = os.path.join(tgen.logdir, "r1vrf/bmp.pcap") + tgen.gears["r1vrf"].run( + "tcpdump -nni r1vrf-eth0 -s 0 -w {} &".format(pcap_file), stdout=None + ) + + for rname, router in tgen.routers().items(): + logger.info("Loading router %s" % rname) + router.load_frr_config( + os.path.join(CWD, "{}/frr.conf".format(rname)), + [(TopoRouter.RD_ZEBRA, None), (TopoRouter.RD_BGP, "-M bmp")], + ) + + tgen.start_router() + + logger.info("starting BMP servers") + for bmp_name, server in tgen.get_bmp_servers().items(): + server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) + + +def teardown_module(_mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_convergence(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + result = verify_bgp_convergence_from_running_config(tgen, dut="r1vrf") + assert result is True, "BGP is not converging" + + +def _test_prefixes(policy, step=1): + """ + Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. + Check if the previous actions are logged in the BMP server with the right + message type and the right policy. + """ + tgen = get_topogen() + + prefixes = ["172.31.0.15/32", "2111::1111/128"] + + for type in ("update", "withdraw"): + bmp_update_seq( + tgen.gears["bmp1vrf"], os.path.join(tgen.logdir, "bmp1vrf", "bmp.log") + ) + + # add prefixes + bgp_configure_prefixes( + tgen.gears["r2vrf"], 65502, "unicast", prefixes, update=(type == "update") + ) + + logger.info(f"checking for prefixes {type}") + + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1vrf/show-bgp-ipv{}-{}-step{}.json".format( + CWD, ipver, type, step + ) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1vrf"], + f"show bgp vrf vrf1 ipv{ipver} json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = f"r1vrf: BGP IPv{ipver} convergence failed" + assert res is None, assertmsg + + # check + test_func = partial( + bmp_check_for_prefixes, + prefixes, + type, + policy, + step, + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf"), + tgen.gears["r1vrf"], + f"{CWD}/bmp1vrf", + UPDATE_EXPECTED_JSON, + LOC_RIB, + ) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the updated prefixes has failed ! %s" % res + + +def test_bmp_server_logging(): + """ + Assert the logging of the bmp server. + """ + + def check_for_log_file(): + tgen = get_topogen() + output = tgen.gears["bmp1vrf"].run( + "ls {}".format(os.path.join(tgen.logdir, "bmp1vrf")) + ) + if "bmp.log" not in output: + return False + return True + + success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) + assert success, "The BMP server is not logging" + + +def test_peer_up(): + """ + Checking for BMP peers up messages + """ + + tgen = get_topogen() + peers = ["192.168.0.2", "192:168::2", "0.0.0.0"] + + logger.info("checking for BMP peers up messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +def test_bmp_bgp_unicast(): + """ + Add/withdraw bgp unicast prefixes and check the bmp logs. + """ + logger.info("*** Unicast prefixes pre-policy logging ***") + _test_prefixes(PRE_POLICY) + logger.info("*** Unicast prefixes post-policy logging ***") + _test_prefixes(POST_POLICY) + logger.info("*** Unicast prefixes loc-rib logging ***") + _test_prefixes(LOC_RIB) + + +def test_peer_down(): + """ + Checking for BMP peers down messages + """ + tgen = get_topogen() + + tgen.gears["r2vrf"].vtysh_cmd("clear bgp *") + + peers = ["192.168.0.2", "192:168::2"] + + logger.info("checking for BMP peers down messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer down", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_bmp_vrf/r1/zebra.conf b/tests/topotests/bgp_bmp_vrf/r1/zebra.conf deleted file mode 100644 index 0b523c9e18d8..000000000000 --- a/tests/topotests/bgp_bmp_vrf/r1/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -interface r1-eth0 - ip address 192.0.2.1/24 -! -interface r1-eth1 - ip address 192.168.0.1/24 - ipv6 address 192:168::1/64 -! diff --git a/tests/topotests/bgp_bmp_vrf/r2/zebra.conf b/tests/topotests/bgp_bmp_vrf/r2/zebra.conf deleted file mode 100644 index 9d82bfe2df5c..000000000000 --- a/tests/topotests/bgp_bmp_vrf/r2/zebra.conf +++ /dev/null @@ -1,8 +0,0 @@ -interface r2-eth0 - ip address 192.168.0.2/24 - ipv6 address 192:168::2/64 -! -interface r2-eth1 - ip address 172.31.0.2/24 - ipv6 address 172:31::2/64 -! diff --git a/tests/topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py b/tests/topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py deleted file mode 100644 index d31328bdb659..000000000000 --- a/tests/topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py +++ /dev/null @@ -1,418 +0,0 @@ -#!/usr/bin/env python -# SPDX-License-Identifier: ISC - -# Copyright 2023 6WIND S.A. -# Authored by Farid Mihoub -# - -""" -test_bgp_bmp.py: Test BGP BMP functionalities - - +------+ +------+ +------+ - | | | | | | - | BMP1 |------------| R1 |---------------| R2 | - | | | | | | - +------+ +------+ +------+ - -Setup two routers R1 and R2 with one link configured with IPv4 and -IPv6 addresses. -Configure BGP in R1 and R2 to exchange prefixes from -the latter to the first router. -Setup a link between R1 and the BMP server, activate the BMP feature in R1 -and ensure the monitored BGP sessions logs are well present on the BMP server. -""" - -from functools import partial -from ipaddress import ip_network -import json -import os -import platform -import pytest -import sys - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join("../")) -sys.path.append(os.path.join("../lib/")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger - -pytestmark = [pytest.mark.bgpd] - -# remember the last sequence number of the logging messages -SEQ = 0 - -PRE_POLICY = "pre-policy" -POST_POLICY = "post-policy" -LOC_RIB = "loc-rib" - -UPDATE_EXPECTED_JSON = False -DEBUG_PCAP = False - - -def build_topo(tgen): - tgen.add_router("r1") - tgen.add_router("r2") - tgen.add_bmp_server("bmp1", ip="192.0.2.10", defaultRoute="via 192.0.2.1") - - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["bmp1"]) - - tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "r1-eth1", "r2-eth0") - - -def setup_module(mod): - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - - tgen.net["r1"].cmd( - """ -ip link add vrf1 type vrf table 10 -ip link set vrf1 up -ip link set r1-eth1 master vrf1 -""" - ) - - if DEBUG_PCAP: - tgen.gears["r1"].run("rm /tmp/bmp_vrf.pcap") - tgen.gears["r1"].run( - "tcpdump -nni r1-eth0 -s 0 -w /tmp/bmp_vrf.pcap &", stdout=None - ) - - for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, "{}/bgpd.conf".format(rname)), - "-M bmp", - ) - - tgen.start_router() - - logger.info("starting BMP servers") - for bmp_name, server in tgen.get_bmp_servers().items(): - server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) - - -def teardown_module(_mod): - tgen = get_topogen() - tgen.stop_topology() - - -def test_bgp_convergence(): - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - result = verify_bgp_convergence_from_running_config(tgen, dut="r1") - assert result is True, "BGP is not converging" - - -def get_bmp_messages(): - """ - Read the BMP logging messages. - """ - messages = [] - tgen = get_topogen() - text_output = tgen.gears["bmp1"].run( - "cat {}".format(os.path.join(tgen.logdir, "bmp1", "bmp.log")) - ) - - for m in text_output.splitlines(): - # some output in the bash can break the message decoding - try: - messages.append(json.loads(m)) - except Exception as e: - logger.warning(str(e) + " message: {}".format(str(m))) - continue - - if not messages: - logger.error("Bad BMP log format, check your BMP server") - - return messages - - -def update_seq(): - global SEQ - - messages = get_bmp_messages() - - if len(messages): - SEQ = messages[-1]["seq"] - - -def update_expected_files(bmp_actual, expected_prefixes, bmp_log_type, policy, step): - tgen = get_topogen() - - with open(f"/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w") as json_file: - json.dump(bmp_actual, json_file, indent=4) - - out = tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" in pfx: - continue - filtered_out["routes"][pfx] = None - - # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done - with open(f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - out = tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv6 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" not in pfx: - continue - filtered_out["routes"][pfx] = None - - with open(f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - -def check_for_prefixes(expected_prefixes, bmp_log_type, policy, step): - """ - Check for the presence of the given prefixes in the BMP server logs with - the given message type and the set policy. - - """ - global SEQ - - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # create empty initial files - # for step in $(seq 1); do - # for i in "update" "withdraw"; do - # for j in "pre-policy" "post-policy" "loc-rib"; do - # echo '{"null": {}}'> bmp-$i-$j-step$step.json - # done - # done - # done - - ref_file = f"{CWD}/bmp1/bmp-{bmp_log_type}-{policy}-step{step}.json" - expected = json.loads(open(ref_file).read()) - - # Build actual json from logs - actual = {} - for m in messages: - if ( - "bmp_log_type" in m.keys() - and "ip_prefix" in m.keys() - and m["ip_prefix"] in expected_prefixes - and m["bmp_log_type"] == bmp_log_type - and m["policy"] == policy - ): - policy_dict = actual.setdefault(m["policy"], {}) - bmp_log_type_dict = policy_dict.setdefault(m["bmp_log_type"], {}) - - # Add or update the ip_prefix dictionary with filtered key-value pairs - bmp_log_type_dict[m["ip_prefix"]] = { - k: v - 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:. - # 0: 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 - if ( - UPDATE_EXPECTED_JSON - and actual - and set(actual.get(policy, {}).get(bmp_log_type, {}).keys()) - == set(expected_prefixes) - ): - update_expected_files(actual, expected_prefixes, bmp_log_type, policy, step) - - return topotest.json_cmp(actual, expected, exact=True) - - -def check_for_peer_message(expected_peers, bmp_log_type): - """ - Check for the presence of a peer up message for the peer - """ - global SEQ - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # get the list of pairs (prefix, policy, seq) for the given message type - peers = [ - m["peer_ip"] - for m in messages - if "peer_ip" in m.keys() and m["bmp_log_type"] == bmp_log_type - ] - - # check for prefixes - for ep in expected_peers: - if ep not in peers: - msg = "The peer {} is not present in the {} log messages." - logger.debug(msg.format(ep, bmp_log_type)) - return False - - SEQ = messages[-1]["seq"] - return True - - -def configure_prefixes(tgen, node, asn, safi, prefixes, vrf=None, update=True): - """ - Configure the bgp prefixes. - """ - withdraw = "no " if not update else "" - vrf = " vrf {}".format(vrf) if vrf else "" - for p in prefixes: - ip = ip_network(p) - cmd = [ - "conf t\n", - "router bgp {}{}\n".format(asn, vrf), - "address-family ipv{} {}\n".format(ip.version, safi), - "{}network {}\n".format(withdraw, ip), - "exit-address-family\n", - ] - logger.debug("setting prefix: ipv{} {} {}".format(ip.version, safi, ip)) - tgen.gears[node].vtysh_cmd("".join(cmd)) - - -def _test_prefixes(policy, step=1): - """ - Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. - Check if the previous actions are logged in the BMP server with the right - message type and the right policy. - """ - tgen = get_topogen() - - prefixes = ["172.31.0.15/32", "2111::1111/128"] - - for type in ("update", "withdraw"): - update_seq() - - # add prefixes - configure_prefixes( - tgen, "r2", 65502, "unicast", prefixes, update=(type == "update") - ) - - logger.info(f"checking for prefixes {type}") - - for ipver in [4, 6]: - if UPDATE_EXPECTED_JSON: - continue - ref_file = "{}/r1/show-bgp-ipv{}-{}-step{}.json".format( - CWD, ipver, type, step - ) - expected = json.loads(open(ref_file).read()) - - test_func = partial( - topotest.router_json_cmp, - tgen.gears["r1"], - f"show bgp vrf vrf1 ipv{ipver} json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = f"r1: BGP IPv{ipver} convergence failed" - assert res is None, assertmsg - - # check - test_func = partial(check_for_prefixes, prefixes, type, policy, step) - success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed ! %s" % res - - -def test_bmp_server_logging(): - """ - Assert the logging of the bmp server. - """ - - def check_for_log_file(): - tgen = get_topogen() - output = tgen.gears["bmp1"].run( - "ls {}".format(os.path.join(tgen.logdir, "bmp1")) - ) - if "bmp.log" not in output: - return False - return True - - success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) - assert success, "The BMP server is not logging" - - -def test_peer_up(): - """ - Checking for BMP peers up messages - """ - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers up messages") - - test_func = partial(check_for_peer_message, peers, "peer up") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -def test_bmp_bgp_unicast(): - """ - Add/withdraw bgp unicast prefixes and check the bmp logs. - """ - logger.info("*** Unicast prefixes pre-policy logging ***") - _test_prefixes(PRE_POLICY) - logger.info("*** Unicast prefixes post-policy logging ***") - _test_prefixes(POST_POLICY) - logger.info("*** Unicast prefixes loc-rib logging ***") - _test_prefixes(LOC_RIB) - - -def test_peer_down(): - """ - Checking for BMP peers down messages - """ - tgen = get_topogen() - - tgen.gears["r2"].vtysh_cmd("clear bgp *") - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers down messages") - - test_func = partial(check_for_peer_message, peers, "peer down") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf b/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf index 49981ac58968..09c65321c2e1 100644 --- a/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf @@ -8,44 +8,64 @@ router bgp 100 no bgp ebgp-requires-policy neighbor 10.0.1.101 remote-as 99 neighbor 10.0.1.101 timers 3 10 + neighbor 10.0.1.101 timers connect 1 neighbor 10.0.1.102 remote-as 99 neighbor 10.0.1.102 timers 3 10 + neighbor 10.0.1.102 timers connect 1 neighbor 10.0.1.103 remote-as 99 neighbor 10.0.1.103 timers 3 10 + neighbor 10.0.1.103 timers connect 1 neighbor 10.0.1.104 remote-as 99 neighbor 10.0.1.104 timers 3 10 + neighbor 10.0.1.104 timers connect 1 neighbor 10.0.1.105 remote-as 99 neighbor 10.0.1.105 timers 3 10 + neighbor 10.0.1.105 timers connect 1 neighbor 10.0.2.106 remote-as 99 neighbor 10.0.2.106 timers 3 10 + neighbor 10.0.1.106 timers connect 1 neighbor 10.0.2.107 remote-as 99 neighbor 10.0.2.107 timers 3 10 + neighbor 10.0.1.107 timers connect 1 neighbor 10.0.2.108 remote-as 99 neighbor 10.0.2.108 timers 3 10 + neighbor 10.0.1.108 timers connect 1 neighbor 10.0.2.109 remote-as 99 neighbor 10.0.2.109 timers 3 10 + neighbor 10.0.1.109 timers connect 1 neighbor 10.0.2.110 remote-as 99 neighbor 10.0.2.110 timers 3 10 + neighbor 10.0.1.110 timers connect 1 neighbor 10.0.3.111 remote-as 111 neighbor 10.0.3.111 timers 3 10 + neighbor 10.0.1.111 timers connect 1 neighbor 10.0.3.112 remote-as 112 neighbor 10.0.3.112 timers 3 10 + neighbor 10.0.1.112 timers connect 1 neighbor 10.0.3.113 remote-as 113 neighbor 10.0.3.113 timers 3 10 + neighbor 10.0.1.113 timers connect 1 neighbor 10.0.3.114 remote-as 114 neighbor 10.0.3.114 timers 3 10 + neighbor 10.0.1.114 timers connect 1 neighbor 10.0.3.115 remote-as 115 neighbor 10.0.3.115 timers 3 10 + neighbor 10.0.1.115 timers connect 1 neighbor 10.0.4.116 remote-as 116 neighbor 10.0.4.116 timers 3 10 + neighbor 10.0.1.116 timers connect 1 neighbor 10.0.4.117 remote-as 117 neighbor 10.0.4.117 timers 3 10 + neighbor 10.0.1.117 timers connect 1 neighbor 10.0.4.118 remote-as 118 neighbor 10.0.4.118 timers 3 10 + neighbor 10.0.1.118 timers connect 1 neighbor 10.0.4.119 remote-as 119 neighbor 10.0.4.119 timers 3 10 + neighbor 10.0.1.119 timers connect 1 neighbor 10.0.4.120 remote-as 120 neighbor 10.0.4.120 timers 3 10 + neighbor 10.0.1.120 timers connect 1 ! ! diff --git a/tests/topotests/bgp_flowspec/r1/bgpd.conf b/tests/topotests/bgp_flowspec/r1/bgpd.conf index 4b7a20f95800..288aeaf4dde9 100644 --- a/tests/topotests/bgp_flowspec/r1/bgpd.conf +++ b/tests/topotests/bgp_flowspec/r1/bgpd.conf @@ -6,6 +6,7 @@ router bgp 100 bgp router-id 10.0.1.1 neighbor 10.0.1.101 remote-as 100 neighbor 10.0.1.101 timers 3 10 + neighbor 10.0.1.101 timers connect 1 neighbor 10.0.1.101 update-source 10.0.1.1 address-family ipv6 flowspec local-install r1-eth0 diff --git a/tests/topotests/bgp_invalid_nexthop/r1/frr.conf b/tests/topotests/bgp_invalid_nexthop/r1/frr.conf index 05e1a6c8259e..f96aeb43668c 100644 --- a/tests/topotests/bgp_invalid_nexthop/r1/frr.conf +++ b/tests/topotests/bgp_invalid_nexthop/r1/frr.conf @@ -8,6 +8,7 @@ router bgp 65001 no bgp ebgp-requires-policy neighbor fc00::2 remote-as external neighbor fc00::2 timers 3 10 + neighbor fc00::2 timers connect 1 address-family ipv6 neighbor fc00::2 activate exit-address-family diff --git a/tests/topotests/bgp_lu_topo1/R3/bgpd.conf b/tests/topotests/bgp_lu_topo1/R3/bgpd.conf index 31d26ea1ed37..9ba059aeeca9 100644 --- a/tests/topotests/bgp_lu_topo1/R3/bgpd.conf +++ b/tests/topotests/bgp_lu_topo1/R3/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log ! ! debug bgp updates ! diff --git a/tests/topotests/bgp_lu_topo1/R3/zebra.conf b/tests/topotests/bgp_lu_topo1/R3/zebra.conf index ea4a1482dd42..fedcd6bc3a7e 100644 --- a/tests/topotests/bgp_lu_topo1/R3/zebra.conf +++ b/tests/topotests/bgp_lu_topo1/R3/zebra.conf @@ -1,4 +1,3 @@ -log file /tmp/zebra.log ! ! debug zebra events ! debug zebra packet detail diff --git a/tests/topotests/bgp_lu_topo2/R3/bgpd.conf b/tests/topotests/bgp_lu_topo2/R3/bgpd.conf index 6443445b802b..a0dd0fe00902 100644 --- a/tests/topotests/bgp_lu_topo2/R3/bgpd.conf +++ b/tests/topotests/bgp_lu_topo2/R3/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log no log unique-id ! ! diff --git a/tests/topotests/bgp_lu_topo2/R3/staticd.conf b/tests/topotests/bgp_lu_topo2/R3/staticd.conf index 867fc5a837f4..c0eee461eaab 100644 --- a/tests/topotests/bgp_lu_topo2/R3/staticd.conf +++ b/tests/topotests/bgp_lu_topo2/R3/staticd.conf @@ -1,4 +1,3 @@ -log file /tmp/staticd.log no log unique-id ! ! diff --git a/tests/topotests/bgp_lu_topo2/R3/zebra.conf b/tests/topotests/bgp_lu_topo2/R3/zebra.conf index dd24deb2141d..fd29ed54dcdf 100644 --- a/tests/topotests/bgp_lu_topo2/R3/zebra.conf +++ b/tests/topotests/bgp_lu_topo2/R3/zebra.conf @@ -1,4 +1,3 @@ -log file /tmp/zebra.log no log unique-id ! ! diff --git a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf index cd7f44ac6650..ced5cb5e4dcc 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf @@ -19,10 +19,13 @@ router bgp 100 view 1 timers bgp 60 180 neighbor 172.16.1.1 remote-as 65001 neighbor 172.16.1.1 timers 3 10 + neighbor 172.16.1.1 timers connect 1 neighbor 172.16.1.2 remote-as 65002 neighbor 172.16.1.2 timers 3 10 + neighbor 172.16.1.2 timers connect 1 neighbor 172.16.1.5 remote-as 65005 neighbor 172.16.1.5 timers 3 10 + neighbor 172.16.1.5 timers connect 1 ! router bgp 100 view 2 bgp router-id 172.30.1.1 @@ -32,8 +35,10 @@ router bgp 100 view 2 timers bgp 60 180 neighbor 172.16.1.3 remote-as 65003 neighbor 172.16.1.3 timers 3 10 + neighbor 172.16.1.3 timers connect 1 neighbor 172.16.1.4 remote-as 65004 neighbor 172.16.1.4 timers 3 10 + neighbor 172.16.1.4 timers connect 1 ! router bgp 100 view 3 bgp router-id 172.30.1.1 @@ -43,10 +48,13 @@ router bgp 100 view 3 timers bgp 60 180 neighbor 172.16.1.6 remote-as 65006 neighbor 172.16.1.6 timers 3 10 + neighbor 172.16.1.6 timers connect 1 neighbor 172.16.1.7 remote-as 65007 neighbor 172.16.1.7 timers 3 10 + neighbor 172.16.1.7 timers connect 1 neighbor 172.16.1.8 remote-as 65008 neighbor 172.16.1.8 timers 3 10 + neighbor 172.16.1.8 timers connect 1 ! route-map local1 permit 10 set community 100:9999 additive diff --git a/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf index 7efa1b79fa5d..06ac666ce6ea 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:2::9 remote-as internal neighbor fd00:0:2::9 timers 3 10 + neighbor fd00:0:2::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf index 4d4ae44e284b..4b696b51b38e 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:2::9 remote-as internal neighbor fd00:0:2::9 timers 3 10 + neighbor fd00:0:2::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf index b14c9bace4a6..081909bbb3f6 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65001 no bgp ebgp-requires-policy neighbor fd00:0:2::9 remote-as external neighbor fd00:0:2::9 timers 3 10 + neighbor fd00:0:2::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf index becea2bbe648..b8f9078f51e8 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65002 no bgp ebgp-requires-policy neighbor fd00:0:3::9 remote-as external neighbor fd00:0:3::9 timers 3 10 + neighbor fd00:0:3::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf index 801736ab988e..19c6bbc81948 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:4::9 remote-as internal neighbor fd00:0:4::9 timers 3 10 + neighbor fd00:0:4::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf index 705ae78b8e1e..1c8f2fa49edc 100644 --- a/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf @@ -2,16 +2,22 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:2::1 remote-as internal neighbor fd00:0:2::1 timers 3 10 + neighbor fd00:0:2::1 timers connect 1 neighbor fd00:0:2::2 remote-as internal neighbor fd00:0:2::2 timers 3 10 + neighbor fd00:0:2::2 timers connect 1 neighbor fd00:0:2::3 remote-as internal neighbor fd00:0:2::3 timers 3 10 + neighbor fd00:0:2::3 timers connect 1 neighbor fd00:0:2::4 remote-as external neighbor fd00:0:2::4 timers 3 10 + neighbor fd00:0:2::4 timers connect 1 neighbor fd00:0:3::5 remote-as external neighbor fd00:0:3::5 timers 3 10 + neighbor fd00:0:3::5 timers connect 1 neighbor fd00:0:4::6 remote-as internal neighbor fd00:0:4::6 timers 3 10 + neighbor fd00:0:4::6 timers connect 1 address-family ipv4 unicast neighbor fd00:0:2::1 route-reflector-client neighbor fd00:0:2::2 route-reflector-client diff --git a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py index e478139eb1e6..58daee32c3eb 100644 --- a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py +++ b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py @@ -36,7 +36,7 @@ def build_topo(tgen): - """ + r""" All peers are FRR BGP peers except r3 that is a exabgp peer. rr is a route-reflector for AS 65000 iBGP peers. Exabgp does not send any IPv6 Link-Local nexthop @@ -222,7 +222,6 @@ def test_bgp_ipv6_table_step1(): link_local_cache = {} router_list = tgen.routers().values() for router in router_list: - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -275,7 +274,6 @@ def test_bgp_ipv6_table_step2(): router_list = tgen.routers().values() for router in router_list: - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step2.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -327,7 +325,6 @@ def test_bgp_ipv6_table_step3(): router_list = tgen.routers().values() for router in router_list: - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) diff --git a/tests/topotests/bgp_path_attribute_discard/r1/frr.conf b/tests/topotests/bgp_path_attribute_discard/r1/frr.conf index ae7fbdd9a93a..ae47862963be 100644 --- a/tests/topotests/bgp_path_attribute_discard/r1/frr.conf +++ b/tests/topotests/bgp_path_attribute_discard/r1/frr.conf @@ -6,4 +6,5 @@ router bgp 65001 no bgp ebgp-requires-policy neighbor 10.0.0.254 remote-as external neighbor 10.0.0.254 timers 3 10 + neighbor 10.0.0.254 timers connect 1 ! diff --git a/tests/topotests/bgp_path_attribute_discard/r2/frr.conf b/tests/topotests/bgp_path_attribute_discard/r2/frr.conf index 1dafbdd8e19f..30ffdefff3f5 100644 --- a/tests/topotests/bgp_path_attribute_discard/r2/frr.conf +++ b/tests/topotests/bgp_path_attribute_discard/r2/frr.conf @@ -6,5 +6,6 @@ router bgp 65254 no bgp ebgp-requires-policy neighbor 10.0.0.254 remote-as internal neighbor 10.0.0.254 timers 3 10 + neighbor 10.0.0.254 timers connect 1 neighbor 10.0.0.254 path-attribute discard 26 ! diff --git a/tests/topotests/bgp_peer_group/r1/frr.conf b/tests/topotests/bgp_peer_group/r1/frr.conf index 035c8e4cf16e..cf9d16c91849 100644 --- a/tests/topotests/bgp_peer_group/r1/frr.conf +++ b/tests/topotests/bgp_peer_group/r1/frr.conf @@ -5,6 +5,9 @@ interface r1-eth0 interface r1-eth1 ip address 192.168.251.1/30 ! +interface r1-eth2 + ip address 192.168.252.1/30 +! ip forwarding ! router bgp 65001 @@ -17,5 +20,9 @@ router bgp 65001 neighbor PG1 remote-as external neighbor PG1 timers 3 20 neighbor PG1 graceful-restart-disable + neighbor PG2 peer-group + neighbor PG2 local-as 65554 no-prepend replace-as neighbor 192.168.251.2 peer-group PG1 + neighbor 192.168.252.2 remote-as 65004 + neighbor 192.168.252.2 peer-group PG2 ! diff --git a/tests/topotests/bgp_peer_group/r4/frr.conf b/tests/topotests/bgp_peer_group/r4/frr.conf new file mode 100644 index 000000000000..b1da90f0644e --- /dev/null +++ b/tests/topotests/bgp_peer_group/r4/frr.conf @@ -0,0 +1,7 @@ +! +interface r4-eth0 + ip address 192.168.252.2/30 +! +router bgp 65004 + neighbor 192.168.252.1 remote-as external +! diff --git a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py index 45f713b8a240..e98d5f8b3b07 100644 --- a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py @@ -30,7 +30,7 @@ def build_topo(tgen): - for routern in range(1, 4): + for routern in range(1, 5): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") @@ -42,6 +42,10 @@ def build_topo(tgen): switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) @@ -84,6 +88,11 @@ def _bgp_peer_group_configured(): "bgpState": "Established", "neighborCapabilities": {"gracefulRestart": "received"}, }, + "192.168.252.2": { + "peerGroup": "PG2", + "bgpState": "Established", + "neighborCapabilities": {"gracefulRestart": "advertisedAndReceived"}, + }, } return topotest.json_cmp(output, expected) @@ -110,6 +119,24 @@ def _bgp_peer_group_check_advertised_routes(): assert result is None, "Failed checking advertised routes from r3" +def test_show_running_remote_as_peer_group(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + output = ( + tgen.gears["r1"] + .cmd( + 'vtysh -c "show running bgpd" | grep "^ neighbor 192.168.252.2 remote-as 65004"' + ) + .rstrip() + ) + assert ( + output == " neighbor 192.168.252.2 remote-as 65004" + ), "192.168.252.2 remote-as is flushed" + + def test_bgp_peer_group_remote_as_del_readd(): tgen = get_topogen() diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf b/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf index 038f108aa8b2..e743010922f5 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf @@ -8,9 +8,17 @@ router bgp 64510 bgp bestpath compare-routerid bgp bestpath peer-type multipath-relax neighbor 10.0.1.2 remote-as 64510 + neighbor 10.0.1.2 timers 3 10 + neighbor 10.0.1.2 timers connect 1 neighbor 10.0.3.2 remote-as 64502 + neighbor 10.0.3.2 timers 3 10 + neighbor 10.0.3.2 timers connect 1 neighbor 10.0.4.2 remote-as 64503 + neighbor 10.0.4.2 timers 3 10 + neighbor 10.0.4.2 timers connect 1 neighbor 10.0.5.2 remote-as 64511 + neighbor 10.0.5.2 timers 3 10 + neighbor 10.0.5.2 timers connect 1 ! line vty ! diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf b/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf index 2362a19f265a..1da7173bba01 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf +++ b/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf @@ -7,7 +7,11 @@ router bgp 64511 bgp router-id 10.0.5.2 no bgp ebgp-requires-policy neighbor 10.0.2.2 remote-as 64511 + neighbor 10.0.2.2 timers 3 10 + neighbor 10.0.2.2 timers connect 1 neighbor 10.0.5.1 remote-as 64510 + neighbor 10.0.5.1 timers 3 10 + neighbor 10.0.5.1 timers connect 1 ! address-family ipv4 unicast neighbor 10.0.5.1 route-map dropall in diff --git a/tests/topotests/bgp_prefix_sid/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf index e02226f2fd64..3fd5e5e9c3cd 100644 --- a/tests/topotests/bgp_prefix_sid/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf @@ -7,8 +7,10 @@ router bgp 1 no bgp ebgp-requires-policy neighbor 10.0.0.101 remote-as 2 neighbor 10.0.0.101 timers 3 10 + neighbor 10.0.0.101 timers connect 1 neighbor 10.0.0.102 remote-as 3 neighbor 10.0.0.102 timers 3 10 + neighbor 10.0.0.102 timers connect 1 ! address-family ipv4 labeled-unicast neighbor 10.0.0.101 activate diff --git a/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf index b3ca0e114d17..946103c30fd2 100644 --- a/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf @@ -18,6 +18,7 @@ router bgp 1 no bgp ebgp-requires-policy neighbor 10.0.0.101 remote-as 2 neighbor 10.0.0.101 timers 3 10 + neighbor 10.0.0.101 timers connect 1 ! address-family ipv6 vpn neighbor 10.0.0.101 activate diff --git a/tests/topotests/bgp_route_server_client/r1/bgpd.conf b/tests/topotests/bgp_route_server_client/r1/bgpd.conf index e464e6c50b88..d379f7df4527 100644 --- a/tests/topotests/bgp_route_server_client/r1/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r1/bgpd.conf @@ -5,7 +5,7 @@ router bgp 65001 no bgp enforce-first-as neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 timers 3 10 - neighbor 2001:db8:1::1 timers connect 5 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:1::1 activate diff --git a/tests/topotests/bgp_route_server_client/r2/bgpd.conf b/tests/topotests/bgp_route_server_client/r2/bgpd.conf index 19607660f98f..7fda2b0a058f 100644 --- a/tests/topotests/bgp_route_server_client/r2/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r2/bgpd.conf @@ -3,16 +3,16 @@ router bgp 65000 view RS no bgp ebgp-requires-policy neighbor 2001:db8:1::2 remote-as external neighbor 2001:db8:1::2 timers 3 10 - neighbor 2001:db8:1::2 timers connect 5 + neighbor 2001:db8:1::2 timers connect 1 neighbor 2001:db8:1::3 remote-as external neighbor 2001:db8:1::3 timers 3 10 - neighbor 2001:db8:1::3 timers connect 5 + neighbor 2001:db8:1::3 timers connect 1 neighbor 2001:db8:1::4 remote-as external neighbor 2001:db8:1::4 timers 3 10 - neighbor 2001:db8:1::4 timers connect 5 + neighbor 2001:db8:1::4 timers connect 1 neighbor 2001:db8:3::2 remote-as external neighbor 2001:db8:3::2 timers 3 10 - neighbor 2001:db8:3::2 timers connect 5 + neighbor 2001:db8:3::2 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:1::2 activate diff --git a/tests/topotests/bgp_route_server_client/r3/bgpd.conf b/tests/topotests/bgp_route_server_client/r3/bgpd.conf index f7daba87face..2f20b9133499 100644 --- a/tests/topotests/bgp_route_server_client/r3/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r3/bgpd.conf @@ -5,7 +5,7 @@ router bgp 65003 no bgp enforce-first-as neighbor 2001:db8:3::1 remote-as external neighbor 2001:db8:3::1 timers 3 10 - neighbor 2001:db8:3::1 timers connect 5 + neighbor 2001:db8:3::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:3::1 activate diff --git a/tests/topotests/bgp_route_server_client/r4/bgpd.conf b/tests/topotests/bgp_route_server_client/r4/bgpd.conf index c907d7284e22..66a15730186f 100644 --- a/tests/topotests/bgp_route_server_client/r4/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r4/bgpd.conf @@ -5,7 +5,7 @@ router bgp 65004 no bgp enforce-first-as neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 timers 3 10 - neighbor 2001:db8:1::1 timers connect 5 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:1::1 activate diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py index a6334918dfcb..9dfeec6de0d6 100644 --- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -180,7 +180,6 @@ def test_bgp_route_server_client_step1(): else: cmd = "show bgp ipv6 unicast json" - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -230,7 +229,6 @@ def test_bgp_route_server_client_step2(): else: cmd = "show bgp ipv6 unicast json" - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step2.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -286,7 +284,6 @@ def test_bgp_route_server_client_step3(): else: cmd = "show bgp ipv6 unicast json" - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf index b598666dfb02..75d8c9e553b9 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 timers bgp 3 9 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf index 4a8579845c89..8e6743c5fd93 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf index e388ccba8a75..37d40651c533 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 bgp router-id 192.168.200.10 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf index 5e0aa5d3f038..02afea1148b7 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf index e388ccba8a75..37d40651c533 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 bgp router-id 192.168.200.10 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf index fabc11e84d79..714f1ec356f0 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf index e388ccba8a75..37d40651c533 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 bgp router-id 192.168.200.10 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf index e369f41b39e9..d5efab4bf6f4 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf index 098e55d0ed34..b80a90ac7d1e 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65000 bgp router-id 10.1.1.1 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf index 4fec8af3dbeb..87cffebd8437 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf index e43399559377..162f5bbccc47 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf index 2a834c799ef2..1f44feb0da59 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65000 bgp router-id 10.4.4.4 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf index 14580e5b3a36..7b0719d266f1 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_bmp_vrf/__init__.py b/tests/topotests/bgp_vpnv4_import_allowas_in/__init__.py similarity index 100% rename from tests/topotests/bgp_bmp_vrf/__init__.py rename to tests/topotests/bgp_vpnv4_import_allowas_in/__init__.py diff --git a/tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf b/tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf new file mode 100644 index 000000000000..30d11627f538 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf @@ -0,0 +1,30 @@ +! +interface r1-eth0 + ip address 192.168.179.4/24 +exit +! +router bgp 65001 + bgp router-id 192.168.179.4 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.179.5 remote-as auto +! + address-family ipv4 vpn + neighbor 192.168.179.5 activate + neighbor 192.168.179.5 next-hop-self + neighbor 192.168.179.5 allowas-in 1 + exit-address-family +! +router bgp 65001 vrf CUSTOMER-A + bgp router-id 192.168.0.1 + no bgp ebgp-requires-policy + no bgp network import-check +! + address-family ipv4 unicast + label vpn export auto + rd vpn export 100:1 + rt vpn both 100:1 + export vpn + import vpn + exit-address-family + diff --git a/tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf b/tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf new file mode 100644 index 000000000000..bbfd2c22f4fe --- /dev/null +++ b/tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf @@ -0,0 +1,40 @@ +! +interface lo + ip address 10.10.10.10/32 +! +interface r2-eth0 + ip address 192.168.179.5/24 +exit +! +interface r2-eth1 + ip address 192.168.2.2/24 +exit +! +router bgp 65002 + bgp router-id 192.168.179.5 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.179.4 remote-as auto +! + address-family ipv4 vpn + neighbor 192.168.179.4 activate + neighbor 192.168.179.4 next-hop-self + exit-address-family +! +router bgp 65002 vrf CUSTOMER-A + bgp router-id 192.168.0.2 + no bgp ebgp-requires-policy + no bgp network import-check +! + address-family ipv4 unicast + redistribute connected + network 10.10.10.10/32 route-map r1 + label vpn export auto + rd vpn export 100:1 + rt vpn both 100:1 + export vpn + import vpn + exit-address-family +! +route-map r1 permit 10 + set as-path prepend 65001 diff --git a/tests/topotests/bgp_vpnv4_import_allowas_in/test_bgp_vpnv4_import_allowas_in.py b/tests/topotests/bgp_vpnv4_import_allowas_in/test_bgp_vpnv4_import_allowas_in.py new file mode 100644 index 000000000000..f3d016cb179b --- /dev/null +++ b/tests/topotests/bgp_vpnv4_import_allowas_in/test_bgp_vpnv4_import_allowas_in.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + r1.run("ip link add CUSTOMER-A type vrf table 1001") + r1.run("ip link set up dev CUSTOMER-A") + r1.run("ip link set r1-eth1 master CUSTOMER-A") + + r2.run("ip link add CUSTOMER-A type vrf table 1001") + r2.run("ip link set up dev CUSTOMER-A") + r2.run("ip link set r2-eth1 master CUSTOMER-A") + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_issue_12502(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads( + r1.vtysh_cmd("show bgp vrf CUSTOMER-A ipv4 unicast 10.10.10.10/32 json") + ) + expected = { + "paths": [ + { + "importedFrom": "100:1", + "aspath": { + "string": "65002 65001", + }, + "valid": True, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see 192.168.2.0/24 with a valid next-hop" + + def _vrf_route_imported_to_zebra(): + output = json.loads( + r1.vtysh_cmd("show ip route vrf CUSTOMER-A 10.10.10.10/32 json") + ) + expected = { + "10.10.10.10/32": [ + { + "protocol": "bgp", + "vrfName": "CUSTOMER-A", + "selected": True, + "installed": True, + "table": 1001, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": True, + "ip": "192.168.179.5", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "vrf": "default", + "active": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_vrf_route_imported_to_zebra) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "Failed to see 10.10.10.10/32 to be imported into default VRF (Zebra)" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf index 572dce745574..2853a7a5caa2 100644 --- a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf @@ -5,6 +5,7 @@ router bgp 100 vrf r1-bgp-cust1 no bgp ebgp-requires-policy neighbor 10.0.1.101 remote-as 99 neighbor 10.0.1.101 timers 3 10 + neighbor 10.0.1.101 timers connect 1 ! ! diff --git a/tests/topotests/docker/build.sh b/tests/topotests/docker/build.sh index aec20587ba39..20d08e4979f2 100755 --- a/tests/topotests/docker/build.sh +++ b/tests/topotests/docker/build.sh @@ -1,11 +1,11 @@ -#!/bin/bash +#!/usr/bin/env bash # SPDX-License-Identifier: MIT # # Copyright 2018 Network Device Education Foundation, Inc. ("NetDEF") cd "$(dirname "$0")"/.. -exec docker build --pull \ +exec $(command -v docker || command -v podman) build --pull \ --compress \ -t frrouting/topotests:latest \ . diff --git a/tests/topotests/docker/frr-topotests.sh b/tests/topotests/docker/frr-topotests.sh index bd37055147a7..8de8e7b1f676 100755 --- a/tests/topotests/docker/frr-topotests.sh +++ b/tests/topotests/docker/frr-topotests.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # SPDX-License-Identifier: MIT # # Copyright 2018 Network Device Education Foundation, Inc. ("NetDEF") @@ -113,10 +113,12 @@ if [ -z "$TOPOTEST_FRR" ]; then git -C "$TOPOTEST_FRR" ls-files -z > "${TOPOTEST_LOGS}/git-ls-files" fi +cmd="$(command -v docker || command -v podman)" + if [ -z "$TOPOTEST_BUILDCACHE" ]; then TOPOTEST_BUILDCACHE=topotest-buildcache - docker volume inspect "${TOPOTEST_BUILDCACHE}" &> /dev/null \ - || docker volume create "${TOPOTEST_BUILDCACHE}" + "${cmd}" volume inspect "${TOPOTEST_BUILDCACHE}" &> /dev/null \ + || "${cmd}" volume create "${TOPOTEST_BUILDCACHE}" fi if [[ -n "$TMUX" ]]; then @@ -145,4 +147,4 @@ if [ -t 0 ]; then set -- -t "$@" fi -exec docker run "$@" +exec "${cmd}" run "$@" diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index bcd1c748120f..329c2b54f568 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -5638,3 +5638,22 @@ def configure_bgp_soft_configuration(tgen, dut, neighbor_dict, direction): ) ) return True + + +def bgp_configure_prefixes(router, asn, safi, prefixes, vrf=None, update=True): + """ + Configure the bgp prefixes. + """ + withdraw = "no " if not update else "" + vrf = " vrf {}".format(vrf) if vrf else "" + for p in prefixes: + ip = ipaddress.ip_network(p) + cmd = [ + "conf t\n", + f"router bgp {asn}{vrf}\n" + f"address-family ipv{ip.version} {safi}\n" + f"{withdraw}network {ip}\n".format(withdraw, ip), + "exit-address-family\n", + ] + logger.debug(f"setting prefix: ipv{ip.version} {safi} {ip}") + router.vtysh_cmd("".join(cmd)) diff --git a/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py b/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py index 3694cb4fe3df..ca49c405d147 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py @@ -72,6 +72,12 @@ def dissect(cls, data): if path_attr_cls == cls.UNKNOWN_ATTR: return data[offset + attr_len :], None + # RFC1771, 4.3 UPDATE Message Format + # The path segment length is a 1-octet long field containing + # the number of ASs in the path segment value field. + if type_code == PATH_ATTR_TYPE_AS_PATH and attr_len == 0: + return data[offset:], path_attr_cls.dissect(data[offset : offset + 2]) + return data[offset + attr_len :], path_attr_cls.dissect( data[offset : offset + attr_len] ) diff --git a/tests/topotests/lib/bmp_collector/bmpserver b/tests/topotests/lib/bmp_collector/bmpserver.py similarity index 58% rename from tests/topotests/lib/bmp_collector/bmpserver rename to tests/topotests/lib/bmp_collector/bmpserver.py index 56d85fc74b30..c42c3875633f 100755 --- a/tests/topotests/lib/bmp_collector/bmpserver +++ b/tests/topotests/lib/bmp_collector/bmpserver.py @@ -5,8 +5,11 @@ # Authored by Farid Mihoub # import argparse +import errno +import logging # XXX: something more reliable should be used "Twisted" a great choice. +import os import signal import socket import sys @@ -20,11 +23,11 @@ # Global variable to track shutdown signal shutdown = False - parser = argparse.ArgumentParser() parser.add_argument("-a", "--address", type=str, default="0.0.0.0") parser.add_argument("-p", "--port", type=int, default=1789) parser.add_argument("-l", "--logfile", type=str, default="/var/log/bmp.log") +parser.add_argument("-r", "--pidfile", type=str, default="/var/run/bmp.pid") def handle_signal(signum, frame): @@ -40,6 +43,74 @@ def timestamp_print(message, file=sys.stderr): print(f"[{current_time}] {message}", file=file) +def check_pid(pid): + if pid < 0: # user input error + return False + if pid == 0: # all processes + return False + try: + os.kill(pid, 0) + return True + except OSError as err: + if err.errno == errno.EPERM: # a process we were denied access to + return True + if err.errno == errno.ESRCH: # No such process + return False + # should never happen + return False + + +def savepid(): + ownid = os.getpid() + + flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY + mode = ((os.R_OK | os.W_OK) << 6) | (os.R_OK << 3) | os.R_OK + + try: + fd = os.open(pid_file, flags, mode) + except OSError: + try: + pid = open(pid_file, "r").readline().strip() + if check_pid(int(pid)): + timestamp_print( + "PID file already exists and program still running %s\n" % pid_file + ) + return False + else: + # If pid is not running, reopen file without O_EXCL + fd = os.open(pid_file, flags ^ os.O_EXCL, mode) + except (OSError, IOError, ValueError): + timestamp_print( + "issue accessing PID file %s (most likely permission or ownership)\n" + % pid_file + ) + return False + + try: + f = os.fdopen(fd, "w") + line = "%d\n" % ownid + f.write(line) + f.close() + saved_pid = True + except IOError: + timestamp_print("Can not create PID file %s\n" % pid_file) + return False + timestamp_print("Created PID file %s with value %d\n" % (pid_file, ownid)) + return True + + +def removepid(): + try: + os.remove(pid_file) + except OSError as exc: + if exc.errno == errno.ENOENT: + pass + else: + timestamp_print("Can not remove PID file %s\n" % pid_file) + return + timestamp_print("Removed PID file %s\n" % pid_file) + + def main(): global shutdown @@ -51,8 +122,13 @@ def main(): ADDRESS, PORT = args.address, args.port LOG_FILE = args.logfile + global pid_file + pid_file = args.pidfile + timestamp_print(f"Starting bmpserver on {args.address}:{args.port}") + savepid() + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: @@ -80,9 +156,7 @@ def main(): while len(data) > BMPMsg.MIN_LEN: data = BMPMsg.dissect(data, log_file=LOG_FILE) - timestamp_print( - f"Finished dissecting data from {client_address}" - ) + timestamp_print(f"Finished dissecting data from {client_address}") except Exception as e: timestamp_print(f"{e}") @@ -99,6 +173,7 @@ def main(): timestamp_print(f"{e}") finally: timestamp_print(f"Server shutting down on {ADDRESS}:{PORT}") + removepid() if __name__ == "__main__": @@ -106,4 +181,5 @@ def main(): sys.exit(main()) except KeyboardInterrupt: logging.info("BMP server was interrupted and is shutting down.") + removepid() sys.exit(0) diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 4d7c56423e36..0a9a84a4bb07 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -1293,18 +1293,19 @@ def start(self, log_file=None): log_err = os.path.join(log_dir, "bmpserver.log") log_arg = "-l {}".format(log_file) if log_file else "" + self.pid_file = os.path.join(log_dir, "bmpserver.pid") with open(log_err, "w") as err: self.run( - "{}/bmp_collector/bmpserver -a {} -p {} {}&".format( - CWD, self.ip, self.port, log_arg + "{}/bmp_collector/bmpserver.py -a {} -p {} -r {} {}&".format( + CWD, self.ip, self.port, self.pid_file, log_arg ), stdout=None, stderr=err, ) def stop(self): - self.run("pkill -f bmpserver") + self.run(f"kill $(cat {self.pid_file}") return "" diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 1c97f7cb1e47..5143ef67a517 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -511,6 +511,42 @@ def test_msdp_sa_filter(): assert val is None, "multicast route convergence failure" +def test_msdp_sa_limit(): + "Test MSDP SA limiting." + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r4"].vtysh_cmd( + """ + configure terminal + router pim + msdp log sa-events + msdp peer 192.168.2.1 sa-limit 4 + msdp peer 192.168.3.1 sa-limit 4 + """ + ) + + # Flow from r1 -> r4 + for multicast_address in [ + "229.1.2.10", + "229.1.2.11", + "229.1.2.12", + "229.1.2.13", + "229.1.2.14", + ]: + app_helper.run("h1", [multicast_address, "h1-eth0"]) + app_helper.run("h2", ["--send=0.7", multicast_address, "h2-eth0"]) + + def test_sa_limit_log(): + r4_log = tgen.gears["r4"].net.getLog("log", "pimd") + return re.search(r"MSDP peer .+ reject SA (.+, .+): SA limit \d+ of 4", r4_log) + + _, val = topotest.run_and_expect(test_sa_limit_log, None, count=30, wait=1) + assert val is None, "SA limit check failed" + + def test_msdp_log_events(): "Test that the enabled logs are working as expected." @@ -521,15 +557,58 @@ def test_msdp_log_events(): r1_log = tgen.gears["r1"].net.getLog("log", "pimd") # Look up for informational messages that should have been enabled. - match = re.search( - "MSDP peer 192.168.1.2 state changed to established", r1_log) + match = re.search("MSDP peer 192.168.1.2 state changed to established", r1_log) assert match is not None - match = re.search( - r"MSDP SA \(192.168.10.100\,229.1.2.3\) created", r1_log) + match = re.search(r"MSDP SA \(192.168.10.100\,229.1.2.3\) created", r1_log) assert match is not None +def test_msdp_shutdown(): + "Shutdown MSDP sessions between r1, r2, r3, then check the state." + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + router pim + msdp shutdown + """ + ) + + r1_expect = { + "192.168.0.2": { + "state": "inactive", + }, + "192.168.1.2": { + "state": "inactive", + }, + } + r2_expect = { + "192.168.0.1": { + "state": "listen", + } + } + r3_expect = { + "192.168.1.1": { + "state": "listen", + } + } + for router in [("r1", r1_expect), ("r2", r2_expect), ("r3", r3_expect)]: + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router[0]], + "show ip msdp peer json", + router[1], + ) + logger.info("Waiting for {} msdp peer data".format(router[0])) + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/msdp_topo3/__init__.py b/tests/topotests/msdp_topo3/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/msdp_topo3/r1/frr.conf b/tests/topotests/msdp_topo3/r1/frr.conf new file mode 100644 index 000000000000..d5b10bf8a15b --- /dev/null +++ b/tests/topotests/msdp_topo3/r1/frr.conf @@ -0,0 +1,31 @@ +log commands +! +interface r1-eth0 + ip address 192.168.1.1/24 + ip pim +! +interface r1-eth1 + ip address 192.168.100.1/24 + ip igmp + ip pim passive +! +interface lo + ip address 10.254.254.1/32 + ip pim + ip pim use-source 10.254.254.1 +! +router bgp 65100 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as 65200 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! +router pim + msdp originator-id 10.254.254.1 + msdp log sa-events + msdp peer 192.168.1.2 source 192.168.1.1 + rp 192.168.1.1 +! \ No newline at end of file diff --git a/tests/topotests/msdp_topo3/r2/frr.conf b/tests/topotests/msdp_topo3/r2/frr.conf new file mode 100644 index 000000000000..245c06187404 --- /dev/null +++ b/tests/topotests/msdp_topo3/r2/frr.conf @@ -0,0 +1,28 @@ +log commands +! +interface r2-eth0 + ip address 192.168.1.2/24 + ip pim +! +interface r2-eth1 + ip address 192.168.101.1/24 + ip igmp + ip pim passive +! +interface lo + ip address 10.254.254.2/32 +! +router bgp 65200 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as 65100 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! +router pim + msdp log sa-events + msdp peer 192.168.1.1 source 192.168.1.2 + rp 192.168.1.2 +! \ No newline at end of file diff --git a/tests/topotests/msdp_topo3/test_msdp_topo3.py b/tests/topotests/msdp_topo3/test_msdp_topo3.py new file mode 100644 index 000000000000..9393ae7ffdde --- /dev/null +++ b/tests/topotests/msdp_topo3/test_msdp_topo3.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_msdp_topo3.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2024 by +# Network Device Education Foundation, Inc. ("NetDEF") +# + +""" +test_msdp_topo3.py: Test the FRR PIM MSDP peer. +""" + +import os +import sys +import json +from functools import partial +import re +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from lib.pim import McastTesterHelper + +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] + +app_helper = McastTesterHelper() + + +def build_topo(tgen): + """ + +----+ +----+ +----+ +----+ + | h1 | <-> | r1 | <-> | r2 | <-> | h2 | + +----+ +----+ +----+ +----+ + + --------------------------> + + Multicast traffic SG(192.168.100.100, 229.1.1.1) + """ + + # Create 2 routers + for routern in range(1, 3): + tgen.add_router(f"r{routern}") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + # Create a host connected and direct at r1: + switch = tgen.add_switch("s2") + tgen.add_host("h1", "192.168.100.100/24", "via 192.168.100.1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["h1"]) + + # Create a host connected and direct at r2: + switch = tgen.add_switch("s3") + tgen.add_host("h2", "192.168.101.100/24", "via 192.168.101.1") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["h2"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for _, router in router_list.items(): + router.load_frr_config(os.path.join(CWD, f"{router.name}/frr.conf")) + + # Initialize all routers. + tgen.start_router() + + app_helper.init(tgen) + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + app_helper.cleanup() + tgen.stop_topology() + + +def test_bgp_convergence(): + "Wait for BGP protocol convergence" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for protocols to converge") + + def expect_loopback_route(router, iptype, route, proto): + "Wait until route is present on RIB for protocol." + logger.info("waiting route {} in {}".format(route, router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show {} route json".format(iptype), + {route: [{"protocol": proto}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + # Wait for R1 + expect_loopback_route("r1", "ip", "10.254.254.2/32", "bgp") + + # Wait for R2 + expect_loopback_route("r2", "ip", "10.254.254.1/32", "bgp") + + +def test_sa_learn(): + """ + Test that the learned SA uses the configured originator ID instead + of the configured RP. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + MCAST_ADDRESS = "229.1.1.1" + app_helper.run("h1", ["--send=0.7", MCAST_ADDRESS, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDRESS, "h2-eth0"]) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r2"], + "show ip msdp sa json", + { + "229.1.1.1": { + "192.168.100.100": { + "rp": "10.254.254.1", + "local": "no", + } + } + } + ) + _, result = topotest.run_and_expect(test_func, None, count=100, wait=1) + assert result is None, 'r2 SA convergence failure' + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_metric_propagation/h1/frr.conf b/tests/topotests/ospf_metric_propagation/h1/frr.conf index 1196a192dd50..b8d1834e24ca 100644 --- a/tests/topotests/ospf_metric_propagation/h1/frr.conf +++ b/tests/topotests/ospf_metric_propagation/h1/frr.conf @@ -1,10 +1,8 @@ ! hostname h1 -password zebra -log file /tmp/h1-frr.log ! ip route 0.0.0.0/0 10.0.91.1 ! interface h1-eth0 ip address 10.0.91.2/24 -! \ No newline at end of file +! diff --git a/tests/topotests/ospf_metric_propagation/h2/frr.conf b/tests/topotests/ospf_metric_propagation/h2/frr.conf index f951fe6ba1d6..4377256261b3 100644 --- a/tests/topotests/ospf_metric_propagation/h2/frr.conf +++ b/tests/topotests/ospf_metric_propagation/h2/frr.conf @@ -1,10 +1,8 @@ ! hostname h2 -password zebra -log file /tmp/h2-frr.log ! ip route 0.0.0.0/0 10.0.94.4 ! interface h2-eth0 ip address 10.0.94.2/24 -! \ No newline at end of file +! diff --git a/tests/topotests/ospf_metric_propagation/r1/frr.conf b/tests/topotests/ospf_metric_propagation/r1/frr.conf index 4966e6a9da1b..082f7df51936 100644 --- a/tests/topotests/ospf_metric_propagation/r1/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r1/frr.conf @@ -1,8 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r1-eth0 ip address 10.0.1.1/24 @@ -93,4 +90,4 @@ route-map costplus permit 30 route-map costplus permit 40 set metric-type type-1 set metric +1 - exit \ No newline at end of file + exit diff --git a/tests/topotests/ospf_metric_propagation/r2/frr.conf b/tests/topotests/ospf_metric_propagation/r2/frr.conf index 0ac5001b1b99..e6ced31d876e 100644 --- a/tests/topotests/ospf_metric_propagation/r2/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r2/frr.conf @@ -1,8 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log -ip forwarding ! interface r2-eth0 ip address 10.0.1.2/24 diff --git a/tests/topotests/ospf_metric_propagation/r3/frr.conf b/tests/topotests/ospf_metric_propagation/r3/frr.conf index 0859173f7971..f6989057f66a 100644 --- a/tests/topotests/ospf_metric_propagation/r3/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r3/frr.conf @@ -1,8 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log -ip forwarding ! interface r3-eth0 ip address 10.0.3.3/24 diff --git a/tests/topotests/ospf_metric_propagation/r4/frr.conf b/tests/topotests/ospf_metric_propagation/r4/frr.conf index 743da272727f..b02ae18fc147 100644 --- a/tests/topotests/ospf_metric_propagation/r4/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r4/frr.conf @@ -1,8 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log -ip forwarding ! interface r4-eth0 ip address 10.0.3.4/24 diff --git a/tests/topotests/ospf_metric_propagation/ra/frr.conf b/tests/topotests/ospf_metric_propagation/ra/frr.conf index 2434faeabc97..5ad819da01bb 100644 --- a/tests/topotests/ospf_metric_propagation/ra/frr.conf +++ b/tests/topotests/ospf_metric_propagation/ra/frr.conf @@ -1,8 +1,5 @@ ! hostname ra -password zebra -log file /tmp/ra-frr.log -ip forwarding ! interface ra-eth0 ip address 10.0.50.5/24 diff --git a/tests/topotests/ospf_metric_propagation/rb/frr.conf b/tests/topotests/ospf_metric_propagation/rb/frr.conf index b83532a8405a..21abefed2604 100644 --- a/tests/topotests/ospf_metric_propagation/rb/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rb/frr.conf @@ -1,8 +1,5 @@ ! hostname rb -password zebra -log file /tmp/rb-frr.log -ip forwarding ! interface rb-eth0 ip address 10.0.50.6/24 diff --git a/tests/topotests/ospf_metric_propagation/rc/frr.conf b/tests/topotests/ospf_metric_propagation/rc/frr.conf index dd8077c3949f..0e6edd92a830 100644 --- a/tests/topotests/ospf_metric_propagation/rc/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rc/frr.conf @@ -1,8 +1,5 @@ ! hostname rc -password zebra -log file /tmp/rc-frr.log -ip forwarding ! interface rc-eth0 ip address 10.0.70.7/24 diff --git a/tests/topotests/ospf_multi_instance/r1/frr.conf b/tests/topotests/ospf_multi_instance/r1/frr.conf index c341a7176a09..b9752c63ad96 100644 --- a/tests/topotests/ospf_multi_instance/r1/frr.conf +++ b/tests/topotests/ospf_multi_instance/r1/frr.conf @@ -1,8 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ospf_multi_instance/r3/frr.conf b/tests/topotests/ospf_multi_instance/r3/frr.conf index 97a3e19c9b10..e6f681a46206 100644 --- a/tests/topotests/ospf_multi_instance/r3/frr.conf +++ b/tests/topotests/ospf_multi_instance/r3/frr.conf @@ -1,8 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log -ip forwarding ! interface lo ip address 3.3.3.1/32 diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf index 995958132c93..bcbe2eded6c6 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ! interface r1-eth0 ip address 10.0.1.1/24 diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf index 29909de6461d..0d3eb3c8c915 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log ! interface r2-eth0 ip address 10.0.2.2/24 diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf index 35fe22e9f9bc..1cc2972f0133 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log ! interface r3-eth0 ip address 10.0.3.3/24 diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf index 721c3d91c388..a82d5b033cf1 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf @@ -1,7 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log ! interface r4-eth0 ip address 10.0.4.4/24 diff --git a/tests/topotests/ospf_netns_vrf/r1/ospfd.conf b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf index ba131465612b..75f38d0058cb 100644 --- a/tests/topotests/ospf_netns_vrf/r1/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-ospfd.log ! interface r1-eth0 vrf r1-ospf-cust1 ip ospf hello-interval 1 diff --git a/tests/topotests/ospf_netns_vrf/r1/zebra.conf b/tests/topotests/ospf_netns_vrf/r1/zebra.conf index 56d7a9764e01..1c08f1e26333 100644 --- a/tests/topotests/ospf_netns_vrf/r1/zebra.conf +++ b/tests/topotests/ospf_netns_vrf/r1/zebra.conf @@ -4,8 +4,6 @@ ! debug zebra event ! hostname r1 -password zebra -log file /tmp/r1-zebra.log ! interface r1-eth0 vrf r1-ospf-cust1 ip address 10.0.1.1/24 diff --git a/tests/topotests/ospf_netns_vrf/r2/ospfd.conf b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf index 01b6b1526b1c..3cd69bb8ff15 100644 --- a/tests/topotests/ospf_netns_vrf/r2/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-ospfd.log ! interface r2-eth0 vrf r2-ospf-cust1 ip ospf hello-interval 1 diff --git a/tests/topotests/ospf_netns_vrf/r2/zebra.conf b/tests/topotests/ospf_netns_vrf/r2/zebra.conf index 6ff72d1267f6..f997028c740c 100644 --- a/tests/topotests/ospf_netns_vrf/r2/zebra.conf +++ b/tests/topotests/ospf_netns_vrf/r2/zebra.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-zebra.log ! interface r2-eth0 vrf r2-ospf-cust1 ip address 10.0.2.1/24 diff --git a/tests/topotests/ospf_netns_vrf/r3/ospfd.conf b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf index abfaa5b9eff1..4581a609b486 100644 --- a/tests/topotests/ospf_netns_vrf/r3/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-ospfd.log ! ! interface r3-eth0 vrf r3-ospf-cust1 diff --git a/tests/topotests/ospf_netns_vrf/r3/zebra.conf b/tests/topotests/ospf_netns_vrf/r3/zebra.conf index 15341500480a..4053d94a63e5 100644 --- a/tests/topotests/ospf_netns_vrf/r3/zebra.conf +++ b/tests/topotests/ospf_netns_vrf/r3/zebra.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-zebra.log ! interface r3-eth0 vrf r3-ospf-cust1 ip address 10.0.3.1/24 diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf index ca84349cdcf2..fdc75633b1a5 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r1-eth0 ip address 10.1.0.1/24 diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf index 89f255bb44ea..350c0de7baf6 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf @@ -1,13 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all hostname r1 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r1-eth0 diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf index 6e26897c494b..c44e936f9d99 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r2-eth0 ip address 10.1.0.2/24 diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf index 429330987e06..806914d81421 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf @@ -1,14 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all ! hostname r2 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r2-eth0 ip address 10.1.0.2/24 diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf index a69e0557bee7..d89269b3244f 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r3-eth0 ip address 10.1.0.3/24 diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf index eada78450e81..343a9d008627 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf @@ -1,14 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all ! hostname r3 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r3-eth0 ip address 10.1.0.3/24 diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf index 1b8388584b82..aa6c80d41e2b 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r4-eth0 ip address 10.1.0.4/24 diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf index 3146ea095762..a1527f5aa989 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf @@ -1,14 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all ! hostname r4 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r4-eth0 ip address 10.1.0.4/24 diff --git a/tests/topotests/ospf_prefix_suppression/r1/frr.conf b/tests/topotests/ospf_prefix_suppression/r1/frr.conf index 437b4741533a..4b9df834bf89 100644 --- a/tests/topotests/ospf_prefix_suppression/r1/frr.conf +++ b/tests/topotests/ospf_prefix_suppression/r1/frr.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r1-eth0 diff --git a/tests/topotests/ospf_prefix_suppression/r2/frr.conf b/tests/topotests/ospf_prefix_suppression/r2/frr.conf index 68390f15f12b..cf4a25a09af5 100644 --- a/tests/topotests/ospf_prefix_suppression/r2/frr.conf +++ b/tests/topotests/ospf_prefix_suppression/r2/frr.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r2-eth0 diff --git a/tests/topotests/ospf_prefix_suppression/r3/frr.conf b/tests/topotests/ospf_prefix_suppression/r3/frr.conf index 984a39d989c6..dbd1bc375f16 100644 --- a/tests/topotests/ospf_prefix_suppression/r3/frr.conf +++ b/tests/topotests/ospf_prefix_suppression/r3/frr.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r3-eth0 diff --git a/tests/topotests/pim_autorp/r1/frr.conf b/tests/topotests/pim_autorp/r1/frr.conf index 92b9b3b41b22..fc4e634452ad 100644 --- a/tests/topotests/pim_autorp/r1/frr.conf +++ b/tests/topotests/pim_autorp/r1/frr.conf @@ -1,9 +1,7 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ! -debug pim autorp +!debug pim autorp ! interface r1-eth0 ip address 10.0.0.1/24 @@ -23,4 +21,4 @@ ip route 10.0.3.0/24 10.0.0.2 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! diff --git a/tests/topotests/pim_autorp/r2/frr.conf b/tests/topotests/pim_autorp/r2/frr.conf index d67dade6f95f..ded462cad184 100644 --- a/tests/topotests/pim_autorp/r2/frr.conf +++ b/tests/topotests/pim_autorp/r2/frr.conf @@ -1,9 +1,7 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log ! -debug pim autorp +!debug pim autorp ! interface r2-eth0 ip address 10.0.0.2/24 @@ -23,4 +21,4 @@ ip route 10.0.3.0/24 10.0.2.4 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! diff --git a/tests/topotests/pim_autorp/r3/frr.conf b/tests/topotests/pim_autorp/r3/frr.conf index 4e93d4ba211d..31726f2c015c 100644 --- a/tests/topotests/pim_autorp/r3/frr.conf +++ b/tests/topotests/pim_autorp/r3/frr.conf @@ -1,9 +1,7 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log ! -debug pim autorp +!debug pim autorp ! interface r3-eth0 ip address 10.0.1.3/24 @@ -23,4 +21,4 @@ ip route 10.0.2.0/24 10.0.3.4 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! diff --git a/tests/topotests/pim_autorp/r4/frr.conf b/tests/topotests/pim_autorp/r4/frr.conf index 382999b11943..9d37da99aa7b 100644 --- a/tests/topotests/pim_autorp/r4/frr.conf +++ b/tests/topotests/pim_autorp/r4/frr.conf @@ -1,9 +1,7 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log ! -debug pim autorp +!debug pim autorp ! interface r4-eth0 ip address 10.0.2.4/24 @@ -23,4 +21,4 @@ ip route 10.0.1.0/24 10.0.2.2 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py index ce1abe42bb09..74d5406970fe 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -132,14 +132,14 @@ def test_pim_send_mcast_stream(): # Let's establish a S,G stream from r2 -> r1 CWD = os.path.dirname(os.path.realpath(__file__)) r2.run( - "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r2-eth0 > /tmp/bar".format( - CWD + "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r2-eth0 > {}/r2/mcast_tx_output".format( + CWD, tgen.logdir ) ) # And from r3 -> r1 r3.run( - "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r3-eth0 > /tmp/bar".format( - CWD + "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r3-eth0 > {}/r3/mcast_tx_output".format( + CWD, tgen.logdir ) ) diff --git a/tests/topotests/pim_boundary_acl/r1/frr.conf b/tests/topotests/pim_boundary_acl/r1/frr.conf new file mode 100644 index 000000000000..cc639b304b37 --- /dev/null +++ b/tests/topotests/pim_boundary_acl/r1/frr.conf @@ -0,0 +1,39 @@ +hostname r1 +! +!debug pim events +!debug igmp events +!debug igmp packets +! +ip prefix-list pim-oil-plist seq 10 deny 229.1.1.0/24 +ip prefix-list pim-oil-plist seq 20 permit any +! +access-list pim-acl seq 10 deny ip host 10.0.20.2 232.1.1.0 0.0.0.255 +access-list pim-acl seq 20 permit ip any any +! +interface r1-eth0 + ip address 10.0.20.1/24 + ip igmp + ip pim +! +interface r1-eth1 + ip address 10.0.30.1/24 + ip pim +! +interface r1-eth2 + ip address 10.0.40.1/24 + ip igmp + ip pim +! +interface lo + ip address 10.254.0.1/32 + ip pim +! +router pim + rp 10.254.0.3 + join-prune-interval 5 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 10.0.30.3 remote-as external + neighbor 10.0.30.3 timers 3 10 + redistribute connected diff --git a/tests/topotests/pim_boundary_acl/r2/frr.conf b/tests/topotests/pim_boundary_acl/r2/frr.conf new file mode 100644 index 000000000000..10ace947b2bc --- /dev/null +++ b/tests/topotests/pim_boundary_acl/r2/frr.conf @@ -0,0 +1,19 @@ +hostname r2 +! +!debug pim events +!debug igmp events +!debug igmp packets +! +ip prefix-list pim-oil-plist seq 10 deny 229.1.1.0/24 +ip prefix-list pim-oil-plist seq 20 permit any +! +access-list pim-acl seq 10 deny ip host 10.0.20.2 232.1.1.0 0.0.0.255 +access-list pim-acl seq 20 permit ip any any +! +interface r2-eth0 + ip address 10.0.20.2/24 + ip pim +! +interface lo + ip address 10.254.0.2/32 +! diff --git a/tests/topotests/pim_boundary_acl/r3/frr.conf b/tests/topotests/pim_boundary_acl/r3/frr.conf new file mode 100644 index 000000000000..972077426643 --- /dev/null +++ b/tests/topotests/pim_boundary_acl/r3/frr.conf @@ -0,0 +1,13 @@ +hostname r3 +! +!debug pim events +!debug igmp events +!debug igmp packets +! +interface r3-eth0 + ip address 10.0.40.4/24 + ip pim +! +interface lo + ip address 10.254.0.4/32 +! diff --git a/tests/topotests/pim_boundary_acl/rp/frr.conf b/tests/topotests/pim_boundary_acl/rp/frr.conf new file mode 100644 index 000000000000..f6eed2391705 --- /dev/null +++ b/tests/topotests/pim_boundary_acl/rp/frr.conf @@ -0,0 +1,22 @@ +hostname rp +! +interface rp-eth0 + ip address 10.0.30.3/24 + ip pim +! +interface lo + ip address 10.254.0.3/32 + ip pim +! +router pim + rp 10.254.0.3 + join-prune-interval 5 + register-accept-list ACCEPT +! +ip prefix-list ACCEPT seq 5 permit 10.0.20.0/24 le 32 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 10.0.30.1 remote-as external + neighbor 10.0.30.1 timers 3 10 + redistribute connected \ No newline at end of file diff --git a/tests/topotests/pim_boundary_acl/test_pim_boundary_acl.py b/tests/topotests/pim_boundary_acl/test_pim_boundary_acl.py new file mode 100644 index 000000000000..1488e610c8ce --- /dev/null +++ b/tests/topotests/pim_boundary_acl/test_pim_boundary_acl.py @@ -0,0 +1,523 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_pim_boundary_acl.py +# +# Copyright (c) 2024 Architecture Technology Corporation +# Corey Siltala +# + +""" +test_pim_boundary_acl.py: Test multicast boundary commands (access-lists and prefix-lists) +""" + +import os +import sys +import pytest +import json +from functools import partial + +pytestmark = [pytest.mark.pimd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +ASM_GROUP="229.1.1.1" +SSM_GROUP="232.1.1.1" + +def build_topo(tgen): + "Build function" + + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + tgen.add_router("rp") + + # rp ------ r1 -------- r2 + # \ + # --------- r3 + # r1 -> .1 + # r2 -> .2 + # rp -> .3 + # r3 -> .4 + # loopback network is 10.254.0.X/32 + # + # r1 <- sw1 -> r2 + # r1-eth0 <-> r2-eth0 + # 10.0.20.0/24 + sw = tgen.add_switch("sw1") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["r2"]) + + # r1 <- sw2 -> rp + # r1-eth1 <-> rp-eth0 + # 10.0.30.0/24 + sw = tgen.add_switch("sw2") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["rp"]) + + # r1 <- sw3 -> r3 + # r1-eth2 <-> r3-eth0 + # 10.0.40.0/24 + sw = tgen.add_switch("sw3") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().items(): + logger.info("Loading router %s" % rname) + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + # tgen.mininet_cli() + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_pim_rp_setup(): + "Ensure basic routing has come up and the rp has an outgoing interface" + # Ensure rp and r1 establish pim neighbor ship and bgp has come up + # Finally ensure that the rp has an outgoing interface on r1 + tgen = get_topogen() + + r1 = tgen.gears["r1"] + expected = { + "10.254.0.3":[ + { + "outboundInterface":"r1-eth1", + "group":"224.0.0.0/4", + "source":"Static" + } + ] + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip pim rp-info json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_pim_asm_igmp_join_acl(): + "Test ASM IGMP joins with prefix-list ACLs" + logger.info("Send IGMP joins from r2 to r1 with ACL enabled and disabled") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r1 = tgen.gears["r1"] + + # No IGMP sources other than from self for AutoRP Discovery group initially + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "224.0.1.40":"*", + "229.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "224.0.1.40":"*", + "229.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected no IGMP sources other than for AutoRP Discovery" + + # Send IGMP join from r2, check if r1 has IGMP source + r2.vtysh_cmd(( + """ + configure terminal + interface {} + ip igmp join {} + """ + ).format("r2-eth0", ASM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "229.1.1.1":{ + "group":"229.1.1.1", + "sources":[ + { + "source":"*", + "timer":"--:--", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # Test inbound boundary on r1 + # Enable multicast boundary on r1, toggle IGMP join on r2 + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} + """ + ).format(ASM_GROUP)) + r1.vtysh_cmd( + """ + configure terminal + interface r1-eth0 + ip multicast boundary oil pim-oil-plist + """ + ) + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} + """ + ).format(ASM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "229.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be absent but is present" + + # Test outbound boundary on r2 + # Enable multicast boundary on r2, toggle IGMP join (test outbound) + # Note: json_cmp treats "*" as wildcard but in this case that's actually what the source is + expected = { + "vrf":"default", + "r2-eth0":{ + "name":"r2-eth0", + "groups":[ + { + "source":"*", + "group":"229.1.1.1", + "primaryAddr":"10.0.20.2", + "sockFd":"*", + "upTime":"*" + } + ] + } + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be present but is absent" + + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} + ip multicast boundary oil pim-oil-plist + ip igmp join {} + """ + ).format(ASM_GROUP, ASM_GROUP)) + expected = { + "vrf":"default", + "r2-eth0":None + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be absent but is present" + + # Cleanup + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} + no ip multicast boundary oil pim-oil-plist + """ + ).format(ASM_GROUP)) + + +def test_pim_ssm_igmp_join_acl(): + "Test SSM IGMP joins with extended ACLs" + logger.info("Send IGMP joins from r2 to r1 with ACL enabled and disabled") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r3 = tgen.gears["r3"] + r2 = tgen.gears["r2"] + r1 = tgen.gears["r1"] + + # No IGMP sources other than from self for AutoRP Discovery group initially + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "224.0.1.40":"*", + "229.1.1.1":None, + "232.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "224.0.1.40":"*", + "229.1.1.1":None, + "232.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", {} + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected no IGMP sources other than from AutoRP Discovery" + + # Send IGMP join from r2, check if r1 has IGMP source + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":{ + "group":"232.1.1.1", + "sources":[ + { + "source":"10.0.20.2", + "timer":"*", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # Test inbound boundary on r1 + # Enable multicast boundary on r1, toggle IGMP join on r2 + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + r1.vtysh_cmd( + """ + configure terminal + interface r1-eth0 + ip multicast boundary pim-acl + """ + ) + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be absent but is present" + + # Add lower, more-specific permit rule to access-list + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + r1.vtysh_cmd(( + """ + configure terminal + access-list pim-acl seq 5 permit ip host 10.0.20.2 {} 0.0.0.128 + """ + ).format(SSM_GROUP)) + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":{ + "group":"232.1.1.1", + "sources":[ + { + "source":"10.0.20.2", + "timer":"*", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # Test outbound boundary on r2 + # Enable multicast boundary on r2, toggle IGMP join (test outbound) + expected = { + "vrf":"default", + "r2-eth0":{ + "name":"r2-eth0", + "groups":[ + { + "source":"10.0.20.2", + "group":"232.1.1.1", + "primaryAddr":"10.0.20.2", + "sockFd":"*", + "upTime":"*" + } + ] + } + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be present but is absent" + + # Enable boundary ACL, check join is absent + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} 10.0.20.2 + ip multicast boundary pim-acl + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP, SSM_GROUP)) + expected = { + "vrf":"default", + "r2-eth0":None + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be absent but is present" + # Check sources on r1 again, should be absent even though we permitted it because r2 is blocking it outbound + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "232.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be absent but is present" + + # Send IGMP join from r3 with different source, should show up on r1 + # Add lower, more-specific permit rule to access-list + r3.vtysh_cmd(( + """ + configure terminal + interface r3-eth0 + ip igmp join {} 10.0.40.4 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "232.1.1.1":{ + "group":"232.1.1.1", + "sources":[ + { + "source":"10.0.40.4", + "timer":"*", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # PIM join + # PIM-DM forwarding + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/pim_cand_rp_bsr/r1/frr.conf b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf index 899e9c068413..badcb8307b99 100644 --- a/tests/topotests/pim_cand_rp_bsr/r1/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ! !debug pim packet !debug pim bsm diff --git a/tests/topotests/pim_cand_rp_bsr/r2/frr.conf b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf index 85af461d5eb9..65926688aa01 100644 --- a/tests/topotests/pim_cand_rp_bsr/r2/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log ! !debug pim packet !debug pim bsm diff --git a/tests/topotests/pim_cand_rp_bsr/r3/frr.conf b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf index 022c44ea58b7..eae90c987c33 100644 --- a/tests/topotests/pim_cand_rp_bsr/r3/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log ! !debug pim packet !debug pim bsm diff --git a/tests/topotests/pim_cand_rp_bsr/r4/frr.conf b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf index 2d0a035f9a9d..276e8792160c 100644 --- a/tests/topotests/pim_cand_rp_bsr/r4/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf @@ -1,7 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log ! ! interface lo diff --git a/tests/topotests/pim_cand_rp_bsr/r5/frr.conf b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf index 552e51f417f6..b86c62600014 100644 --- a/tests/topotests/pim_cand_rp_bsr/r5/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf @@ -1,7 +1,5 @@ ! hostname r5 -password zebra -log file /tmp/r5-frr.log ! ! interface r5-eth0 diff --git a/tests/topotests/pim_cand_rp_bsr/r6/frr.conf b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf index 20955a12c709..1fd3582211cb 100644 --- a/tests/topotests/pim_cand_rp_bsr/r6/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf @@ -1,7 +1,5 @@ ! hostname r6 -password zebra -log file /tmp/r6-frr.log ! ! interface r6-eth0 diff --git a/tests/topotests/simple_snmp_test/r1/bgpd.conf b/tests/topotests/simple_snmp_test/r1/bgpd.conf index 00d1e1767085..bcdf1c4f7e7e 100644 --- a/tests/topotests/simple_snmp_test/r1/bgpd.conf +++ b/tests/topotests/simple_snmp_test/r1/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 100 bgp router-id 1.1.1.1 diff --git a/tests/topotests/zebra_rib/r1/frr-import.conf b/tests/topotests/zebra_rib/r1/frr-import.conf index d07433144f89..687843be0c43 100644 --- a/tests/topotests/zebra_rib/r1/frr-import.conf +++ b/tests/topotests/zebra_rib/r1/frr-import.conf @@ -1,7 +1,6 @@ ! hostname r1 password zebra -log file /tmp/r1-frr.log ! interface r1-eth0 ip address 10.0.0.1/24 @@ -15,4 +14,4 @@ ip route 10.3.0.0/24 10.10.0.2 table 10 ip route 10.4.0.0/24 10.10.0.2 table 10 ! ip forwarding -! \ No newline at end of file +! diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index a248a1a30424..be831a1d344f 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -134,9 +134,11 @@ show ip ospf router-info pce CMD_LIST_END # RIP Support Bundle Command List -# PROC_NAME:rip -# CMD_LIST_START -# CMD_LIST_END +PROC_NAME:rip +CMD_LIST_START +show ip rip +show ip rip status +CMD_LIST_END # ISIS Support Bundle Command List PROC_NAME:isis diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 5a54c60c6b11..c460dea70cda 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -39,6 +39,7 @@ #include "frrstr.h" #include "json.h" #include "ferr.h" +#include "sockopt.h" DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy"); @@ -4690,9 +4691,8 @@ static int vtysh_connect(struct vtysh_client *vclient) * Increasing the RECEIVE socket buffer size so that the socket can hold * after receving from other process. */ - ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbufsize, - sizeof(rcvbufsize)); - if (ret < 0) { + ret = setsockopt_so_recvbuf(sock, rcvbufsize); + if (ret <= 0) { #ifdef DEBUG fprintf(stderr, "Cannot set socket %d rcv buffer size, %s\n", sock, safe_strerror(errno)); diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index acc612c0a858..611a7872d013 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -44,7 +44,7 @@ #define DEFAULT_PERIOD 5 #define DEFAULT_TIMEOUT 90 -#define DEFAULT_RESTART_TIMEOUT 20 +#define DEFAULT_RESTART_TIMEOUT 90 #define DEFAULT_LOGLEVEL LOG_INFO #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index c3c953b76b42..5fd7e66a3b1c 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -78,6 +78,10 @@ module frr-pim { type string; } + typedef access-list-ref { + type string; + } + /* * Groupings */ @@ -264,6 +268,21 @@ module frr-pim { description "Log all MSDP SA related events."; } + + leaf originator-id { + type inet:ip-address; + description + "Configure the RP address for the SAs. + + By default the local system RP address will be used."; + } + + leaf shutdown { + type boolean; + default false; + description + "Shutdown MSDP functionality."; + } } list msdp-mesh-groups { @@ -330,6 +349,12 @@ module frr-pim { } uses msdp-authentication; + + leaf sa-limit { + type uint32; + description + "Peer SA maximum limit."; + } } container mlag { @@ -500,7 +525,13 @@ module frr-pim { leaf multicast-boundary-oil { type plist-ref; description - "Prefix-List to define multicast boundary"; + "Prefix-List to define multicast boundary by group"; + } + + leaf multicast-boundary-acl { + type access-list-ref; + description + "Access-list to define multicast boundary by source and group"; } list mroute { diff --git a/zebra/main.c b/zebra/main.c index 138a955bc313..4546d1477009 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -467,6 +467,9 @@ int main(int argc, char **argv) zebra_if_init(); zebra_debug_init(); + /* Open Zebra API server socket */ + zserv_open(zserv_path); + /* * Initialize NS( and implicitly the VRF module), and make kernel * routing socket. */ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 10acee9be435..d269cdd01537 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -282,7 +282,7 @@ int zsend_interface_address(int cmd, struct zserv *client, { int blen; struct prefix *p; - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, ifp->vrf->vrf_id); stream_putl(s, ifp->ifindex); @@ -323,7 +323,7 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client, struct nbr_connected *ifc) { int blen; - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); struct prefix *p; zclient_create_header(s, cmd, ifp->vrf->vrf_id); @@ -651,7 +651,7 @@ static int zsend_nexthop_lookup_mrib(struct zserv *client, struct ipaddr *addr, struct nexthop *nexthop; /* Get output stream. */ - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); /* Fill in result. */ @@ -706,7 +706,7 @@ int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, zlog_debug("%s: type %d, id %d, note %s", __func__, type, id, zapi_nhg_notify_owner2str(note)); - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); zclient_create_header(s, ZEBRA_NHG_NOTIFY_OWNER, VRF_DEFAULT); @@ -835,7 +835,7 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, dplane_ctx_rule_get_vrfid(ctx)); @@ -889,7 +889,7 @@ void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putw(s, note); @@ -923,7 +923,7 @@ void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putw(s, note); @@ -959,7 +959,7 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putw(s, note); @@ -1049,13 +1049,12 @@ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, vrf_id_t vrf_id) { int blen; - struct stream *s; /* Check this client need interface information. */ if (!vrf_bitmap_check(&client->ridinfo[afi], vrf_id)) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); /* Message type. */ zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); @@ -1077,7 +1076,7 @@ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, */ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); stream_write(s, pw->ifname, IFNAMSIZ); @@ -1094,7 +1093,7 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct label_manager_chunk *lmc) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); /* proto */ @@ -1120,7 +1119,7 @@ int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id, int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id, unsigned short result) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); @@ -1144,7 +1143,7 @@ static int zsend_assign_table_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct table_manager_chunk *tmc) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, vrf_id); @@ -1164,7 +1163,7 @@ static int zsend_table_manager_connect_response(struct zserv *client, vrf_id_t vrf_id, uint16_t result) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, vrf_id); @@ -2406,7 +2405,7 @@ static void zread_router_id_delete(ZAPI_HANDLER_ARGS) static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_CAPABILITIES, zvrf->vrf->vrf_id); stream_putl(s, vrf_get_backend()); @@ -3990,8 +3989,7 @@ static inline void zebra_gre_source_set(ZAPI_HANDLER_ARGS) static void zsend_error_msg(struct zserv *client, enum zebra_error_types error, struct zmsghdr *bad_hdr) { - - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_ERROR, bad_hdr->vrf_id); diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c index 6ee0fdbb8d90..ca53eb2eb34d 100644 --- a/zebra/zebra_cli.c +++ b/zebra/zebra_cli.c @@ -2252,6 +2252,9 @@ static void lib_vrf_mpls_fec_nexthop_resolution_cli_write( } } +#if CONFDATE > 20251207 +CPP_NOTICE("Remove no-op netns command") +#endif DEFPY_YANG (vrf_netns, vrf_netns_cmd, "[no] netns ![NAME$netns_name]", diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 0d53591336f8..f9009dabb75b 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1152,6 +1152,7 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) listcount(mac->neigh_list)); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + mac->rem_seq = 0; return 0; } @@ -2411,6 +2412,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + mac->rem_seq = 0; } return 0; diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 0d3fd2a7268f..3325532ca920 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -466,7 +466,7 @@ static int fec_send(struct zebra_fec *fec, struct zserv *client) rn = fec->rn; /* Get output stream. */ - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT); diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c index 881b681c2f6d..86e25469ba2d 100644 --- a/zebra/zebra_mroute.c +++ b/zebra/zebra_mroute.c @@ -61,7 +61,7 @@ void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS) suc = kernel_get_ipmr_sg_stats(zvrf, &mroute); stream_failure: - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b2543ca0e8b1..e64a620f0030 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2838,6 +2838,8 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) if (!ere->startup && (re->flags & ZEBRA_FLAG_SELFROUTE) && zrouter.asic_offloaded) { + struct route_entry *entry; + if (!same) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug( @@ -2854,6 +2856,25 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) early_route_memory_free(ere); return; } + + RNODE_FOREACH_RE (rn, entry) { + if (CHECK_FLAG(entry->status, ROUTE_ENTRY_REMOVED)) + continue; + + if (entry->type != ere->re->type) + continue; + + /* + * If we have an entry that is changed but un + * processed and not a self route, then + * we should just drop this new self route + */ + if (CHECK_FLAG(entry->status, ROUTE_ENTRY_CHANGED) && + !(entry->flags & ZEBRA_FLAG_SELFROUTE)) { + early_route_memory_free(ere); + return; + } + } } /* Set default distance by route type. */ @@ -3746,10 +3767,8 @@ static struct meta_queue *meta_queue_new(void) new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct meta_queue)); - for (i = 0; i < MQ_SIZE; i++) { + for (i = 0; i < MQ_SIZE; i++) new->subq[i] = list_new(); - assert(new->subq[i]); - } return new; } @@ -3935,12 +3954,7 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) /* initialise zebra rib work queue */ static void rib_queue_init(void) { - if (!(zrouter.ribq = work_queue_new(zrouter.master, - "route_node processing"))) { - flog_err(EC_ZEBRA_WQ_NONEXISTENT, - "%s: could not initialise work queue!", __func__); - return; - } + zrouter.ribq = work_queue_new(zrouter.master, "route_node processing"); /* fill in the work queue spec */ zrouter.ribq->spec.workfunc = &meta_queue_process; @@ -3950,11 +3964,8 @@ static void rib_queue_init(void) zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; zrouter.ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME; - if (!(zrouter.mq = meta_queue_new())) { - flog_err(EC_ZEBRA_WQ_NONEXISTENT, - "%s: could not initialise meta queue!", __func__); - return; - } + zrouter.mq = meta_queue_new(); + return; } @@ -4406,9 +4417,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (ng) { nhe.nhg.nexthop = ng->nexthop; - if (re->type == ZEBRA_ROUTE_CONNECT || - re->type == ZEBRA_ROUTE_LOCAL || - re->type == ZEBRA_ROUTE_KERNEL) + if (RIB_SYSTEM_ROUTE(re)) SET_FLAG(nhe.flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL); } else if (re->nhe_id > 0) nhe.id = re->nhe_id; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index ad112a4ab1f4..c60eeab94671 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2203,7 +2203,7 @@ static int zl3vni_send_add_to_client(struct zebra_l3vni *zl3vni) is_anycast_mac = false; } - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); /* The message is used for both vni add and/or update like * vrr mac is added for l3vni SVI. @@ -2246,7 +2246,7 @@ static int zl3vni_send_del_to_client(struct zebra_l3vni *zl3vni) if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); @@ -4403,6 +4403,7 @@ static int zebra_vxlan_check_del_local_mac(struct interface *ifp, UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + mac->rem_seq = 0; } return 0; @@ -5860,7 +5861,7 @@ static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf, if (!CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putl(s, IPV4_MAX_BYTELEN); diff --git a/zebra/zserv.c b/zebra/zserv.c index 07e399664316..7ef358232991 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -57,6 +57,7 @@ extern struct zebra_privs_t zserv_privs; /* The listener socket for clients connecting to us */ static int zsock; +static bool started_p; /* The lock that protects access to zapi client objects */ static pthread_mutex_t client_mutex; @@ -183,10 +184,9 @@ void zserv_log_message(const char *errmsg, struct stream *msg, */ static void zserv_client_fail(struct zserv *client) { - flog_warn( - EC_ZEBRA_CLIENT_IO_ERROR, - "Client '%s' (session id %d) encountered an error and is shutting down.", - zebra_route_string(client->proto), client->session_id); + flog_warn(EC_ZEBRA_CLIENT_IO_ERROR, + "Client %d '%s' (session id %d) encountered an error and is shutting down.", + client->sock, zebra_route_string(client->proto), client->session_id); atomic_store_explicit(&client->pthread->running, false, memory_order_relaxed); @@ -467,8 +467,8 @@ static void zserv_read(struct event *thread) } if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Read %d packets from client: %s. Current ibuf fifo count: %zu. Conf P2p %d", - p2p_avail - p2p, zebra_route_string(client->proto), + zlog_debug("Read %d packets from client: %s(%d). Current ibuf fifo count: %zu. Conf P2p %d", + p2p_avail - p2p, zebra_route_string(client->proto), client->sock, client_ibuf_fifo_cnt, p2p_orig); /* Reschedule ourselves since we have space in ibuf_fifo */ @@ -929,9 +929,16 @@ void zserv_close(void) /* Free client list's mutex */ pthread_mutex_destroy(&client_mutex); + + started_p = false; } -void zserv_start(char *path) + +/* + * Open zebra's ZAPI listener socket. This is done early during startup, + * before zebra is ready to listen and accept client connections. + */ +void zserv_open(const char *path) { int ret; mode_t old_mask; @@ -973,6 +980,26 @@ void zserv_start(char *path) path, safe_strerror(errno)); close(zsock); zsock = -1; + } + + umask(old_mask); +} + +/* + * Start listening for ZAPI client connections. + */ +void zserv_start(const char *path) +{ + int ret; + + /* This may be called more than once during startup - potentially once + * per netns - but only do this work once. + */ + if (started_p) + return; + + if (zsock <= 0) { + flog_err_sys(EC_LIB_SOCKET, "Zserv socket open failed"); return; } @@ -986,7 +1013,7 @@ void zserv_start(char *path) return; } - umask(old_mask); + started_p = true; zserv_event(NULL, ZSERV_ACCEPT); } diff --git a/zebra/zserv.h b/zebra/zserv.h index 87d2b4adbf81..ce47ef19fa36 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -255,16 +255,25 @@ extern void zserv_init(void); */ extern void zserv_close(void); +/* + * Open Zebra API server socket. + * + * Create and open the server socket. + * + * path + * where to place the Unix domain socket + */ +extern void zserv_open(const char *path); + /* * Start Zebra API server. * - * Allocates resources, creates the server socket and begins listening on the - * socket. + * Allocates resources and begins listening on the server socket. * * path * where to place the Unix domain socket */ -extern void zserv_start(char *path); +extern void zserv_start(const char *path); /* * Send a message to a connected Zebra API client.