summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--babeld/babeld.c14
-rw-r--r--bfdd/event.c4
-rw-r--r--bgpd/bgp_bmp.c18
-rw-r--r--bgpd/bgp_evpn_vty.c17
-rw-r--r--bgpd/bgp_mplsvpn.c46
-rw-r--r--bgpd/bgp_packet.c7
-rw-r--r--bgpd/bgp_packet.h3
-rw-r--r--bgpd/bgp_route.c112
-rw-r--r--bgpd/bgp_route.h3
-rw-r--r--bgpd/bgp_zebra.c7
-rw-r--r--bgpd/bgpd.c23
-rw-r--r--doc/user/bgp.rst5
-rw-r--r--isisd/isis_nb.c12
-rw-r--r--isisd/isis_nb_config.c40
-rw-r--r--lib/event.c85
-rw-r--r--lib/frr_pthread.c8
-rw-r--r--lib/frrcu.c15
-rw-r--r--lib/frrevent.h19
-rw-r--r--lib/sigevent.h27
-rw-r--r--lib/zlog_5424.c12
-rw-r--r--nhrpd/netlink_arp.c2
-rw-r--r--tests/topotests/bgp_bmp/test_bgp_bmp_1.py7
-rw-r--r--tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf10
-rw-r--r--tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json155
-rw-r--r--tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json103
-rw-r--r--tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json120
-rw-r--r--tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json120
-rw-r--r--tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json137
-rw-r--r--tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py234
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py75
-rw-r--r--zebra/fpm_listener.c2
31 files changed, 1137 insertions, 305 deletions
diff --git a/babeld/babeld.c b/babeld/babeld.c
index 1d2f60e3ad..4e68f05df4 100644
--- a/babeld/babeld.c
+++ b/babeld/babeld.c
@@ -538,7 +538,7 @@ resize_receive_buffer(int size)
}
static void
-babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist)
+babel_distribute_update (struct distribute_ctx *ctx __attribute__((__unused__)), struct distribute *dist)
{
struct interface *ifp;
babel_interface_nfo *babel_ifp;
@@ -593,7 +593,7 @@ babel_distribute_update_all (struct prefix_list *notused)
}
static void
-babel_distribute_update_all_wrapper (struct access_list *notused)
+babel_distribute_update_all_wrapper (struct access_list *notused __attribute__((__unused__)))
{
babel_distribute_update_all(NULL);
}
@@ -872,16 +872,18 @@ babeld_quagga_init(void)
/* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
int
-input_filter(const unsigned char *id,
+input_filter(const unsigned char *id __attribute__((__unused__)),
const unsigned char *prefix, unsigned short plen,
- const unsigned char *neigh, unsigned int ifindex)
+ const unsigned char *neigh __attribute__((__unused__)),
+ unsigned int ifindex)
{
return babel_filter(0, prefix, plen, ifindex);
}
int
-output_filter(const unsigned char *id, const unsigned char *prefix,
- unsigned short plen, unsigned int ifindex)
+output_filter(const unsigned char *id __attribute__((__unused__)),
+ const unsigned char *prefix, unsigned short plen,
+ unsigned int ifindex)
{
return babel_filter(1, prefix, plen, ifindex);
}
diff --git a/bfdd/event.c b/bfdd/event.c
index e5f43b6cc6..f85b4335be 100644
--- a/bfdd/event.c
+++ b/bfdd/event.c
@@ -107,6 +107,7 @@ void sbfd_init_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
tv_normalize(&tv);
event_add_timer_tv(master, sbfd_init_xmt_cb, bs, &tv, &bs->xmttimer_ev);
+ event_set_tardy_threshold(bs->xmttimer_ev, bs->xmt_TO / 2);
}
void sbfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
@@ -123,6 +124,7 @@ void sbfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
tv_normalize(&tv);
event_add_timer_tv(master, sbfd_echo_xmt_cb, bs, &tv, &bs->echo_xmttimer_ev);
+ event_set_tardy_threshold(bs->echo_xmttimer_ev, bs->echo_xmt_TO / 2);
}
void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
@@ -140,6 +142,7 @@ void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
tv_normalize(&tv);
event_add_timer_tv(master, bfd_xmt_cb, bs, &tv, &bs->xmttimer_ev);
+ event_set_tardy_threshold(bs->xmttimer_ev, bs->xmt_TO / 2);
}
void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
@@ -158,6 +161,7 @@ void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
event_add_timer_tv(master, bfd_echo_xmt_cb, bs, &tv,
&bs->echo_xmttimer_ev);
+ event_set_tardy_threshold(bs->echo_xmttimer_ev, bs->echo_xmt_TO / 2);
}
void bfd_recvtimer_delete(struct bfd_session *bs)
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index e458e5e5ac..b1bff82b05 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -56,6 +56,7 @@ static int bmp_route_update_bgpbmp(struct bmp_targets *bt, afi_t afi, safi_t saf
static void bmp_send_all_bgp(struct peer *peer, bool down);
static struct bmp_imported_bgp *bmp_imported_bgp_find(struct bmp_targets *bt, char *name);
static void bmp_stats_per_instance(struct bgp *bgp, struct bmp_targets *bt);
+static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp);
DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)");
@@ -551,9 +552,12 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
- if (bbpeer && bbpeer->open_tx)
+ if (bbpeer && bbpeer->open_tx) {
+ if (is_locrib)
+ /* update bgp id each time peer up LOC-RIB message is to be sent */
+ bmp_bgp_peer_vrf(bbpeer, peer->bgp);
stream_put(s, bbpeer->open_tx, bbpeer->open_tx_len);
- else {
+ } else {
stream_put(s, dummy_open, sizeof(dummy_open));
zlog_warn("bmp: missing TX OPEN message for peer %s",
peer->host);
@@ -2209,6 +2213,8 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp)
struct peer *peer = bgp->peer_self;
uint16_t send_holdtime;
as_t local_as;
+ struct stream *s;
+ size_t open_len;
if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
send_holdtime = peer->holdtime;
@@ -2221,8 +2227,8 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp)
else
local_as = peer->local_as;
- struct stream *s = bgp_open_make(peer, send_holdtime, local_as);
- size_t open_len = stream_get_endp(s);
+ s = bgp_open_make(peer, send_holdtime, local_as, &peer->local_id);
+ open_len = stream_get_endp(s);
bbpeer->open_rx_len = open_len;
if (bbpeer->open_rx)
@@ -2230,6 +2236,10 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp)
bbpeer->open_rx = XMALLOC(MTYPE_BMP_OPEN, open_len);
memcpy(bbpeer->open_rx, s->data, open_len);
+ stream_free(s);
+
+ s = bgp_open_make(peer, send_holdtime, bgp->as, &bgp->router_id);
+ open_len = stream_get_endp(s);
bbpeer->open_tx_len = open_len;
if (bbpeer->open_tx)
XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index dc6e0d33c2..8a0c6e10d6 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -766,7 +766,7 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
if (detail)
route_vty_out_detail(vty, bgp, bd, bgp_dest_get_prefix(bd), pi,
AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED,
- json_path, NULL);
+ json_path, NULL, 0);
else
route_vty_out(vty, &bd->rn->p, pi, 0, SAFI_EVPN,
json_path, false);
@@ -893,7 +893,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn,
if (detail)
route_vty_out_detail(vty, bgp, dest, &tmp_p, pi, AFI_L2VPN,
SAFI_EVPN, RPKI_NOT_BEING_USED, json_path,
- NULL);
+ NULL, 0);
else
route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN,
@@ -2569,7 +2569,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
json_path = json_object_new_array();
route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi,
- RPKI_NOT_BEING_USED, json_path, NULL);
+ RPKI_NOT_BEING_USED, json_path, NULL, 0);
if (json)
json_object_array_add(json_paths, json_path);
@@ -2697,7 +2697,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
}
route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, pi, afi, safi,
- RPKI_NOT_BEING_USED, json_path, NULL);
+ RPKI_NOT_BEING_USED, json_path, NULL, 0);
if (json)
json_object_array_add(json_paths, json_path);
@@ -2807,7 +2807,7 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
json_path = json_object_new_array();
route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi,
- RPKI_NOT_BEING_USED, json_path, NULL);
+ RPKI_NOT_BEING_USED, json_path, NULL, 0);
if (json)
json_object_array_add(json_paths, json_path);
@@ -2919,7 +2919,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
json_path = json_object_new_array();
route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi,
- safi, RPKI_NOT_BEING_USED, json_path, NULL);
+ safi, RPKI_NOT_BEING_USED, json_path, NULL, 0);
if (json)
json_object_array_add(json_paths, json_path);
@@ -3055,7 +3055,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
json_path = json_object_new_array();
route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN, SAFI_EVPN,
- RPKI_NOT_BEING_USED, json_path, NULL);
+ RPKI_NOT_BEING_USED, json_path, NULL, 0);
if (json)
json_object_array_add(json_paths, json_path);
@@ -3227,7 +3227,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
route_vty_out_detail(vty, bgp, dest,
bgp_dest_get_prefix(dest), pi,
AFI_L2VPN, SAFI_EVPN,
- RPKI_NOT_BEING_USED, json_path, NULL);
+ RPKI_NOT_BEING_USED, json_path, NULL,
+ 0);
} else
route_vty_out(vty, p, pi, 0, SAFI_EVPN,
json_path, false);
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 46e529f03d..6a8df3b68e 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -1052,6 +1052,7 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
struct bgp_path_info *bpi_ultimate;
struct bgp *bgp_nexthop;
struct bgp_table *table;
+ struct interface *ifp;
bool nh_valid;
bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
@@ -1062,6 +1063,15 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
else
bgp_nexthop = bgp_orig;
+ /* The nexthop is invalid if its VRF does not exist */
+ if (bgp_nexthop->vrf_id == VRF_UNKNOWN)
+ return false;
+
+ /* The nexthop is invalid if its VRF interface is down*/
+ ifp = if_get_vrf_loopback(bgp_nexthop->vrf_id);
+ if (ifp && !if_is_up(ifp))
+ return false;
+
/*
* No nexthop tracking for redistributed routes, for
* EVPN-imported routes that get leaked, or for routes
@@ -1126,8 +1136,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
struct bgp_path_info *bpi;
struct bgp_path_info *new;
struct bgp_path_info_extra *extra;
- struct bgp_path_info *parent = source_bpi;
struct bgp_labels bgp_labels = {};
+ struct bgp *bgp_nexthop;
bool labelssame;
uint8_t i;
@@ -1159,8 +1169,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
* match parent
*/
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
- if (bpi->extra && bpi->extra->vrfleak &&
- bpi->extra->vrfleak->parent == parent)
+ if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->parent == source_bpi)
break;
}
@@ -1174,6 +1183,16 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label,
bgp_labels.num_labels);
+ bgp_nexthop = bpi->extra->vrfleak->bgp_orig ?: bgp_orig;
+ if (bgp_nexthop->vrf_id == VRF_UNKNOWN) {
+ if (debug) {
+ zlog_debug("%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, origin VRF does not exist, not leaking",
+ __func__, to_bgp->name_pretty, source_bpi->flags,
+ bpi->flags, p);
+ }
+ return NULL;
+ }
+
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)
&& CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
if (debug) {
@@ -1185,9 +1204,11 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
return NULL;
}
- if (attrhash_cmp(bpi->attr, new_attr) && labelssame
- && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
-
+ if (attrhash_cmp(bpi->attr, new_attr) && labelssame &&
+ !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) &&
+ leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, source_bpi, bpi,
+ bgp_orig, p,
+ debug) == !!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) {
bgp_attr_unintern(&new_attr);
if (debug)
zlog_debug(
@@ -1274,6 +1295,14 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
return NULL;
}
+ if (bgp_orig->vrf_id == VRF_UNKNOWN) {
+ if (debug) {
+ zlog_debug("%s: ->%s(s_flags: 0x%x): %pFX: New route, origin VRF does not exist, not leaking",
+ __func__, to_bgp->name_pretty, source_bpi->flags, p);
+ }
+ return NULL;
+ }
+
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
to_bgp->peer_self, new_attr, bn);
@@ -1297,9 +1326,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (bgp_labels.num_labels)
new->extra->labels = bgp_labels_intern(&bgp_labels);
- new->extra->vrfleak->parent = bgp_path_info_lock(parent);
- bgp_dest_lock_node(
- (struct bgp_dest *)parent->net);
+ new->extra->vrfleak->parent = bgp_path_info_lock(source_bpi);
+ bgp_dest_lock_node((struct bgp_dest *)source_bpi->net);
new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 7e342dba26..5ac7c7176e 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -637,7 +637,8 @@ void bgp_keepalive_send(struct peer *peer)
bgp_writes_on(peer->connection);
}
-struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as)
+struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as,
+ struct in_addr *id)
{
struct stream *s = stream_new(BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE);
bool ext_opt_params = false;
@@ -650,7 +651,7 @@ struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t loc
stream_putw(s, (local_as <= BGP_AS_MAX) ? (uint16_t)local_as
: BGP_AS_TRANS);
stream_putw(s, send_holdtime); /* Hold Time */
- stream_put_in_addr(s, &peer->local_id); /* BGP Identifier */
+ stream_put_in_addr(s, id); /* BGP Identifier */
/* Set capabilities */
if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) {
@@ -705,7 +706,7 @@ void bgp_open_send(struct peer_connection *connection)
else
local_as = peer->local_as;
- s = bgp_open_make(peer, send_holdtime, local_as);
+ s = bgp_open_make(peer, send_holdtime, local_as, &peer->local_id);
/* Dump packet if debug option is set. */
/* bgp_packet_dump (s); */
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index 866b8f617d..ae81aade70 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -49,7 +49,8 @@ DECLARE_HOOK(bgp_packet_send,
/* Packet send and receive function prototypes. */
extern void bgp_keepalive_send(struct peer *peer);
-extern struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as);
+extern struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as,
+ struct in_addr *id);
extern void bgp_open_send(struct peer_connection *connection);
extern void bgp_notify_send(struct peer_connection *connection, uint8_t code,
uint8_t sub_code);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index a1a5068a7f..36690d55f4 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -10795,7 +10795,7 @@ static void route_vty_out_detail_es_info(struct vty *vty,
void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
const struct prefix *p, struct bgp_path_info *path, afi_t afi,
safi_t safi, enum rpki_states rpki_curr_state, json_object *json_paths,
- struct attr *pattr)
+ struct attr *pattr, uint16_t show_opts)
{
char buf[INET6_ADDRSTRLEN];
char vni_buf[30] = {};
@@ -11824,6 +11824,16 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
llgr_remaining);
}
+ /* Display internal data if asked */
+ if (CHECK_FLAG(show_opts, BGP_SHOW_OPT_INTERNAL_DATA)) {
+ if (!json_paths) {
+ vty_out(vty, " net: %p, path: %p, pathext: %p, attr: %p\n", path->net,
+ path, path->extra, attr);
+ vty_out(vty, " flags net: 0x%u, path: 0x%u, attr: 0x%" PRIu64 "\n",
+ path->net->flags, path->flags, attr->flag);
+ }
+ }
+
/* Output some debug about internal state of the dest flags */
if (json_paths) {
if (CHECK_FLAG(bn->flags, BGP_NODE_PROCESS_SCHEDULED))
@@ -12255,7 +12265,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa
route_vty_out_detail(vty, bgp, dest, dest_p, pi,
family2afi(dest_p->family), safi,
- rpki_curr_state, json_paths, NULL);
+ rpki_curr_state, json_paths, NULL,
+ show_flags);
} else {
route_vty_out(vty, dest_p, pi, display,
safi, json_paths, wide);
@@ -12773,7 +12784,8 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node,
struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
json_object *json, enum bgp_path_type pathtype, int *display,
- enum rpki_states rpki_target_state, struct attr *attr)
+ enum rpki_states rpki_target_state, struct attr *attr,
+ uint16_t show_opts)
{
struct bgp_path_info *pi;
int header = 1;
@@ -12817,7 +12829,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *
&& (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH)
|| CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))))
route_vty_out_detail(vty, bgp, bgp_node, bgp_dest_get_prefix(bgp_node), pi,
- afi, safi, rpki_curr_state, json_paths, attr);
+ afi, safi, rpki_curr_state, json_paths, attr,
+ show_opts);
}
if (json && json_paths) {
@@ -12854,12 +12867,11 @@ const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
}
/* Display specified route of BGP table. */
-static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
- struct bgp_table *rib, const char *ip_str,
- afi_t afi, safi_t safi,
- enum rpki_states rpki_target_state,
- struct prefix_rd *prd, int prefix_check,
- enum bgp_path_type pathtype, bool use_json)
+static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, struct bgp_table *rib,
+ const char *ip_str, afi_t afi, safi_t safi,
+ enum rpki_states rpki_target_state, struct prefix_rd *prd,
+ int prefix_check, enum bgp_path_type pathtype, bool use_json,
+ uint16_t show_opts)
{
int ret;
int display = 0;
@@ -12904,8 +12916,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
continue;
}
- bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi,
- json, pathtype, &display, rpki_target_state, NULL);
+ bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json,
+ pathtype, &display, rpki_target_state, NULL, show_opts);
bgp_dest_unlock_node(rm);
}
@@ -12964,8 +12976,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
rm = longest_pfx;
bgp_dest_lock_node(rm);
- bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi,
- json, pathtype, &display, rpki_target_state, NULL);
+ bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json,
+ pathtype, &display, rpki_target_state, NULL, show_opts);
bgp_dest_unlock_node(rm);
}
@@ -12992,7 +13004,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
if (!prefix_check
|| dest_p->prefixlen == match.prefixlen) {
bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json, pathtype,
- &display, rpki_target_state, NULL);
+ &display, rpki_target_state, NULL, show_opts);
}
bgp_dest_unlock_node(dest);
@@ -13012,10 +13024,10 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
}
/* Display specified route of Main RIB */
-static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str,
- afi_t afi, safi_t safi, struct prefix_rd *prd,
- int prefix_check, enum bgp_path_type pathtype,
- enum rpki_states rpki_target_state, bool use_json)
+static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi,
+ safi_t safi, struct prefix_rd *prd, int prefix_check,
+ enum bgp_path_type pathtype, enum rpki_states rpki_target_state,
+ bool use_json, uint16_t show_opts)
{
if (!bgp) {
bgp = bgp_get_default();
@@ -13032,9 +13044,9 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str,
if (safi == SAFI_LABELED_UNICAST)
safi = SAFI_UNICAST;
- return bgp_show_route_in_table(vty, bgp, bgp->rib[afi][safi], ip_str,
- afi, safi, rpki_target_state, prd,
- prefix_check, pathtype, use_json);
+ return bgp_show_route_in_table(vty, bgp, bgp->rib[afi][safi], ip_str, afi, safi,
+ rpki_target_state, prd, prefix_check, pathtype, use_json,
+ show_opts);
}
static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc,
@@ -13396,7 +13408,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
|"BGP_SELF_ORIG_CMD_STR"\
- |detail-routes$detail_routes\
+ |detail-routes$detail_routes [internal$internal]\
] [json$uj [detail$detail_json] | wide$wide]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
@@ -13447,6 +13459,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
"Display route and more specific routes\n"
BGP_SELF_ORIG_HELP_STR
"Display detailed version of all routes\n"
+ "Display detailed version of all routes including internal data\n"
JSON_STR
"Display detailed version of JSON output\n"
"Increase table width for longer prefixes\n")
@@ -13475,6 +13488,9 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
if (detail_routes)
SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL);
+ if (internal)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_INTERNAL_DATA);
+
/* [<ipv4|ipv6> [all]] */
if (all) {
SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
@@ -13763,7 +13779,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
DEFUN (show_ip_bgp_route,
show_ip_bgp_route_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [<bestpath|multipath>] [rpki <valid|invalid|notfound>] [json]",
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [internal] [<bestpath|multipath>] [rpki <valid|invalid|notfound>] [json]",
SHOW_STR
IP_STR
BGP_STR
@@ -13774,6 +13790,7 @@ DEFUN (show_ip_bgp_route,
"IPv4 prefix\n"
"Network in the BGP routing table to display\n"
"IPv6 prefix\n"
+ "Display internal data additionally\n"
"Display only the bestpath\n"
"Display only multipaths\n"
"Display only paths that match the specified rpki state\n"
@@ -13790,6 +13807,7 @@ DEFUN (show_ip_bgp_route,
struct bgp *bgp = NULL;
enum bgp_path_type path_type;
bool uj = use_json(argc, argv);
+ uint16_t show_opts = 0;
int idx = 0;
@@ -13827,6 +13845,10 @@ DEFUN (show_ip_bgp_route,
prefix = argv[idx]->arg;
+ /* Display internal data also */
+ if (argv_find(argv, argc, "internal", &idx))
+ SET_FLAG(show_opts, BGP_SHOW_OPT_INTERNAL_DATA);
+
/* [<bestpath|multipath>] */
if (argv_find(argv, argc, "bestpath", &idx))
path_type = BGP_PATH_SHOW_BESTPATH;
@@ -13835,8 +13857,8 @@ DEFUN (show_ip_bgp_route,
else
path_type = BGP_PATH_SHOW_ALL;
- return bgp_show_route(vty, bgp, prefix, afi, safi, NULL, prefix_check,
- path_type, RPKI_NOT_BEING_USED, uj);
+ return bgp_show_route(vty, bgp, prefix, afi, safi, NULL, prefix_check, path_type,
+ RPKI_NOT_BEING_USED, uj, show_opts);
}
DEFUN (show_ip_bgp_regexp,
@@ -14694,9 +14716,8 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
return CMD_WARNING;
}
- return bgp_show_route(vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0,
- BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED,
- use_json(argc, argv));
+ return bgp_show_route(vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_SHOW_ALL,
+ RPKI_NOT_BEING_USED, use_json(argc, argv), 0);
}
#endif /* KEEP_OLD_VPN_COMMANDS */
@@ -14728,9 +14749,8 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix,
vty_out(vty, "Unable to figure out Network\n");
return CMD_WARNING;
}
- return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL,
- prefix_check, BGP_PATH_SHOW_ALL,
- RPKI_NOT_BEING_USED, use_json(argc, argv));
+ return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, prefix_check,
+ BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), 0);
}
static void show_adj_route_header(struct vty *vty, struct peer *peer,
@@ -14886,8 +14906,9 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
if (use_json)
json_net = json_object_new_object();
- bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi, json_net,
- BGP_PATH_SHOW_ALL, &display, RPKI_NOT_BEING_USED, NULL);
+ bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi,
+ json_net, BGP_PATH_SHOW_ALL, &display,
+ RPKI_NOT_BEING_USED, NULL, show_flags);
if (use_json)
json_object_object_addf(json_ar, json_net,
"%pFX", rn_p);
@@ -15023,7 +15044,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
pass_in = dest;
bgp_show_path_info(NULL, pass_in, vty, bgp, afi, safi,
json_net, BGP_PATH_SHOW_ALL, &display,
- RPKI_NOT_BEING_USED, NULL);
+ RPKI_NOT_BEING_USED, NULL, show_flags);
if (use_json)
json_object_object_addf(
json_ar, json_net,
@@ -15075,7 +15096,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
bgp_show_path_info(NULL, dest, vty, bgp, afi, safi,
json_net, BGP_PATH_SHOW_ALL,
&display, RPKI_NOT_BEING_USED,
- adj->attr);
+ adj->attr, show_flags);
if (use_json)
json_object_object_addf(json_ar, json_net,
"%pFX", rn_p);
@@ -15121,9 +15142,10 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
if (use_json)
json_net =
json_object_new_object();
- bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi,
- safi, json_net, BGP_PATH_SHOW_BESTPATH,
- &display, RPKI_NOT_BEING_USED, NULL);
+ bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp,
+ afi, safi, json_net,
+ BGP_PATH_SHOW_BESTPATH, &display,
+ RPKI_NOT_BEING_USED, NULL, show_flags);
if (use_json)
json_object_object_addf(
json_ar, json_net,
@@ -15767,10 +15789,9 @@ DEFUN (show_bgp_afi_vpn_rd_route,
}
if (!strcmp(argv[5]->arg, "all"))
- return bgp_show_route(vty, NULL, argv[6]->arg, afi,
- SAFI_MPLS_VPN, NULL, 0, BGP_PATH_SHOW_ALL,
- RPKI_NOT_BEING_USED,
- use_json(argc, argv));
+ return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, NULL, 0,
+ BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv),
+ 0);
ret = str2prefix_rd(argv[5]->arg, &prd);
if (!ret) {
@@ -15778,9 +15799,8 @@ DEFUN (show_bgp_afi_vpn_rd_route,
return CMD_WARNING;
}
- return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd,
- 0, BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED,
- use_json(argc, argv));
+ return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd, 0,
+ BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), 0);
}
static struct bgp_distance *bgp_distance_new(void)
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index c4cbbee0c7..1f854cad19 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -752,6 +752,7 @@ DECLARE_HOOK(bgp_route_update,
#define BGP_SHOW_OPT_JSON_DETAIL (1 << 7)
#define BGP_SHOW_OPT_TERSE (1 << 8)
#define BGP_SHOW_OPT_ROUTES_DETAIL (1 << 9)
+#define BGP_SHOW_OPT_INTERNAL_DATA (1 << 10)
/* Prototypes. */
extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi,
@@ -969,7 +970,7 @@ extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
const struct prefix *p, struct bgp_path_info *path, afi_t afi,
safi_t safi, enum rpki_states, json_object *json_paths,
- struct attr *attr);
+ struct attr *attr, uint16_t show_opts);
extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_table *table, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg,
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 1669aabc60..84ff88be16 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2349,6 +2349,13 @@ void bgp_zebra_instance_register(struct bgp *bgp)
bgp_zebra_advertise_all_vni(bgp, 1);
bgp_nht_register_nexthops(bgp);
+
+ /*
+ * Request SRv6 locator information from Zebra, if SRv6 is enabled
+ * and a locator is configured for this BGP instance.
+ */
+ if (bgp->srv6_enabled && bgp->srv6_locator_name[0] != '\0' && !bgp->srv6_locator)
+ bgp_zebra_srv6_manager_get_locator(bgp->srv6_locator_name);
}
/* Deregister this instance with Zebra. Invoked upon the instance
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 1034e49bae..2672f38291 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3418,17 +3418,6 @@ static struct bgp *bgp_create(as_t *as, const char *name,
}
bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp));
- bgp->as = *as;
- if (as_pretty)
- bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty);
- else
- bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as));
-
- if (asnotation != ASNOTATION_UNDEFINED) {
- bgp->asnotation = asnotation;
- SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
- } else
- asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation);
if (BGP_DEBUG(zebra, ZEBRA)) {
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
@@ -3472,6 +3461,18 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->peer = list_new();
peer_init:
+ bgp->as = *as;
+ if (as_pretty)
+ bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty);
+ else
+ bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as));
+
+ if (asnotation != ASNOTATION_UNDEFINED) {
+ bgp->asnotation = asnotation;
+ SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
+ } else
+ asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation);
+
bgp->peer->cmp = (int (*)(void *, void *))peer_cmp;
bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same,
"BGP Peer Hash");
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 42f7ca84dd..a1dd799392 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -4647,7 +4647,7 @@ incoming/outgoing directions.
If ``json`` option is specified, output is displayed in JSON format.
-.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes
+.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes [internal]
Display the detailed version of all routes. The same format as using
``show [ip] bgp [afi] [safi] PREFIX``, but for the whole BGP table.
@@ -4655,6 +4655,9 @@ incoming/outgoing directions.
If ``all`` option is specified, ``ip`` keyword is ignored and,
routes displayed for all AFIs and SAFIs.
+ ``internal`` option is used to display internal data additionally. JSON
+ output is not supported with this option.
+
If ``afi`` is specified, with ``all`` option, routes will be displayed for
each SAFI in the selected AFI.
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 3024bb57ea..5f95fe48a4 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -561,12 +561,6 @@ const struct frr_yang_module_info frr_isisd_info = {
}
},
{
- .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type",
- .cbs = {
- .modify = isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify,
- }
- },
- {
.xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list",
.cbs = {
.cli_show = cli_show_isis_frr_remote_lfa_plist,
@@ -598,12 +592,6 @@ const struct frr_yang_module_info frr_isisd_info = {
}
},
{
- .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type",
- .cbs = {
- .modify = isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify,
- }
- },
- {
.xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list",
.cbs = {
.cli_show = cli_show_isis_frr_remote_lfa_plist,
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index fb391534e2..6bd3b39bc7 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -1763,26 +1763,6 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy(
}
/*
- * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type
- */
-int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify(
- struct nb_cb_modify_args *args)
-{
- struct lfa_tiebreaker *tie_b;
- struct isis_area *area;
-
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- tie_b = nb_running_get_entry(args->dnode, NULL, true);
- area = tie_b->area;
- tie_b->type = yang_dnode_get_enum(args->dnode, NULL);
- lsp_regenerate_schedule(area, area->is_type, 0);
-
- return NB_OK;
-}
-
-/*
* XPath: /frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list
*/
int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify(
@@ -1912,26 +1892,6 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy(
}
/*
- * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type
- */
-int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify(
- struct nb_cb_modify_args *args)
-{
- struct lfa_tiebreaker *tie_b;
- struct isis_area *area;
-
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- tie_b = nb_running_get_entry(args->dnode, NULL, true);
- area = tie_b->area;
- tie_b->type = yang_dnode_get_enum(args->dnode, NULL);
- lsp_regenerate_schedule(area, area->is_type, 0);
-
- return NB_OK;
-}
-
-/*
* XPath: /frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list
*/
int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify(
diff --git a/lib/event.c b/lib/event.c
index 6081ba4727..8c09debf91 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -571,6 +571,11 @@ struct event_loop *event_master_create(const char *name)
rv->spin = true;
rv->handle_signals = true;
+ /* tardy event warnings */
+ monotime(&rv->last_tardy_warning);
+ rv->last_tardy_warning.tv_sec -= (TARDY_WARNING_INTERVAL + TIMER_SECOND_MICRO - 1) /
+ TIMER_SECOND_MICRO;
+
/* Set pthread owner, should be updated by actual owner */
rv->owner = pthread_self();
rv->cancel_req = list_new();
@@ -770,13 +775,13 @@ static struct event *thread_get(struct event_loop *m, uint8_t type,
thread->master = m;
thread->arg = arg;
thread->yield = EVENT_YIELD_TIME_SLOT; /* default */
+ thread->tardy_threshold = 0;
/* thread->ref is zeroed either by XCALLOC above or by memset before
* being put on the "unuse" list by thread_add_unuse().
* Setting it here again makes coverity complain about a missing
* lock :(
*/
/* thread->ref = NULL; */
- thread->ignore_timer_late = false;
/*
* So if the passed in funcname is not what we have
@@ -1023,6 +1028,8 @@ static void _event_add_timer_timeval(const struct xref_eventsched *xref,
return;
thread = thread_get(m, EVENT_TIMER, func, arg, xref);
+ /* default lateness warning: 4s */
+ thread->tardy_threshold = TARDY_DEFAULT_THRESHOLD;
frr_with_mutex (&thread->mtx) {
thread->u.sands = t;
@@ -1685,34 +1692,12 @@ static void thread_process_io(struct event_loop *m, unsigned int num)
static unsigned int thread_process_timers(struct event_loop *m,
struct timeval *timenow)
{
- struct timeval prev = *timenow;
- bool displayed = false;
struct event *thread;
unsigned int ready = 0;
while ((thread = event_timer_list_first(&m->timer))) {
if (timercmp(timenow, &thread->u.sands, <))
break;
- prev = thread->u.sands;
- prev.tv_sec += 4;
- /*
- * If the timer would have popped 4 seconds in the
- * past then we are in a situation where we are
- * really getting behind on handling of events.
- * Let's log it and do the right thing with it.
- */
- if (timercmp(timenow, &prev, >)) {
- atomic_fetch_add_explicit(
- &thread->hist->total_starv_warn, 1,
- memory_order_seq_cst);
- if (!displayed && !thread->ignore_timer_late) {
- flog_warn(
- EC_LIB_STARVE_THREAD,
- "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago",
- thread);
- displayed = true;
- }
- }
event_timer_list_pop(&m->timer);
thread->type = EVENT_READY;
@@ -1946,6 +1931,29 @@ void event_getrusage(RUSAGE_T *r)
#endif
}
+static void event_tardy_warn(struct event *thread, unsigned long since_us)
+{
+ char buf[64];
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) };
+ double loadavg[3];
+ int rv;
+
+ rv = getloadavg(loadavg, array_size(loadavg));
+ if (rv < 0)
+ bprintfrr(&fb, "not available");
+ else {
+ for (int i = 0; i < rv; i++) {
+ bprintfrr(&fb, "%.2f", loadavg[i]);
+ if (i < rv - 1)
+ bputs(&fb, ", ");
+ }
+ }
+
+ flog_warn(EC_LIB_STARVE_THREAD,
+ "CPU starvation: %pTHD getting executed %lums late, warning threshold %lums. System load: %pFB",
+ thread, (since_us + 999) / 1000, (thread->tardy_threshold + 999) / 1000, &fb);
+}
+
/*
* Call a thread.
*
@@ -1962,6 +1970,33 @@ void event_call(struct event *thread)
RUSAGE_T before, after;
bool suppress_warnings = EVENT_ARG(thread);
+ if (thread->tardy_threshold) {
+ int64_t timer_late_us = monotime_since(&thread->u.sands, NULL);
+
+ /* Timers have a tardiness warning defaulting to 4s.
+ * It can be customized with event_set_tardy_threshold()
+ * (bfdd does that since the protocol has really short timers)
+ *
+ * If we are more than that threshold late, print a warning
+ * since we're running behind in calling timers (probably due
+ * to high system load.)
+ */
+ if (timer_late_us > (int64_t)thread->tardy_threshold) {
+ int64_t since_last_warning;
+ struct timeval *tw;
+
+ atomic_fetch_add_explicit(&thread->hist->total_starv_warn, 1,
+ memory_order_seq_cst);
+
+ tw = &thread->master->last_tardy_warning;
+ since_last_warning = monotime_since(tw, NULL);
+ if (since_last_warning > TARDY_WARNING_INTERVAL) {
+ event_tardy_warn(thread, timer_late_us);
+ monotime(tw);
+ }
+ }
+ }
+
/* if the thread being called is the CLI, it may change cputime_enabled
* ("service cputime-stats" command), which can result in nonsensical
* and very confusing warnings
@@ -2145,9 +2180,9 @@ static ssize_t printfrr_thread_dbg(struct fbuf *buf, struct printfrr_eargs *ea,
char info[16] = "";
if (!thread)
- return bputs(buf, "{(thread *)NULL}");
+ return bputs(buf, "{(event *)NULL}");
- rv += bprintfrr(buf, "{(thread *)%p arg=%p", thread, thread->arg);
+ rv += bprintfrr(buf, "{(event *)%p arg=%p", thread, thread->arg);
if (thread->type < array_size(types) && types[thread->type])
rv += bprintfrr(buf, " %-6s", types[thread->type]);
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index 3a4bc712fc..0b4d7c77ae 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -20,6 +20,7 @@
#include "zlog.h"
#include "libfrr.h"
#include "libfrr_trace.h"
+#include "sigevent.h"
DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives");
@@ -185,10 +186,9 @@ int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
assert(frr_is_after_fork || !"trying to start thread before fork()");
- /* Ensure we never handle signals on a background thread by blocking
- * everything here (new thread inherits signal mask)
- */
- sigfillset(&blocksigs);
+ sigemptyset(&blocksigs);
+ frr_sigset_add_mainonly(&blocksigs);
+ /* new thread inherits mask */
pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs);
frrtrace(1, frr_libfrr, frr_pthread_run, fpt->name);
diff --git a/lib/frrcu.c b/lib/frrcu.c
index b85c525c58..1e7ed99eff 100644
--- a/lib/frrcu.c
+++ b/lib/frrcu.c
@@ -42,6 +42,7 @@
#include "frrcu.h"
#include "seqlock.h"
#include "atomlist.h"
+#include "sigevent.h"
DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread");
DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier");
@@ -346,7 +347,19 @@ static void rcu_start(void)
*/
sigset_t oldsigs, blocksigs;
- sigfillset(&blocksigs);
+ /* technically, the RCU thread is very poorly suited to run even just a
+ * crashlog handler, since zlog_sigsafe() could deadlock on transiently
+ * invalid (due to RCU) logging data structures
+ *
+ * but given that when we try to write a crashlog, we're already in
+ * b0rked territory anyway - give the crashlog handler a chance.
+ *
+ * (also cf. the SIGALRM usage in writing crashlogs to avoid hung
+ * processes on any kind of deadlock in crash handlers)
+ */
+ sigemptyset(&blocksigs);
+ frr_sigset_add_mainonly(&blocksigs);
+ /* new thread inherits mask */
pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs);
rcu_active = true;
diff --git a/lib/frrevent.h b/lib/frrevent.h
index c35b39a147..61baf7919c 100644
--- a/lib/frrevent.h
+++ b/lib/frrevent.h
@@ -95,6 +95,7 @@ struct event_loop {
bool ready_run_loop;
RUSAGE_T last_getrusage;
+ struct timeval last_tardy_warning;
};
/* Event types. */
@@ -126,11 +127,17 @@ struct event {
struct timeval real;
struct cpu_event_history *hist; /* cache pointer to cpu_history */
unsigned long yield; /* yield time in microseconds */
+ /* lateness warning threshold, usec. 0 if it's not a timer. */
+ unsigned long tardy_threshold;
const struct xref_eventsched *xref; /* origin location */
pthread_mutex_t mtx; /* mutex for thread.c functions */
- bool ignore_timer_late;
};
+/* rate limit late timer warnings */
+#define TARDY_WARNING_INTERVAL 10 * TIMER_SECOND_MICRO
+/* default threshold for late timer warning */
+#define TARDY_DEFAULT_THRESHOLD 4 * TIMER_SECOND_MICRO
+
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pTH"(struct event *)
#endif
@@ -305,9 +312,17 @@ static inline bool event_is_scheduled(struct event *thread)
/* Debug signal mask */
void debug_signals(const sigset_t *sigs);
+/* getting called more than given microseconds late will print a warning.
+ * Default if not called: 4s. Don't call this on non-timers.
+ */
+static inline void event_set_tardy_threshold(struct event *event, unsigned long thres)
+{
+ event->tardy_threshold = thres;
+}
+
static inline void event_ignore_late_timer(struct event *event)
{
- event->ignore_timer_late = true;
+ event->tardy_threshold = 0;
}
#ifdef __cplusplus
diff --git a/lib/sigevent.h b/lib/sigevent.h
index 0b07f594c1..2c51ba3767 100644
--- a/lib/sigevent.h
+++ b/lib/sigevent.h
@@ -45,6 +45,33 @@ bool frr_sigevent_check(sigset_t *setp);
/* check whether there are signals to handle, process any found */
extern int frr_sigevent_process(void);
+/* Ensure we don't handle "application-type" signals on a secondary thread by
+ * blocking these signals when creating threads
+ *
+ * NB: SIGSEGV, SIGABRT, etc. must be allowed on all threads or we get no
+ * crashlogs. Since signals vary a little bit between platforms, below is a
+ * list of known things to go to the main thread. Any unknown signals should
+ * stay thread-local.
+ */
+static inline void frr_sigset_add_mainonly(sigset_t *blocksigs)
+{
+ /* signals we actively handle */
+ sigaddset(blocksigs, SIGHUP);
+ sigaddset(blocksigs, SIGINT);
+ sigaddset(blocksigs, SIGTERM);
+ sigaddset(blocksigs, SIGUSR1);
+
+ /* signals we don't actively use but that semantically belong */
+ sigaddset(blocksigs, SIGUSR2);
+ sigaddset(blocksigs, SIGQUIT);
+ sigaddset(blocksigs, SIGCHLD);
+ sigaddset(blocksigs, SIGPIPE);
+ sigaddset(blocksigs, SIGTSTP);
+ sigaddset(blocksigs, SIGTTIN);
+ sigaddset(blocksigs, SIGTTOU);
+ sigaddset(blocksigs, SIGWINCH);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/zlog_5424.c b/lib/zlog_5424.c
index 4c60d4b405..6265ce3b1f 100644
--- a/lib/zlog_5424.c
+++ b/lib/zlog_5424.c
@@ -782,7 +782,7 @@ static void zlog_5424_cycle(struct zlog_cfg_5424 *zcf, int fd)
}
old = zcf->active ? &zcf->active->zt : NULL;
- old = zlog_target_replace(old, &zlt->zt);
+ old = zlog_target_replace(old, zlt ? &zlt->zt : NULL);
zcf->active = zlt;
/* oldt->fd == fd happens for zlog_5424_apply_meta() */
@@ -1076,9 +1076,17 @@ bool zlog_5424_apply_dst(struct zlog_cfg_5424 *zcf)
bool zlog_5424_apply_meta(struct zlog_cfg_5424 *zcf)
{
+ int fd;
+
frr_with_mutex (&zcf->cfg_mtx) {
if (zcf->active)
- zlog_5424_cycle(zcf, zcf->active->fd);
+ fd = zcf->active->fd;
+ else if (zcf->prio_min != ZLOG_DISABLED)
+ fd = zlog_5424_open(zcf, -1);
+ else
+ fd = -1;
+ if (fd >= 0)
+ zlog_5424_cycle(zcf, fd);
}
return true;
diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c
index be909c862a..564e04deba 100644
--- a/nhrpd/netlink_arp.c
+++ b/nhrpd/netlink_arp.c
@@ -184,7 +184,7 @@ int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
: (cmd == ZEBRA_NEIGH_ADDED) ? "new-neigh"
: "del-neigh",
&addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type);
- if (cmd == ZEBRA_NEIGH_GET) {
+ if (cmd == ZEBRA_NEIGH_GET && ndm_state != ZEBRA_NEIGH_STATE_INCOMPLETE) {
if (c->cur.type >= NHRP_CACHE_CACHED) {
nhrp_cache_set_used(c, 1);
debugf(NHRP_DEBUG_KERNEL,
diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py
index 1d7aa97473..c454c9c4a4 100644
--- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py
+++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py
@@ -78,6 +78,13 @@ def setup_module(mod):
"tcpdump -nni r1-eth0 -s 0 -w {} &".format(pcap_file), stdout=None
)
+ tgen.net["r2"].cmd(
+ """
+ip link add vrf1 type vrf table 10
+ip link set vrf1 up
+"""
+ )
+
for _, (rname, router) in enumerate(tgen.routers().items(), 1):
logger.info("Loading router %s" % rname)
router.load_frr_config(
diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf
index d3ababde3a..e3f8b242a1 100644
--- a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf
+++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf
@@ -1,3 +1,7 @@
+vrf DONNA
+ ip route 172.16.3.0/24 10.0.0.254
+exit-vrf
+!
int dummy0
ip address 10.0.4.1/24
no shut
@@ -28,6 +32,9 @@ ip router-id 10.0.4.1
!
router bgp 99
no bgp ebgp-requires-policy
+ ! 10.0.4.254 peer session will not be established
+ ! it is there just to activate the ipv4 vpn table
+ neighbor 10.0.4.254 remote-as external
address-family ipv4 unicast
redistribute connected
rd vpn export 10.0.4.1:1
@@ -36,11 +43,14 @@ router bgp 99
export vpn
import vpn
!
+ address-family ipv4 vpn
+ neighbor 10.0.4.254 activate
!
router bgp 99 vrf DONNA
no bgp ebgp-requires-policy
address-family ipv4 unicast
redistribute connected
+ network 172.16.3.0/24
label vpn export 101
rd vpn export 10.0.4.1:1
rt vpn export 10.0.4.1:101
diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json
new file mode 100644
index 0000000000..c7ff2f4f80
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json
@@ -0,0 +1,155 @@
+{
+ "routerId": "10.0.4.1",
+ "localAS": 99,
+ "routes": {
+ "routeDistinguishers": {
+ "10.0.4.1:1": {
+ "10.0.0.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "default",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "IGP",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "IGP",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.101.0/24": [
+ {
+ "valid": null,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "IGP",
+ "announceNexthopSelf": true,
+ "nhVrfName": "ZITA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
+
diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json
new file mode 100644
index 0000000000..1797d78582
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json
@@ -0,0 +1,103 @@
+{
+ "routerId": "10.0.4.1",
+ "localAS": 99,
+ "routes": {
+ "routeDistinguishers": {
+ "10.0.4.1:1": {
+ "10.0.0.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "default",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.3.0/24": null,
+ "172.16.101.0/24": null
+ }
+ }
+ }
+}
+
diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json
new file mode 100644
index 0000000000..4b0eaaa052
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json
@@ -0,0 +1,120 @@
+{
+ "routerId": "10.0.4.1",
+ "localAS": 99,
+ "routes": {
+ "routeDistinguishers": {
+ "10.0.4.1:1": {
+ "10.0.0.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24": [
+ {
+ "valid": null,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24": [
+ {
+ "valid": null,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "default",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "IGP",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.101.0/24": null
+ }
+ }
+ }
+}
+
diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json
new file mode 100644
index 0000000000..de18bc8463
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json
@@ -0,0 +1,120 @@
+{
+ "routerId": "10.0.4.1",
+ "localAS": 99,
+ "routes": {
+ "routeDistinguishers": {
+ "10.0.4.1:1": {
+ "10.0.0.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "default",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "IGP",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.101.0/24": null
+ }
+ }
+ }
+}
+
diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json
new file mode 100644
index 0000000000..0c249e241e
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json
@@ -0,0 +1,137 @@
+{
+ "routerId": "10.0.4.1",
+ "localAS": 99,
+ "routes": {
+ "routeDistinguishers": {
+ "10.0.4.1:1": {
+ "10.0.0.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "EVA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "default",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.3.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "IGP",
+ "announceNexthopSelf": true,
+ "nhVrfName": "DONNA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "172.16.101.0/24": [
+ {
+ "valid": true,
+ "pathFrom": "external",
+ "path": "",
+ "origin": "IGP",
+ "announceNexthopSelf": true,
+ "nhVrfName": "ZITA",
+ "nexthops": [
+ {
+ "ip": "0.0.0.0",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
+
diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py
index a44f07b560..67e53cb0cc 100644
--- a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py
+++ b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py
@@ -13,6 +13,7 @@
Test basic VPNv4 route leaking
"""
+import json
import os
import sys
from functools import partial
@@ -60,6 +61,22 @@ def teardown_module(mod):
tgen.stop_topology()
+def test_bgp_convergence():
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
+
def test_vrf_route_leak_donna():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
@@ -119,20 +136,20 @@ def test_vrf_route_leak_donna():
],
},
],
- "172.16.101.0/24": [
+ "172.16.3.0/24": [
{
- "protocol": "bgp",
- "selected": None,
+ "protocol": "static",
+ "selected": True,
"nexthops": [
{
- "fib": None,
- "interfaceName": "unknown",
- "vrf": "Unknown",
- "active": None,
- },
+ "fib": True,
+ "interfaceName": "dummy1",
+ "active": True,
+ }
],
},
],
+ "172.16.101.0/24": None,
}
test_func = partial(
@@ -191,20 +208,21 @@ def test_vrf_route_leak_eva():
"protocol": "connected",
}
],
- "172.16.101.0/24": [
+ "172.16.3.0/24": [
{
"protocol": "bgp",
- "selected": None,
+ "selected": True,
"nexthops": [
{
- "fib": None,
- "interfaceName": "unknown",
- "vrf": "Unknown",
- "active": None,
- },
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ }
],
},
],
+ "172.16.101.0/24": None,
}
test_func = partial(
@@ -258,6 +276,20 @@ def test_vrf_route_leak_default():
"protocol": "connected",
}
],
+ "172.16.3.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ }
+ ],
+ },
+ ],
}
test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
@@ -298,34 +330,8 @@ interface EVA
# Test DONNA VRF.
expect = {
- "10.0.1.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "EVA",
- "vrf": "EVA",
- "active": None,
- },
- ],
- },
- ],
- "10.0.3.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "EVA",
- "vrf": "EVA",
- "active": None,
- },
- ],
- },
- ],
+ "10.0.1.0/24": None,
+ "10.0.3.0/24": None,
}
test_func = partial(
@@ -349,6 +355,14 @@ interface EVA
result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+ # check BGP IPv4 VPN table
+ json_file = "{}/{}/show_bgp_ipv4_vpn_eva_down.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
def test_vrf_route_leak_donna_after_eva_up():
logger.info("Ensure that route states change after EVA interface goes up")
@@ -404,6 +418,14 @@ interface EVA
result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+ # check BGP IPv4 VPN table
+ json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
def test_vrf_route_leak_donna_add_vrf_zita():
logger.info("Add VRF ZITA and ensure that the route from VRF ZITA is updated")
@@ -417,20 +439,7 @@ def test_vrf_route_leak_donna_add_vrf_zita():
# Test DONNA VRF.
expect = {
- "172.16.101.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "ZITA",
- "vrf": "ZITA",
- "active": None,
- },
- ],
- },
- ],
+ "172.16.101.0/24": None,
}
test_func = partial(
@@ -439,6 +448,14 @@ def test_vrf_route_leak_donna_add_vrf_zita():
result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+ # check BGP IPv4 VPN table
+ json_file = "{}/{}/show_bgp_ipv4_vpn_add_zita.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
def test_vrf_route_leak_donna_set_zita_up():
logger.info("Set VRF ZITA up and ensure that the route from VRF ZITA is updated")
@@ -480,6 +497,14 @@ interface ZITA
result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+ # check BGP IPv4 VPN table
+ json_file = "{}/{}/show_bgp_ipv4_vpn_zita_up.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
def test_vrf_route_leak_donna_delete_vrf_zita():
logger.info("Delete VRF ZITA and ensure that the route from VRF ZITA is deleted")
@@ -502,6 +527,101 @@ def test_vrf_route_leak_donna_delete_vrf_zita():
result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+ # check BGP IPv4 VPN table
+ json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
+
+def test_vrf_route_leak_default_delete_prefix():
+ logger.info(
+ "Remove BGP static prefix 172.16.3.0/24 from VRF DONNA and ensure that the route is deleted on default"
+ )
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r1.vtysh_cmd(
+ """
+configure
+router bgp 99 vrf DONNA
+ address-family ipv4 unicast
+ no network 172.16.3.0/24
+"""
+ )
+
+ # Test default VRF.
+ expect = {
+ "172.16.3.0/24": None,
+ }
+
+ test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP VRF default check failed:\n{}".format(diff)
+
+ # check BGP IPv4 VPN table
+ json_file = "{}/{}/show_bgp_ipv4_vpn_del_donna_prefix.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
+
+def test_vrf_route_leak_default_prefix_back():
+ logger.info(
+ "Set back BGP static prefix 172.16.3.0/24 to VRF DONNA and ensure that the route is set on default"
+ )
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r1.vtysh_cmd(
+ """
+configure
+router bgp 99 vrf DONNA
+ address-family ipv4 unicast
+ network 172.16.3.0/24
+"""
+ )
+
+ # Test default VRF.
+ expect = {
+ "172.16.3.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ }
+ ],
+ },
+ ],
+ }
+
+ test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP VRF default check failed:\n{}".format(diff)
+
+ # check BGP IPv4 VPN table
+ json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name)
+ expect = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff)
+
def test_memory_leak():
"Run the memory leak test and report results."
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
index 6d4b436bcc..3bc36862bf 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
+++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
@@ -123,20 +123,7 @@ def test_vrf_route_leak_donna():
],
},
],
- "172.16.101.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "unknown",
- "vrf": "Unknown",
- "active": None,
- },
- ],
- },
- ],
+ "172.16.101.0/24": None,
}
test_func = partial(
@@ -195,20 +182,7 @@ def test_vrf_route_leak_eva():
"protocol": "connected",
}
],
- "172.16.101.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "unknown",
- "vrf": "Unknown",
- "active": None,
- },
- ],
- },
- ],
+ "172.16.101.0/24": None,
}
test_func = partial(
@@ -302,34 +276,8 @@ interface EVA
# Test DONNA VRF.
expect = {
- "10.0.1.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "EVA",
- "vrf": "EVA",
- "active": None,
- },
- ],
- },
- ],
- "10.0.3.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "EVA",
- "vrf": "EVA",
- "active": None,
- },
- ],
- },
- ],
+ "10.0.1.0/24": None,
+ "10.0.3.0/24": None,
}
test_func = partial(
@@ -421,20 +369,7 @@ def test_vrf_route_leak_donna_add_vrf_zita():
# Test DONNA VRF.
expect = {
- "172.16.101.0/24": [
- {
- "protocol": "bgp",
- "selected": None,
- "nexthops": [
- {
- "fib": None,
- "interfaceName": "ZITA",
- "vrf": "ZITA",
- "active": None,
- },
- ],
- },
- ],
+ "172.16.101.0/24": None,
}
test_func = partial(
diff --git a/zebra/fpm_listener.c b/zebra/fpm_listener.c
index ed0842a3b1..140cfa77cf 100644
--- a/zebra/fpm_listener.c
+++ b/zebra/fpm_listener.c
@@ -189,7 +189,7 @@ read_fpm_msg(char *buf, size_t buf_len)
fprintf(stderr,
"Read %lu bytes but expected to read %lu bytes instead\n",
bytes_read, need_len);
- return NULL;
+ continue;
}
if (reading_full_msg)