summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_open.c1
-rw-r--r--bgpd/bgp_packet.c99
-rw-r--r--bgpd/bgp_vty.c27
-rw-r--r--bgpd/bgpd.c3
-rw-r--r--doc/developer/logging.rst14
-rw-r--r--ldpd/lde.c5
-rw-r--r--ldpd/ldpd.c60
-rw-r--r--ldpd/ldpd.h2
-rw-r--r--ldpd/ldpe.c5
-rw-r--r--ldpd/log.c138
-rw-r--r--ldpd/log.h43
-rw-r--r--ldpd/subdir.am1
-rw-r--r--lib/affinitymap.c2
-rw-r--r--lib/mgmt_msg_native.c1
-rw-r--r--lib/netns_other.c5
-rw-r--r--lib/northbound_sysrepo.c2
-rw-r--r--lib/printf/README1
-rw-r--r--lib/printf/printflocal.h1
-rw-r--r--lib/printf/vfprintf.c44
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/yang.c10
-rw-r--r--lib/zlog.c97
-rw-r--r--lib/zlog.h3
-rw-r--r--lib/zlog_recirculate.c56
-rw-r--r--lib/zlog_recirculate.h12
-rw-r--r--ripd/rip_cli.c32
-rw-r--r--ripd/ripd.c33
-rw-r--r--ripd/subdir.am1
-rw-r--r--ripngd/ripng_cli.c32
-rw-r--r--ripngd/ripngd.c33
-rw-r--r--ripngd/subdir.am1
-rw-r--r--tests/lib/test_printfrr.c12
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py42
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py122
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py36
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py45
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py37
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py37
-rw-r--r--zebra/main.c1
-rw-r--r--zebra/zserv.c55
40 files changed, 822 insertions, 331 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index aa1d81362b..15738e673b 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -2039,7 +2039,6 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
* or disable its use, and that switch MUST be off by default.
*/
if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION) ||
- CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY) ||
peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) {
SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 55d3efde23..8a36a3f4c8 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1240,7 +1240,6 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
/* Encode MP_EXT capability. */
switch (capability_code) {
case CAPABILITY_CODE_SOFT_VERSION:
- SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV);
stream_putc(s, action);
stream_putc(s, CAPABILITY_CODE_SOFT_VERSION);
cap_len = stream_get_endp(s);
@@ -1271,6 +1270,9 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
: "Removing",
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
+
+ COND_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV,
+ action == CAPABILITY_ACTION_SET);
break;
case CAPABILITY_CODE_MP:
stream_putc(s, action);
@@ -1290,11 +1292,6 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
iana_safi2str(pkt_safi));
break;
case CAPABILITY_CODE_RESTART:
- if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) &&
- !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER))
- return;
-
- SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
stream_putc(s, action);
stream_putc(s, CAPABILITY_CODE_RESTART);
cap_len = stream_get_endp(s);
@@ -1343,13 +1340,10 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
+ COND_FLAG(peer->cap, PEER_CAP_RESTART_ADV,
+ action == CAPABILITY_ACTION_SET);
break;
case CAPABILITY_CODE_LLGR:
- if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV))
- return;
-
- SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV);
-
stream_putc(s, action);
stream_putc(s, CAPABILITY_CODE_LLGR);
cap_len = stream_get_endp(s);
@@ -1381,10 +1375,11 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
: "Removing",
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
+
+ COND_FLAG(peer->cap, PEER_CAP_LLGR_ADV,
+ action == CAPABILITY_ACTION_SET);
break;
case CAPABILITY_CODE_ADDPATH:
- SET_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV);
-
FOREACH_AFI_SAFI (afi, safi) {
if (peer->afc[afi][safi]) {
addpath_afi_safi_count++;
@@ -1462,10 +1457,10 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
+ COND_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV,
+ action == CAPABILITY_ACTION_SET);
break;
case CAPABILITY_CODE_PATHS_LIMIT:
- SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV);
-
FOREACH_AFI_SAFI (afi, safi) {
if (!peer->afc[afi][safi])
continue;
@@ -1505,6 +1500,8 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
.send);
}
+ COND_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV,
+ action == CAPABILITY_ACTION_SET);
break;
case CAPABILITY_CODE_ORF:
/* Convert AFI, SAFI to values for packet. */
@@ -1578,43 +1575,42 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
iana_safi2str(pkt_safi));
break;
case CAPABILITY_CODE_FQDN:
- if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN) &&
- hostname) {
- SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV);
- stream_putc(s, action);
- stream_putc(s, CAPABILITY_CODE_FQDN);
- cap_len = stream_get_endp(s);
- stream_putc(s, 0); /* Capability Length */
-
- len = strlen(hostname);
+ stream_putc(s, action);
+ stream_putc(s, CAPABILITY_CODE_FQDN);
+ cap_len = stream_get_endp(s);
+ stream_putc(s, 0); /* Capability Length */
+
+ len = strlen(hostname);
+ if (len > BGP_MAX_HOSTNAME)
+ len = BGP_MAX_HOSTNAME;
+
+ stream_putc(s, len);
+ stream_put(s, hostname, len);
+
+ if (domainname) {
+ len = strlen(domainname);
if (len > BGP_MAX_HOSTNAME)
len = BGP_MAX_HOSTNAME;
stream_putc(s, len);
- stream_put(s, hostname, len);
-
- if (domainname) {
- len = strlen(domainname);
- if (len > BGP_MAX_HOSTNAME)
- len = BGP_MAX_HOSTNAME;
+ stream_put(s, domainname, len);
+ } else
+ stream_putc(s, 0);
- stream_putc(s, len);
- stream_put(s, domainname, len);
- } else
- stream_putc(s, 0);
+ len = stream_get_endp(s) - cap_len - 1;
+ stream_putc_at(s, cap_len, len);
- len = stream_get_endp(s) - cap_len - 1;
- stream_putc_at(s, cap_len, len);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s",
+ peer,
+ action == CAPABILITY_ACTION_SET
+ ? "Advertising"
+ : "Removing",
+ capability, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
- if (bgp_debug_neighbor_events(peer))
- zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s",
- peer,
- action == CAPABILITY_ACTION_SET
- ? "Advertising"
- : "Removing",
- capability, iana_afi2str(pkt_afi),
- iana_safi2str(pkt_safi));
- }
+ COND_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV,
+ action == CAPABILITY_ACTION_SET);
break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
@@ -1624,13 +1620,12 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
case CAPABILITY_CODE_EXT_MESSAGE:
break;
case CAPABILITY_CODE_ROLE:
- if (peer->local_role != ROLE_UNDEFINED) {
- SET_FLAG(peer->cap, PEER_CAP_ROLE_ADV);
- stream_putc(s, action);
- stream_putc(s, CAPABILITY_CODE_ROLE);
- stream_putc(s, CAPABILITY_CODE_ROLE_LEN);
- stream_putc(s, peer->local_role);
- }
+ stream_putc(s, action);
+ stream_putc(s, CAPABILITY_CODE_ROLE);
+ stream_putc(s, CAPABILITY_CODE_ROLE_LEN);
+ stream_putc(s, peer->local_role);
+ COND_FLAG(peer->cap, PEER_CAP_ROLE_ADV,
+ action == CAPABILITY_ACTION_SET);
break;
default:
break;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index efc71bc8a7..2920405780 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -3260,6 +3260,8 @@ DEFUN (bgp_graceful_restart_disable,
GR_DISABLE)
{
int ret = BGP_GR_FAILURE;
+ struct listnode *node, *nnode;
+ struct peer *peer;
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
@@ -3278,6 +3280,15 @@ DEFUN (bgp_graceful_restart_disable,
vty_out(vty,
"Graceful restart configuration changed, reset all peers to take effect\n");
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
+ CAPABILITY_CODE_RESTART,
+ CAPABILITY_ACTION_UNSET);
+ bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
+ CAPABILITY_CODE_LLGR,
+ CAPABILITY_ACTION_UNSET);
+ }
+
return bgp_vty_return(vty, ret);
}
@@ -18416,9 +18427,19 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
}
/* capability software-version */
- if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION))
- vty_out(vty, " neighbor %s capability software-version\n",
- addr);
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) {
+ if (!peergroup_flag_check(peer,
+ PEER_FLAG_CAPABILITY_SOFT_VERSION))
+ vty_out(vty,
+ " no neighbor %s capability software-version\n",
+ addr);
+ } else {
+ if (peergroup_flag_check(peer,
+ PEER_FLAG_CAPABILITY_SOFT_VERSION))
+ vty_out(vty,
+ " neighbor %s capability software-version\n",
+ addr);
+ }
/* dont-capability-negotiation */
if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY))
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index e7712f0f3e..be816c3361 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1541,6 +1541,9 @@ struct peer *peer_new(struct bgp *bgp)
if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS))
SET_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS);
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY))
+ SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_SOFT_VERSION);
+
SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_FQDN);
SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN);
diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst
index 52653d3768..6058b8c0fc 100644
--- a/doc/developer/logging.rst
+++ b/doc/developer/logging.rst
@@ -77,7 +77,14 @@ are available:
.. note::
- ``printfrr()`` does not support the ``%n`` format.
+ ``printfrr()`` does not support the ``%n`` format. It does support ISO C23
+ ``%b``, ``%w99d`` and ``%wf99d`` additions, but the latter two are not
+ supported by the ``frr-format`` plugin yet, and all 3 aren't supported by
+ the older compilers still in use on some supported platforms.
+
+ ``%b`` can be used with ``FMT_NSTD``, but ``%w99d`` and ``%wf99d`` require
+ work in the ``frr-format`` plugin before they are really usable.
+
AS-Safety
^^^^^^^^^
@@ -557,8 +564,9 @@ Integer formats
cause compiler warnings when used without the plugin. Use with
:c:macro:`FMT_NSTD` if necessary.
- It is possible ISO C23 may introduce another format for these, possibly
- ``%w64d`` discussed in `JTC 1/SC 22/WG 14/N2680 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2680.pdf>`_.
+ As anticipated, ISO C23 has introduced new modifiers for this, specifically
+ ``%w64d`` (= ``%Ld``) and ``%w64u`` (= ``%Lu``). Unfortunately, these new
+ modifiers are not supported by ``frr-format`` yet.
.. frrfmt:: %Lu (uint64_t)
diff --git a/ldpd/lde.c b/ldpd/lde.c
index ef4aecadad..876dd41630 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -28,6 +28,7 @@
#include "stream.h"
#include "network.h"
#include "libfrr.h"
+#include "zlog_live.h"
static void lde_shutdown(void);
static void lde_dispatch_imsg(struct event *thread);
@@ -116,6 +117,8 @@ static struct frr_signal_t lde_signals[] =
void
lde(void)
{
+ static struct zlog_live_cfg child_log;
+
#ifdef HAVE_SETPROCTITLE
setproctitle("label decision engine");
#endif
@@ -123,6 +126,8 @@ lde(void)
log_procname = log_procnames[PROC_LDE_ENGINE];
master = frr_init();
+ zlog_live_open_fd(&child_log, LOG_DEBUG, LDPD_FD_LOG);
+
/* no frr_config_fork() here, allow frr_pthread to create threads */
frr_is_after_fork = true;
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index da29a4f20d..492a36b3d6 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -35,9 +35,10 @@
#include "qobj.h"
#include "libfrr.h"
#include "lib_errors.h"
+#include "zlog_recirculate.h"
static void ldpd_shutdown(void);
-static pid_t start_child(enum ldpd_process, char *, int, int);
+static pid_t start_child(enum ldpd_process, char *, int, int, int);
static void main_dispatch_ldpe(struct event *thread);
static void main_dispatch_lde(struct event *thread);
static int main_imsg_send_ipc_sockets(struct imsgbuf *,
@@ -69,6 +70,8 @@ DEFINE_QOBJ_TYPE(l2vpn_pw);
DEFINE_QOBJ_TYPE(l2vpn);
DEFINE_QOBJ_TYPE(ldpd_conf);
+const char *log_procname;
+
struct ldpd_global global;
struct ldpd_init init;
struct ldpd_conf *ldpd_conf, *vty_conf;
@@ -231,8 +234,12 @@ main(int argc, char *argv[])
{
char *saved_argv0;
int lflag = 0, eflag = 0;
- int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2];
- int pipe_parent2lde[2], pipe_parent2lde_sync[2];
+ int pipe_parent2ldpe[2];
+ int pipe_parent2ldpe_sync[2];
+ int pipe_ldpe_log[2];
+ int pipe_parent2lde[2];
+ int pipe_parent2lde_sync[2];
+ int pipe_lde_log[2];
bool ctl_sock_used = false;
ldpd_process = PROC_MAIN;
@@ -300,15 +307,6 @@ main(int argc, char *argv[])
exit(1);
}
- if (lflag || eflag) {
- struct zprivs_ids_t ids;
-
- zprivs_preinit(&ldpd_privs);
- zprivs_get_ids(&ids);
-
- zlog_init(ldpd_di.progname, "LDP", 0,
- ids.uid_normal, ids.gid_normal);
- }
if (lflag)
lde();
else if (eflag)
@@ -321,6 +319,9 @@ main(int argc, char *argv[])
pipe_parent2ldpe_sync) == -1)
fatal("socketpair");
+ if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, pipe_ldpe_log) == -1)
+ fatal("socketpair");
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2lde) == -1)
fatal("socketpair");
@@ -328,6 +329,9 @@ main(int argc, char *argv[])
pipe_parent2lde_sync) == -1)
fatal("socketpair");
+ if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, pipe_lde_log) == -1)
+ fatal("socketpair");
+
sock_set_nonblock(pipe_parent2ldpe[0]);
sock_set_cloexec(pipe_parent2ldpe[0]);
sock_set_nonblock(pipe_parent2ldpe[1]);
@@ -335,6 +339,11 @@ main(int argc, char *argv[])
sock_set_nonblock(pipe_parent2ldpe_sync[0]);
sock_set_cloexec(pipe_parent2ldpe_sync[0]);
sock_set_cloexec(pipe_parent2ldpe_sync[1]);
+ sock_set_nonblock(pipe_ldpe_log[0]);
+ sock_set_cloexec(pipe_ldpe_log[0]);
+ sock_set_nonblock(pipe_ldpe_log[1]);
+ sock_set_cloexec(pipe_ldpe_log[1]);
+
sock_set_nonblock(pipe_parent2lde[0]);
sock_set_cloexec(pipe_parent2lde[0]);
sock_set_nonblock(pipe_parent2lde[1]);
@@ -342,14 +351,24 @@ main(int argc, char *argv[])
sock_set_nonblock(pipe_parent2lde_sync[0]);
sock_set_cloexec(pipe_parent2lde_sync[0]);
sock_set_cloexec(pipe_parent2lde_sync[1]);
+ sock_set_nonblock(pipe_lde_log[0]);
+ sock_set_cloexec(pipe_lde_log[0]);
+ sock_set_nonblock(pipe_lde_log[1]);
+ sock_set_cloexec(pipe_lde_log[1]);
/* start children */
lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0,
- pipe_parent2lde[1], pipe_parent2lde_sync[1]);
+ pipe_parent2lde[1], pipe_parent2lde_sync[1], pipe_lde_log[1]);
ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0,
- pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1]);
+ pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1], pipe_ldpe_log[1]);
master = frr_init();
+ /* The two child processes use the zlog_live backend to send their
+ * messages here, where the actual logging config is then applied.
+ * Look for zlog_live_open_fd() to find the other end of this.
+ */
+ zlog_recirculate_subscribe(master, pipe_lde_log[0]);
+ zlog_recirculate_subscribe(master, pipe_ldpe_log[0]);
vrf_init(NULL, NULL, NULL, NULL);
access_list_init();
@@ -484,7 +503,8 @@ ldpd_shutdown(void)
}
static pid_t
-start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync)
+start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
+ int fd_log)
{
char *argv[7];
int argc = 0, nullfd;
@@ -499,6 +519,7 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync)
default:
close(fd_async);
close(fd_sync);
+ close(fd_log);
return (pid);
}
@@ -520,6 +541,9 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync)
if (dup2(fd_sync, LDPD_FD_SYNC) == -1)
fatal("cannot setup imsg sync fd");
+ if (dup2(fd_log, LDPD_FD_LOG) == -1)
+ fatal("cannot setup zlog fd");
+
argv[argc++] = argv0;
switch (p) {
case PROC_MAIN:
@@ -569,9 +593,6 @@ static void main_dispatch_ldpe(struct event *thread)
break;
switch (imsg.hdr.type) {
- case IMSG_LOG:
- logit(imsg.hdr.pid, "%s", (const char *)imsg.data);
- break;
case IMSG_REQUEST_SOCKETS:
af = imsg.hdr.pid;
main_imsg_send_net_sockets(af);
@@ -637,9 +658,6 @@ static void main_dispatch_lde(struct event *thread)
break;
switch (imsg.hdr.type) {
- case IMSG_LOG:
- logit(imsg.hdr.pid, "%s", (const char *)imsg.data);
- break;
case IMSG_KLABEL_CHANGE:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(struct kroute))
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index 81c6ba3ccd..ad831a6ea3 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -30,6 +30,7 @@
#define LDPD_FD_ASYNC 3
#define LDPD_FD_SYNC 4
+#define LDPD_FD_LOG 5
#define LDPD_OPT_VERBOSE 0x00000001
#define LDPD_OPT_VERBOSE2 0x00000002
@@ -139,7 +140,6 @@ enum imsg_type {
IMSG_RECONF_L2VPN_IPW,
IMSG_RECONF_END,
IMSG_DEBUG_UPDATE,
- IMSG_LOG,
IMSG_ACL_CHECK,
IMSG_INIT,
IMSG_PW_UPDATE,
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index e66b9e92dd..6e844c0aa1 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -23,6 +23,7 @@
#include "privs.h"
#include "sigevent.h"
#include "libfrr.h"
+#include "zlog_live.h"
static void ldpe_shutdown(void);
static void ldpe_dispatch_main(struct event *thread);
@@ -93,6 +94,8 @@ char *pkt_ptr; /* packet buffer */
void
ldpe(void)
{
+ static struct zlog_live_cfg child_log;
+
#ifdef HAVE_SETPROCTITLE
setproctitle("ldp engine");
#endif
@@ -100,6 +103,8 @@ ldpe(void)
log_procname = log_procnames[ldpd_process];
master = frr_init();
+ zlog_live_open_fd(&child_log, LOG_DEBUG, LDPD_FD_LOG);
+
/* no frr_config_fork() here, allow frr_pthread to create threads */
frr_is_after_fork = true;
diff --git a/ldpd/log.c b/ldpd/log.c
deleted file mode 100644
index 7c4d782dcf..0000000000
--- a/ldpd/log.c
+++ /dev/null
@@ -1,138 +0,0 @@
-// SPDX-License-Identifier: ISC
-/* $OpenBSD$ */
-
-/*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
- */
-
-#include <zebra.h>
-
-#include "ldpd.h"
-#include "ldpe.h"
-#include "lde.h"
-#include "log.h"
-#include "printfrr.h"
-
-#include <lib/log.h>
-
-const char *log_procname;
-
-void
-logit(int pri, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vlog(pri, fmt, ap);
- va_end(ap);
-}
-
-void
-vlog(int pri, const char *fmt, va_list ap)
-{
- char buf[1024];
-
- switch (ldpd_process) {
- case PROC_LDE_ENGINE:
- vsnprintfrr(buf, sizeof(buf), fmt, ap);
- lde_imsg_compose_parent_sync(IMSG_LOG, pri, buf, strlen(buf) + 1);
- break;
- case PROC_LDP_ENGINE:
- vsnprintfrr(buf, sizeof(buf), fmt, ap);
- ldpe_imsg_compose_parent_sync(IMSG_LOG, pri, buf, strlen(buf) + 1);
- break;
- case PROC_MAIN:
- vzlog(pri, fmt, ap);
- break;
- }
-}
-
-void
-log_warn(const char *emsg, ...)
-{
- char *nfmt;
- va_list ap;
-
- /* best effort to even work in out of memory situations */
- if (emsg == NULL)
- logit(LOG_ERR, "%s", strerror(errno));
- else {
- va_start(ap, emsg);
-
- if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) {
- /* we tried it... */
- vlog(LOG_ERR, emsg, ap);
- logit(LOG_ERR, "%s", strerror(errno));
- } else {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
- /* format extended above */
- vlog(LOG_ERR, nfmt, ap);
-#pragma GCC diagnostic pop
- free(nfmt);
- }
- va_end(ap);
- }
-}
-
-void
-log_warnx(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vlog(LOG_ERR, emsg, ap);
- va_end(ap);
-}
-
-void
-log_info(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vlog(LOG_INFO, emsg, ap);
- va_end(ap);
-}
-
-void
-log_notice(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vlog(LOG_NOTICE, emsg, ap);
- va_end(ap);
-}
-
-void
-log_debug(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vlog(LOG_DEBUG, emsg, ap);
- va_end(ap);
-}
-
-void
-fatal(const char *emsg)
-{
- if (emsg == NULL)
- logit(LOG_CRIT, "fatal in %s: %s", log_procname, strerror(errno));
- else
- if (errno)
- logit(LOG_CRIT, "fatal in %s: %s: %s",
- log_procname, emsg, strerror(errno));
- else
- logit(LOG_CRIT, "fatal in %s: %s", log_procname, emsg);
-
- exit(1);
-}
-
-void
-fatalx(const char *emsg)
-{
- errno = 0;
- fatal(emsg);
-}
diff --git a/ldpd/log.h b/ldpd/log.h
index 641ad8ac5e..aa6f700608 100644
--- a/ldpd/log.h
+++ b/ldpd/log.h
@@ -8,29 +8,30 @@
#ifndef LOG_H
#define LOG_H
-#include <stdarg.h>
+#include "log.h"
+#include "assert.h"
extern const char *log_procname;
-void logit(int, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void vlog(int, const char *, va_list)
- __attribute__((__format__ (printf, 2, 0)));
-void log_warn(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void log_warnx(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void log_info(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void log_notice(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void log_debug(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void fatal(const char *)
- __attribute__ ((noreturn))
- __attribute__((__format__ (printf, 1, 0)));
-void fatalx(const char *)
- __attribute__ ((noreturn))
- __attribute__((__format__ (printf, 1, 0)));
+#define log_warnx zlog_err /* yes this is poorly named */
+#define log_warn zlog_warn
+#define log_info zlog_info
+#define log_notice zlog_notice /* not used anywhere */
+#define log_debug zlog_debug
+
+#define fatal(msg) \
+ do { \
+ assertf(0, "fatal in %s: %pSQq (%m)", log_procname, \
+ (const char *)msg); \
+ __builtin_unreachable(); \
+ } while (0) \
+ /* end */
+#define fatalx(msg) \
+ do { \
+ assertf(0, "fatal in %s: %pSQq", log_procname, \
+ (const char *)msg); \
+ __builtin_unreachable(); \
+ } while (0) \
+ /* end */
#endif /* LOG_H */
diff --git a/ldpd/subdir.am b/ldpd/subdir.am
index 0b948adb6f..ad5933fec3 100644
--- a/ldpd/subdir.am
+++ b/ldpd/subdir.am
@@ -28,7 +28,6 @@ ldpd_libldp_a_SOURCES = \
ldpd/ldp_vty_exec.c \
ldpd/ldp_zebra.c \
ldpd/ldpe.c \
- ldpd/log.c \
ldpd/logmsg.c \
ldpd/neighbor.c \
ldpd/notification.c \
diff --git a/lib/affinitymap.c b/lib/affinitymap.c
index e53d54a443..6ff8e83f91 100644
--- a/lib/affinitymap.c
+++ b/lib/affinitymap.c
@@ -41,8 +41,6 @@
#include "jhash.h"
DEFINE_MTYPE_STATIC(LIB, AFFINITY_MAP, "Affinity map");
-DEFINE_MTYPE(LIB, AFFINITY_MAP_NAME, "Affinity map name");
-DEFINE_MTYPE_STATIC(LIB, AFFINITY_MAP_INDEX, "Affinity map index");
DEFINE_QOBJ_TYPE(affinity_maps);
DEFINE_QOBJ_TYPE(affinity_map);
diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c
index d27c5d3a29..98b7da45ce 100644
--- a/lib/mgmt_msg_native.c
+++ b/lib/mgmt_msg_native.c
@@ -9,7 +9,6 @@
#include "mgmt_msg_native.h"
DEFINE_MGROUP(MSG_NATIVE, "Native message allocations");
-DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_MSG, "native mgmt msg");
DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_ERROR, "native error msg");
DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_GET_TREE, "native get tree msg");
DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_TREE_DATA, "native tree data msg");
diff --git a/lib/netns_other.c b/lib/netns_other.c
index 30218409dd..545a962b55 100644
--- a/lib/netns_other.c
+++ b/lib/netns_other.c
@@ -13,10 +13,6 @@
#include "log.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context");
-DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name");
-
-
static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
RB_GENERATE(ns_head, ns, entry, ns_compare)
@@ -39,7 +35,6 @@ void ns_init_management(ns_id_t ns_id)
{
}
-
/*
* NS utilities
*/
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 4942d66850..640334926d 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -19,8 +19,6 @@
#include <sysrepo/values.h>
#include <sysrepo/xpath.h>
-DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module");
-
static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"};
static struct event_loop *master;
diff --git a/lib/printf/README b/lib/printf/README
index 46d51cec6a..3c3ef74ca8 100644
--- a/lib/printf/README
+++ b/lib/printf/README
@@ -1,6 +1,7 @@
This is the printf implementation from FreeBSD. The history of this code is:
- imported on 2019-05-12, from SVN revision 347514
- resynced on 2023-09-03, to pick up `%b` implementation
+- resynced on 2024-03-10, to pick up `%w[f](8|16|32|64)d` implementation
Please don't reindent or otherwise mangle the files to make importing fixes
easy (not that there are significant changes likely to happen...)
diff --git a/lib/printf/printflocal.h b/lib/printf/printflocal.h
index 4b030912fe..93318c8fdb 100644
--- a/lib/printf/printflocal.h
+++ b/lib/printf/printflocal.h
@@ -52,6 +52,7 @@
#define PTRDIFFT 0x800 /* ptrdiff_t */
#define INTMAXT 0x1000 /* intmax_t */
#define CHARINT 0x2000 /* print char using int format */
+#define FASTINT 0x4000 /* int_fastN_t */
/*
* Macros for converting digits to letters and vice versa
diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c
index 2083642d5e..3f6700c838 100644
--- a/lib/printf/vfprintf.c
+++ b/lib/printf/vfprintf.c
@@ -416,6 +416,49 @@ reswitch: switch (ch) {
case 't':
flags |= PTRDIFFT;
goto rflag;
+ case 'w':
+ /*
+ * Fixed-width integer types. On all platforms we
+ * support, int8_t is equivalent to char, int16_t
+ * is equivalent to short, int32_t is equivalent
+ * to int, int64_t is equivalent to long long int.
+ * Furthermore, int_fast8_t, int_fast16_t and
+ * int_fast32_t are equivalent to int, and
+ * int_fast64_t is equivalent to long long int.
+ */
+ flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT);
+ if (fmt[0] == 'f') {
+ flags |= FASTINT;
+ fmt++;
+ } else {
+ flags &= ~FASTINT;
+ }
+ if (fmt[0] == '8') {
+ if (!(flags & FASTINT))
+ flags |= CHARINT;
+ else
+ (void) 0; /* no flag set = 32 */
+ fmt += 1;
+ } else if (fmt[0] == '1' && fmt[1] == '6') {
+ if (!(flags & FASTINT))
+ flags |= SHORTINT;
+ else
+ (void) 0; /* no flag set = 32 */
+ fmt += 2;
+ } else if (fmt[0] == '3' && fmt[1] == '2') {
+ /* no flag set = 32 */
+ fmt += 2;
+ } else if (fmt[0] == '6' && fmt[1] == '4') {
+ flags |= LLONGINT;
+ fmt += 2;
+ } else {
+ if (flags & FASTINT) {
+ flags &= ~FASTINT;
+ fmt--;
+ }
+ goto invalid;
+ }
+ goto rflag;
case 'z':
flags |= SIZET;
goto rflag;
@@ -684,6 +727,7 @@ number: if ((dprec = prec) >= 0)
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
goto done;
+invalid:
/* pretend it was %c with argument ch */
buf[0] = ch;
cp = buf;
diff --git a/lib/subdir.am b/lib/subdir.am
index db11def741..c621ad0658 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -131,6 +131,7 @@ lib_libfrr_la_SOURCES = \
lib/zlog_5424.c \
lib/zlog_5424_cli.c \
lib/zlog_live.c \
+ lib/zlog_recirculate.c \
lib/zlog_targets.c \
lib/printf/printf-pos.c \
lib/printf/vfprintf.c \
@@ -329,6 +330,7 @@ pkginclude_HEADERS += \
lib/zlog.h \
lib/zlog_5424.h \
lib/zlog_live.h \
+ lib/zlog_recirculate.h \
lib/zlog_targets.h \
lib/pbr.h \
lib/tc.h \
diff --git a/lib/yang.c b/lib/yang.c
index 03044fc29e..d71cb2f498 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -199,6 +199,16 @@ next:
if (ret == YANG_ITER_STOP)
return ret;
}
+ LY_LIST_FOR ((const struct lysc_node *)lysc_node_notifs(snode), child) {
+ ret = yang_snodes_iterate_subtree(child, module, cb, flags, arg);
+ if (ret == YANG_ITER_STOP)
+ return ret;
+ }
+ LY_LIST_FOR ((const struct lysc_node *)lysc_node_actions(snode), child) {
+ ret = yang_snodes_iterate_subtree(child, module, cb, flags, arg);
+ if (ret == YANG_ITER_STOP)
+ return ret;
+ }
return ret;
}
diff --git a/lib/zlog.c b/lib/zlog.c
index 8734fd55af..ffca572609 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -50,6 +50,7 @@
#include "printfrr.h"
#include "frrcu.h"
#include "zlog.h"
+#include "zlog_live.h"
#include "libfrr_trace.h"
#include "frrevent.h"
@@ -109,6 +110,9 @@ struct zlog_msg {
size_t textlen;
size_t hdrlen;
+ /* for relayed log messages ONLY (cf. zlog_recirculate_live_msg) */
+ intmax_t pid, tid;
+
/* This is always ISO8601 with sub-second precision 9 here, it's
* converted for callers as needed. ts_dot points to the "."
* separating sub-seconds. ts_zonetail is "Z" or "+00:00" for the
@@ -357,6 +361,16 @@ void zlog_msg_pid(struct zlog_msg *msg, intmax_t *pid, intmax_t *tid)
{
#ifndef __OpenBSD__
static thread_local intmax_t cached_pid = -1;
+#endif
+
+ /* recirculated messages */
+ if (msg->pid) {
+ *pid = msg->pid;
+ *tid = msg->tid;
+ return;
+ }
+
+#ifndef __OpenBSD__
if (cached_pid != -1)
*pid = cached_pid;
else
@@ -507,6 +521,89 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref,
XFREE(MTYPE_LOG_MESSAGE, msg->text);
}
+/* reinject log message received by zlog_recirculate_recv(). As of writing,
+ * only used in the ldpd parent process to proxy messages from lde/ldpe
+ * subprocesses.
+ */
+void zlog_recirculate_live_msg(uint8_t *data, size_t len)
+{
+ struct zlog_target *zt;
+ struct zlog_msg stackmsg = {}, *msg = &stackmsg;
+ struct zlog_live_hdr *hdr;
+ struct xrefdata *xrefdata, ref = {};
+
+ if (len < sizeof(*hdr))
+ return;
+
+ hdr = (struct zlog_live_hdr *)data;
+ if (hdr->hdrlen < sizeof(*hdr))
+ return;
+ data += hdr->hdrlen;
+ len -= sizeof(*hdr);
+
+ msg->ts.tv_sec = hdr->ts_sec;
+ msg->ts.tv_nsec = hdr->ts_nsec;
+ msg->pid = hdr->pid;
+ msg->tid = hdr->tid;
+ msg->prio = hdr->prio;
+
+ if (hdr->textlen > len)
+ return;
+ msg->textlen = hdr->textlen;
+ msg->hdrlen = hdr->texthdrlen;
+ msg->text = (char *)data;
+
+ /* caller needs to make sure we have a trailing \n\0, it's not
+ * transmitted on zlog_live
+ */
+ if (msg->text[msg->textlen] != '\n' ||
+ msg->text[msg->textlen + 1] != '\0')
+ return;
+
+ static_assert(sizeof(msg->argpos[0]) == sizeof(hdr->argpos[0]),
+ "in-memory struct doesn't match on-wire variant");
+ msg->n_argpos = MIN(hdr->n_argpos, array_size(msg->argpos));
+ memcpy(msg->argpos, hdr->argpos, msg->n_argpos * sizeof(msg->argpos[0]));
+
+ /* This will only work if we're in the same daemon: we received a log
+ * message uid and are now doing a lookup in *our* known uids to find
+ * it. This works for ldpd because it's the same binary containing the
+ * same log messages, and ldpd is the only use case right now.
+ *
+ * When the uid is not found, the log message uid is lost but the
+ * message itself is still processed correctly. If this is needed,
+ * this can be made to work in two ways:
+ * (a) synthesize a temporary xref_logmsg from the received data.
+ * This is a bit annoying due to lifetimes with per-thread buffers.
+ * (b) extract and aggregate all log messages. This already happens
+ * with frr.xref but that would need to be fed back in.
+ */
+ strlcpy(ref.uid, hdr->uid, sizeof(ref.uid));
+ xrefdata = xrefdata_uid_find(&xrefdata_uid, &ref);
+
+ if (xrefdata && xrefdata->xref->type == XREFT_LOGMSG) {
+ struct xref_logmsg *xref_logmsg;
+
+ xref_logmsg = (struct xref_logmsg *)xrefdata->xref;
+ msg->xref = xref_logmsg;
+ msg->fmt = xref_logmsg->fmtstring;
+ } else {
+ /* fake out format string... */
+ msg->fmt = msg->text + hdr->texthdrlen;
+ }
+
+ rcu_read_lock();
+ frr_each_safe (zlog_targets, &zlog_targets, zt) {
+ if (msg->prio > zt->prio_min)
+ continue;
+ if (!zt->logfn)
+ continue;
+
+ zt->logfn(zt, &msg, 1);
+ }
+ rcu_read_unlock();
+}
+
static void zlog_backtrace_msg(const struct xref_logmsg *xref, int prio)
{
struct event *tc = pthread_getspecific(thread_current);
diff --git a/lib/zlog.h b/lib/zlog.h
index 27401d51fb..9d93979957 100644
--- a/lib/zlog.h
+++ b/lib/zlog.h
@@ -125,6 +125,9 @@ static inline void zlog_ref(const struct xref_logmsg *xref,
extern void zlog_sigsafe(const char *text, size_t len);
+/* recirculate a log message from zlog_live */
+extern void zlog_recirculate_live_msg(uint8_t *data, size_t len);
+
/* extra priority value to disable a target without deleting it */
#define ZLOG_DISABLED (LOG_EMERG-1)
diff --git a/lib/zlog_recirculate.c b/lib/zlog_recirculate.c
new file mode 100644
index 0000000000..abc73eeed0
--- /dev/null
+++ b/lib/zlog_recirculate.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2024 David Lamparter, for NetDEF, Inc.
+ */
+
+#include "zebra.h"
+
+#include "log.h"
+#include "frrevent.h"
+
+#include "zlog_recirculate.h"
+
+/* This is only the event loop part; it's split off from
+ * zlog_recirculate_live_msg since there's an integration boundary; this
+ * half deals with events, the other half with zlog interna.
+ *
+ * As of writing, this runs in ldpd in the *parent* process and receives log
+ * messages from the lde/ldpe subprocesses. It is not used anywhere else
+ * (yet?)
+ */
+static void zlog_recirculate_recv(struct event *ev)
+{
+ uint8_t rxbuf[4096];
+ ssize_t n_rd;
+ int fd = EVENT_FD(ev);
+
+ /* see below for -2, "\n\0" are added */
+ n_rd = read(fd, rxbuf, sizeof(rxbuf) - 2);
+ if (n_rd == 0) {
+ /* EOF */
+ close(fd);
+ /* event_add_read not called yet, nothing to cancel */
+ return;
+ }
+ if (n_rd < 0 && (errno != EAGAIN) && (errno != EWOULDBLOCK)) {
+ /* error */
+ zlog_warn("error on log relay socket %d: %m", fd);
+ close(fd);
+ /* event_add_read not called yet, nothing to cancel */
+ return;
+ }
+
+ event_add_read(ev->master, zlog_recirculate_recv, NULL, fd, NULL);
+ if (n_rd < 0)
+ return;
+
+ /* log infrastructure has an implicit \n\0 at the end */
+ rxbuf[n_rd] = '\n';
+ rxbuf[n_rd + 1] = '\0';
+ zlog_recirculate_live_msg(rxbuf, n_rd);
+}
+
+void zlog_recirculate_subscribe(struct event_loop *el, int fd)
+{
+ event_add_read(el, zlog_recirculate_recv, NULL, fd, NULL);
+}
diff --git a/lib/zlog_recirculate.h b/lib/zlog_recirculate.h
new file mode 100644
index 0000000000..a2ddb4e172
--- /dev/null
+++ b/lib/zlog_recirculate.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2024 David Lamparter, for NetDEF, Inc.
+ */
+
+#ifndef _FRR_ZLOG_RECIRCULATE_H
+#define _FRR_ZLOG_RECIRCULATE_H
+
+/* fd should be one end of a socketpair() */
+extern void zlog_recirculate_subscribe(struct event_loop *tm, int fd);
+
+#endif
diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c
index 2e967698ea..4d4349b81a 100644
--- a/ripd/rip_cli.c
+++ b/ripd/rip_cli.c
@@ -1125,36 +1125,6 @@ void cli_show_ip_rip_bfd_profile(struct vty *vty, const struct lyd_node *dnode,
yang_dnode_get_string(dnode, NULL));
}
-/*
- * XPath: /frr-ripd:clear-rip-route
- */
-DEFPY_YANG (clear_ip_rip,
- clear_ip_rip_cmd,
- "clear ip rip [vrf WORD]",
- CLEAR_STR
- IP_STR
- "Clear IP RIP database\n"
- VRF_CMD_HELP_STR)
-{
- struct list *input;
- int ret;
-
- input = list_new();
- if (vrf) {
- struct yang_data *yang_vrf;
-
- yang_vrf = yang_data_new("/frr-ripd:clear-rip-route/input/vrf",
- vrf);
- listnode_add(input, yang_vrf);
- }
-
- ret = nb_cli_rpc(vty, "/frr-ripd:clear-rip-route", input, NULL);
-
- list_delete(&input);
-
- return ret;
-}
-
DEFPY_YANG(
rip_distribute_list, rip_distribute_list_cmd,
"distribute-list ACCESSLIST4_NAME$name <in|out>$dir [WORD$ifname]",
@@ -1325,8 +1295,6 @@ void rip_cli_init(void)
install_element(INTERFACE_NODE, &ip_rip_bfd_profile_cmd);
install_element(INTERFACE_NODE, &no_ip_rip_bfd_profile_cmd);
- install_element(ENABLE_NODE, &clear_ip_rip_cmd);
-
if_rmap_init(RIP_NODE);
}
/* clang-format off */
diff --git a/ripd/ripd.c b/ripd/ripd.c
index b8a140c9ca..e3220a9267 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3254,6 +3254,38 @@ DEFUN (show_ip_rip_status,
return CMD_SUCCESS;
}
+#include "ripd/ripd_clippy.c"
+
+/*
+ * XPath: /frr-ripd:clear-rip-route
+ */
+DEFPY_YANG (clear_ip_rip,
+ clear_ip_rip_cmd,
+ "clear ip rip [vrf WORD]",
+ CLEAR_STR
+ IP_STR
+ "Clear IP RIP database\n"
+ VRF_CMD_HELP_STR)
+{
+ struct list *input;
+ int ret;
+
+ input = list_new();
+ if (vrf) {
+ struct yang_data *yang_vrf;
+
+ yang_vrf = yang_data_new("/frr-ripd:clear-rip-route/input/vrf",
+ vrf);
+ listnode_add(input, yang_vrf);
+ }
+
+ ret = nb_cli_rpc(vty, "/frr-ripd:clear-rip-route", input, NULL);
+
+ list_delete(&input);
+
+ return ret;
+}
+
/* Distribute-list update functions. */
static void rip_distribute_update(struct distribute_ctx *ctx,
struct distribute *dist)
@@ -3628,6 +3660,7 @@ void rip_init(void)
/* Install rip commands. */
install_element(VIEW_NODE, &show_ip_rip_cmd);
install_element(VIEW_NODE, &show_ip_rip_status_cmd);
+ install_element(ENABLE_NODE, &clear_ip_rip_cmd);
/* Debug related init. */
rip_debug_init();
diff --git a/ripd/subdir.am b/ripd/subdir.am
index aed8d249fe..7fb3726077 100644
--- a/ripd/subdir.am
+++ b/ripd/subdir.am
@@ -33,6 +33,7 @@ ripd_ripd_SOURCES = \
clippy_scan += \
ripd/rip_bfd.c \
ripd/rip_cli.c \
+ ripd/ripd.c \
# end
noinst_HEADERS += \
diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c
index ed460a239e..4806861fe0 100644
--- a/ripngd/ripng_cli.c
+++ b/ripngd/ripng_cli.c
@@ -512,36 +512,6 @@ void cli_show_ipv6_ripng_split_horizon(struct vty *vty,
}
}
-/*
- * XPath: /frr-ripngd:clear-ripng-route
- */
-DEFPY_YANG (clear_ipv6_rip,
- clear_ipv6_rip_cmd,
- "clear ipv6 ripng [vrf WORD]",
- CLEAR_STR
- IPV6_STR
- "Clear IPv6 RIP database\n"
- VRF_CMD_HELP_STR)
-{
- struct list *input;
- int ret;
-
- input = list_new();
- if (vrf) {
- struct yang_data *yang_vrf;
-
- yang_vrf = yang_data_new(
- "/frr-ripngd:clear-ripng-route/input/vrf", vrf);
- listnode_add(input, yang_vrf);
- }
-
- ret = nb_cli_rpc(vty, "/frr-ripngd:clear-ripng-route", input, NULL);
-
- list_delete(&input);
-
- return ret;
-}
-
DEFPY_YANG(
ripng_ipv6_distribute_list, ripng_ipv6_distribute_list_cmd,
"ipv6 distribute-list ACCESSLIST6_NAME$name <in|out>$dir [WORD$ifname]",
@@ -693,8 +663,6 @@ void ripng_cli_init(void)
install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
- install_element(ENABLE_NODE, &clear_ipv6_rip_cmd);
-
if_rmap_init(RIPNG_NODE);
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index f4dadf377d..80b9013e0f 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2231,6 +2231,38 @@ DEFUN (show_ipv6_ripng_status,
return CMD_SUCCESS;
}
+#include "ripngd/ripngd_clippy.c"
+
+/*
+ * XPath: /frr-ripngd:clear-ripng-route
+ */
+DEFPY_YANG (clear_ipv6_rip,
+ clear_ipv6_rip_cmd,
+ "clear ipv6 ripng [vrf WORD]",
+ CLEAR_STR
+ IPV6_STR
+ "Clear IPv6 RIP database\n"
+ VRF_CMD_HELP_STR)
+{
+ struct list *input;
+ int ret;
+
+ input = list_new();
+ if (vrf) {
+ struct yang_data *yang_vrf;
+
+ yang_vrf = yang_data_new(
+ "/frr-ripngd:clear-ripng-route/input/vrf", vrf);
+ listnode_add(input, yang_vrf);
+ }
+
+ ret = nb_cli_rpc(vty, "/frr-ripngd:clear-ripng-route", input, NULL);
+
+ list_delete(&input);
+
+ return ret;
+}
+
/* Update ECMP routes to zebra when ECMP is disabled. */
void ripng_ecmp_disable(struct ripng *ripng)
{
@@ -2648,6 +2680,7 @@ void ripng_init(void)
/* Install ripng commands. */
install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
+ install_element(ENABLE_NODE, &clear_ipv6_rip_cmd);
ripng_if_init();
ripng_debug_init();
diff --git a/ripngd/subdir.am b/ripngd/subdir.am
index 83e376b555..a88114432d 100644
--- a/ripngd/subdir.am
+++ b/ripngd/subdir.am
@@ -27,6 +27,7 @@ ripngd_ripngd_SOURCES = \
clippy_scan += \
ripngd/ripng_cli.c \
+ ripngd/ripngd.c \
# end
noinst_HEADERS += \
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
index 66699ec7c0..cefa07ec73 100644
--- a/tests/lib/test_printfrr.c
+++ b/tests/lib/test_printfrr.c
@@ -143,6 +143,8 @@ int main(int argc, char **argv)
NAN,
};
uint64_t ui64 = 0xfeed1278cafef00d;
+ uint16_t i16 = -23456;
+ int_fast8_t if8 = 123;
struct in_addr ip;
char *p;
char buf[256];
@@ -169,6 +171,16 @@ int main(int argc, char **argv)
FMT_NSTD(printchk("11110000000011111010010111000011", "%b", 0xf00fa5c3));
FMT_NSTD(printchk("0b01011010", "%#010b", 0x5a));
+/* FMT_NSTD is conditional on the frr-format plugin being NOT enabled.
+ * However, the frr-format plugin does not support %wd/%wfd yet, so this needs
+ * to be unconditional.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+ printchk("123 -23456 feed1278cafef00d 9876", "%wf8d %w16d %w64x %d",
+ if8, i16, ui64, 9876);
+#pragma GCC diagnostic pop
+
inet_aton("192.168.1.2", &ip);
printchk("192.168.1.2", "%pI4", &ip);
printchk(" 192.168.1.2", "%20pI4", &ip);
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py
index f83ee2971c..5202f51e28 100644
--- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py
@@ -135,7 +135,7 @@ def test_bgp_dynamic_capability_addpath():
step("Disable Addpath capability RX and check if it's exchanged dynamically")
# Clear message stats to check if we receive a notification or not after we
- # change the settings fo LLGR.
+ # disable addpath-rx.
r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
r2.vtysh_cmd(
"""
@@ -174,6 +174,46 @@ def test_bgp_dynamic_capability_addpath():
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Session was reset after disabling Addpath RX flags"
+ # Clear message stats to check if we receive a notification or not after we
+ # disable Addpath capability.
+ r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ address-family ipv4 unicast
+ no neighbor 192.168.1.2 addpath-tx-all-paths
+ """
+ )
+
+ def _bgp_check_if_addpath_capability_is_absent():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ "addPath": {
+ "ipv4Unicast": {
+ "txAdvertisedAndReceived": None,
+ "txAdvertised": None,
+ "rxAdvertised": True,
+ }
+ },
+ },
+ "messageStats": {
+ "notificationsRecv": 0,
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_addpath_capability_is_absent,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to disable Addpath capability"
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py
new file mode 100644
index 0000000000..338886d5f4
--- /dev/null
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+"""
+Test if fqdn capability is exchanged dynamically.
+"""
+
+import os
+import re
+import sys
+import json
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+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.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ 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_bgp_dynamic_capability_fqdn():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ "hostName": {
+ "advHostName": "r1",
+ "rcvHostName": "r2",
+ },
+ },
+ }
+ }
+ 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, "Can't converge"
+
+ step("Disable fqdn capability and check if it's exchanged dynamically")
+
+ # Clear message stats to check if we receive a notification or not after we
+ # disable fqdn capability.
+ r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ no neighbor 192.168.1.2 capability fqdn
+ """
+ )
+
+ def _bgp_check_if_fqdn_capability_is_absent():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ "hostName": {
+ "advHostName": None,
+ "rcvHostName": "r2",
+ },
+ },
+ "messageStats": {
+ "notificationsRecv": 0,
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_fqdn_capability_is_absent,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to disable fqdn capability"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py
index b7e2090eee..4644ef3293 100644
--- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py
@@ -159,7 +159,7 @@ def test_bgp_dynamic_capability_graceful_restart():
)
# Clear message stats to check if we receive a notification or not after we
- # change the settings fo LLGR.
+ # disable graceful-restart notification support.
r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
r2.vtysh_cmd(
"""
@@ -207,6 +207,40 @@ def test_bgp_dynamic_capability_graceful_restart():
result is None
), "Session was reset after changing Graceful-Restart notification support"
+ # Clear message stats to check if we receive a notification or not after we
+ # disable GR.
+ r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ bgp graceful-restart-disable
+ """
+ )
+
+ def _bgp_check_if_gr_llgr_capability_is_absent():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ "gracefulRestartCapability": "received",
+ "longLivedGracefulRestart": "received",
+ },
+ "messageStats": {
+ "notificationsRecv": 0,
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_gr_llgr_capability_is_absent,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to disable GR/LLGR capabilities"
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py
index f1ad74c05c..ba95bd1614 100644
--- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py
@@ -172,6 +172,51 @@ def test_bgp_dynamic_capability_orf():
result is None
), "Only 10.10.10.20/32 SHOULD be advertised due to ORF filtering"
+ # Clear message stats to check if we receive a notification or not after we
+ # disable ORF capability.
+ r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ address-family ipv4 unicast
+ no neighbor 192.168.1.2 capability orf prefix-list both
+ """
+ )
+
+ def _bgp_check_if_orf_capability_is_absent():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ },
+ "messageStats": {
+ "notificationsRecv": 0,
+ "notificationsSent": 0,
+ },
+ "addressFamilyInfo": {
+ "ipv4Unicast": {
+ "acceptedPrefixCounter": 1,
+ "afDependentCap": {
+ "orfPrefixList": {
+ "sendMode": "received",
+ "recvMode": "received",
+ }
+ },
+ }
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_orf_capability_is_absent,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to disable ORF capability"
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py
index 700d4c130d..aa9ad5f0e8 100644
--- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py
@@ -84,7 +84,7 @@ def test_bgp_dynamic_capability_role():
step("Set local-role and check if it's exchanged dynamically")
# Clear message stats to check if we receive a notification or not after we
- # change the settings fo LLGR.
+ # change the role.
r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
r1.vtysh_cmd(
"""
@@ -132,6 +132,41 @@ def test_bgp_dynamic_capability_role():
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Session was reset after setting role capability"
+ # Clear message stats to check if we receive a notification or not after we
+ # change the role.
+ r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ no neighbor 192.168.1.2 local-role customer
+ """
+ )
+
+ def _bgp_check_if_role_capability_is_absent():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "localRole": "undefined",
+ "remoteRole": "provider",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ "role": "received",
+ },
+ "messageStats": {
+ "notificationsRecv": 0,
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_role_capability_is_absent,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to disable role capability"
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py
index 11840b4c61..737e694701 100644
--- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py
@@ -86,7 +86,7 @@ def test_bgp_dynamic_capability_software_version():
step("Enable software version capability and check if it's exchanged dynamically")
# Clear message stats to check if we receive a notification or not after we
- # change the settings fo LLGR.
+ # enable software-version capability.
r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
r1.vtysh_cmd(
"""
@@ -155,6 +155,41 @@ def test_bgp_dynamic_capability_software_version():
result is None
), "Session was reset after enabling software version capability"
+ # Clear message stats to check if we receive a notification or not after we
+ # disable software-version capability.
+ r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ no neighbor 192.168.1.2 capability software-version
+ """
+ )
+
+ def _bgp_check_if_software_version_capability_is_absent():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ "softwareVersion": {
+ "advertisedSoftwareVersion": None,
+ },
+ },
+ "messageStats": {
+ "notificationsRecv": 0,
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_software_version_capability_is_absent,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to disable software version capability"
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
diff --git a/zebra/main.c b/zebra/main.c
index 606ecc7279..27e98ed999 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -203,6 +203,7 @@ static void sigint(void)
rib_update_finish();
list_delete(&zrouter.client_list);
+ list_delete(&zrouter.stale_client_list);
/* Indicate that all new dplane work has been enqueued. When that
* work is complete, the dataplane will enqueue an event
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 6a64176d98..3671fdb507 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -306,6 +306,14 @@ zwrite_fail:
* this task reschedules itself.
*
* Any failure in any of these actions is handled by terminating the client.
+ *
+ * The client's input buffer ibuf_fifo can have a maximum items as configured
+ * in the packets_to_process. This way we are not filling up the FIFO more
+ * than the maximum when the zebra main is busy. If the fifo has space, we
+ * reschedule ourselves to read more.
+ *
+ * The main thread processes the items in ibuf_fifo and always signals the
+ * client IO thread.
*/
static void zserv_read(struct event *thread)
{
@@ -313,15 +321,25 @@ static void zserv_read(struct event *thread)
int sock;
size_t already;
struct stream_fifo *cache;
- uint32_t p2p_orig;
-
- uint32_t p2p;
+ uint32_t p2p; /* Temp p2p used to process */
+ uint32_t p2p_orig; /* Configured p2p (Default-1000) */
+ int p2p_avail; /* How much space is available for p2p */
struct zmsghdr hdr;
+ size_t client_ibuf_fifo_cnt = stream_fifo_count_safe(client->ibuf_fifo);
p2p_orig = atomic_load_explicit(&zrouter.packets_to_process,
memory_order_relaxed);
+ p2p_avail = p2p_orig - client_ibuf_fifo_cnt;
+
+ /*
+ * Do nothing if ibuf_fifo count has reached its max limit. Otherwise
+ * proceed and reschedule ourselves if there is space in the ibuf_fifo.
+ */
+ if (p2p_avail <= 0)
+ return;
+
+ p2p = p2p_avail;
cache = stream_fifo_new();
- p2p = p2p_orig;
sock = EVENT_FD(thread);
while (p2p) {
@@ -421,7 +439,7 @@ static void zserv_read(struct event *thread)
p2p--;
}
- if (p2p < p2p_orig) {
+ if (p2p < (uint32_t)p2p_avail) {
uint64_t time_now = monotime(NULL);
/* update session statistics */
@@ -435,19 +453,23 @@ static void zserv_read(struct event *thread)
while (cache->head)
stream_fifo_push(client->ibuf_fifo,
stream_fifo_pop(cache));
+ /* Need to update count as main thread could have processed few */
+ client_ibuf_fifo_cnt =
+ stream_fifo_count_safe(client->ibuf_fifo);
}
/* Schedule job to process those packets */
zserv_event(client, ZSERV_PROCESS_MESSAGES);
-
}
if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("Read %d packets from client: %s", p2p_orig - p2p,
- zebra_route_string(client->proto));
+ zlog_debug("Read %d packets from client: %s. Current ibuf fifo count: %zu. Conf P2p %d",
+ p2p_avail - p2p, zebra_route_string(client->proto),
+ client_ibuf_fifo_cnt, p2p_orig);
- /* Reschedule ourselves */
- zserv_client_event(client, ZSERV_CLIENT_READ);
+ /* Reschedule ourselves since we have space in ibuf_fifo */
+ if (client_ibuf_fifo_cnt < p2p_orig)
+ zserv_client_event(client, ZSERV_CLIENT_READ);
stream_fifo_free(cache);
@@ -483,14 +505,20 @@ static void zserv_client_event(struct zserv *client,
* as the task argument.
*
* Each message is popped off the client's input queue and the action associated
- * with the message is executed. This proceeds until there are no more messages,
- * an error occurs, or the processing limit is reached.
+ * with the message is executed. This proceeds until an error occurs, or the
+ * processing limit is reached.
*
* The client's I/O thread can push at most zrouter.packets_to_process messages
* onto the input buffer before notifying us there are packets to read. As long
* as we always process zrouter.packets_to_process messages here, then we can
* rely on the read thread to handle queuing this task enough times to process
* everything on the input queue.
+ *
+ * If the client ibuf always schedules a wakeup to the client IO to read more
+ * items from the socked buffer. This way we ensure
+ * - Client IO thread always tries to read the socket buffer and add more
+ * items to the ibuf_fifo (until max limit)
+ * - the hidden config change (zebra zapi-packets <>) is taken into account.
*/
static void zserv_process_messages(struct event *thread)
{
@@ -524,6 +552,9 @@ static void zserv_process_messages(struct event *thread)
/* Reschedule ourselves if necessary */
if (need_resched)
zserv_event(client, ZSERV_PROCESS_MESSAGES);
+
+ /* Ensure to include the read socket in the select/poll/etc.. */
+ zserv_client_event(client, ZSERV_CLIENT_READ);
}
int zserv_send_message(struct zserv *client, struct stream *msg)