summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/agentx.c8
-rw-r--r--lib/base64.c193
-rw-r--r--lib/base64.h45
-rw-r--r--lib/bfd.c8
-rw-r--r--lib/checksum.c85
-rw-r--r--lib/checksum.h43
-rw-r--r--lib/command.c4
-rw-r--r--lib/frr_pthread.c6
-rw-r--r--lib/frr_zmq.c24
-rw-r--r--lib/if.c3
-rw-r--r--lib/lib_errors.c6
-rw-r--r--lib/lib_errors.h1
-rw-r--r--lib/libfrr.c9
-rw-r--r--lib/northbound_cli.c4
-rw-r--r--lib/northbound_confd.c41
-rw-r--r--lib/northbound_grpc.cpp9
-rw-r--r--lib/northbound_sysrepo.c8
-rw-r--r--lib/pullwr.c11
-rw-r--r--lib/resolver.c15
-rw-r--r--lib/routemap.c11
-rw-r--r--lib/sigevent.c4
-rw-r--r--lib/spf_backoff.c6
-rw-r--r--lib/subdir.am4
-rw-r--r--lib/systemd.c3
-rw-r--r--lib/thread.c85
-rw-r--r--lib/thread.h16
-rw-r--r--lib/vty.c227
-rw-r--r--lib/vty.h26
-rw-r--r--lib/wheel.c10
-rw-r--r--lib/workqueue.c4
-rw-r--r--lib/workqueue.h2
-rw-r--r--lib/yang_wrappers.c59
-rw-r--r--lib/yang_wrappers.h7
-rw-r--r--lib/zclient.c40
-rw-r--r--lib/zlog.c5
-rw-r--r--lib/zlog.h3
-rw-r--r--lib/zlog_5424.c5
-rw-r--r--lib/zlog_live.c245
-rw-r--r--lib/zlog_live.h53
39 files changed, 1078 insertions, 260 deletions
diff --git a/lib/agentx.c b/lib/agentx.c
index 5f865ca2b8..821c573fb2 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -46,7 +46,7 @@ static struct list *events = NULL;
static void agentx_events_update(void);
-static int agentx_timeout(struct thread *t)
+static void agentx_timeout(struct thread *t)
{
timeout_thr = NULL;
@@ -54,10 +54,9 @@ static int agentx_timeout(struct thread *t)
run_alarms();
netsnmp_check_outstanding_agent_requests();
agentx_events_update();
- return 0;
}
-static int agentx_read(struct thread *t)
+static void agentx_read(struct thread *t)
{
fd_set fds;
int flags, new_flags = 0;
@@ -72,7 +71,7 @@ static int agentx_read(struct thread *t)
if (-1 == flags) {
flog_err(EC_LIB_SYSTEM_CALL, "Failed to get FD settings fcntl: %s(%d)",
strerror(errno), errno);
- return -1;
+ return;
}
if (flags & O_NONBLOCK)
@@ -101,7 +100,6 @@ static int agentx_read(struct thread *t)
netsnmp_check_outstanding_agent_requests();
agentx_events_update();
- return 0;
}
static void agentx_events_update(void)
diff --git a/lib/base64.c b/lib/base64.c
new file mode 100644
index 0000000000..e3f238969b
--- /dev/null
+++ b/lib/base64.c
@@ -0,0 +1,193 @@
+/*
+ * This is part of the libb64 project, and has been placed in the public domain.
+ * For details, see http://sourceforge.net/projects/libb64
+ */
+
+#include "base64.h"
+
+static const int CHARS_PER_LINE = 72;
+static const char *ENCODING =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+void base64_init_encodestate(struct base64_encodestate *state_in)
+{
+ state_in->step = step_A;
+ state_in->result = 0;
+ state_in->stepcount = 0;
+}
+
+char base64_encode_value(char value_in)
+{
+ if (value_in > 63)
+ return '=';
+ return ENCODING[(int)value_in];
+}
+
+int base64_encode_block(const char *plaintext_in, int length_in, char *code_out,
+ struct base64_encodestate *state_in)
+{
+ const char *plainchar = plaintext_in;
+ const char *const plaintextend = plaintext_in + length_in;
+ char *codechar = code_out;
+ char result;
+ char fragment;
+
+ result = state_in->result;
+
+ switch (state_in->step) {
+ while (1) {
+ case step_A:
+ if (plainchar == plaintextend) {
+ state_in->result = result;
+ state_in->step = step_A;
+ return codechar - code_out;
+ }
+ fragment = *plainchar++;
+ result = (fragment & 0x0fc) >> 2;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x003) << 4;
+ /* fall through */
+ case step_B:
+ if (plainchar == plaintextend) {
+ state_in->result = result;
+ state_in->step = step_B;
+ return codechar - code_out;
+ }
+ fragment = *plainchar++;
+ result |= (fragment & 0x0f0) >> 4;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x00f) << 2;
+ /* fall through */
+ case step_C:
+ if (plainchar == plaintextend) {
+ state_in->result = result;
+ state_in->step = step_C;
+ return codechar - code_out;
+ }
+ fragment = *plainchar++;
+ result |= (fragment & 0x0c0) >> 6;
+ *codechar++ = base64_encode_value(result);
+ result = (fragment & 0x03f) >> 0;
+ *codechar++ = base64_encode_value(result);
+
+ ++(state_in->stepcount);
+ if (state_in->stepcount == CHARS_PER_LINE/4) {
+ *codechar++ = '\n';
+ state_in->stepcount = 0;
+ }
+ }
+ }
+ /* control should not reach here */
+ return codechar - code_out;
+}
+
+int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in)
+{
+ char *codechar = code_out;
+
+ switch (state_in->step) {
+ case step_B:
+ *codechar++ = base64_encode_value(state_in->result);
+ *codechar++ = '=';
+ *codechar++ = '=';
+ break;
+ case step_C:
+ *codechar++ = base64_encode_value(state_in->result);
+ *codechar++ = '=';
+ break;
+ case step_A:
+ break;
+ }
+ *codechar++ = '\n';
+
+ return codechar - code_out;
+}
+
+
+signed char base64_decode_value(signed char value_in)
+{
+ static const signed char decoding[] = {
+ 62, -1, -1, -1, 63, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, -1,
+ -1, -1, -2, -1, -1, -1, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25,
+ -1, -1, -1, -1, -1, -1, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51
+ };
+ value_in -= 43;
+ if (value_in < 0 || value_in >= 80)
+ return -1;
+ return decoding[(int)value_in];
+}
+
+void base64_init_decodestate(struct base64_decodestate *state_in)
+{
+ state_in->step = step_a;
+ state_in->plainchar = 0;
+}
+
+int base64_decode_block(const char *code_in, int length_in, char *plaintext_out,
+ struct base64_decodestate *state_in)
+{
+ const char *codec = code_in;
+ char *plainc = plaintext_out;
+ signed char fragmt;
+
+ *plainc = state_in->plainchar;
+
+ switch (state_in->step) {
+ while (1) {
+ case step_a:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_a;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc = (fragmt & 0x03f) << 2;
+ /* fall through */
+ case step_b:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_b;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc++ |= (fragmt & 0x030) >> 4;
+ *plainc = (fragmt & 0x00f) << 4;
+ /* fall through */
+ case step_c:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_c;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc++ |= (fragmt & 0x03c) >> 2;
+ *plainc = (fragmt & 0x003) << 6;
+ /* fall through */
+ case step_d:
+ do {
+ if (codec == code_in+length_in) {
+ state_in->step = step_d;
+ state_in->plainchar = *plainc;
+ return plainc - plaintext_out;
+ }
+ fragmt = base64_decode_value(*codec++);
+ } while (fragmt < 0);
+ *plainc++ |= (fragmt & 0x03f);
+ }
+ }
+ /* control should not reach here */
+ return plainc - plaintext_out;
+}
diff --git a/lib/base64.h b/lib/base64.h
new file mode 100644
index 0000000000..3dc1559aa4
--- /dev/null
+++ b/lib/base64.h
@@ -0,0 +1,45 @@
+/*
+ * This is part of the libb64 project, and has been placed in the public domain.
+ * For details, see http://sourceforge.net/projects/libb64
+ */
+
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+enum base64_encodestep {
+ step_A, step_B, step_C
+};
+
+struct base64_encodestate {
+ enum base64_encodestep step;
+ char result;
+ int stepcount;
+};
+
+void base64_init_encodestate(struct base64_encodestate *state_in);
+
+char base64_encode_value(char value_in);
+
+int base64_encode_block(const char *plaintext_in, int length_in, char *code_out,
+ struct base64_encodestate *state_in);
+
+int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in);
+
+
+enum base64_decodestep {
+ step_a, step_b, step_c, step_d
+};
+
+struct base64_decodestate {
+ enum base64_decodestep step;
+ char plainchar;
+};
+
+void base64_init_decodestate(struct base64_decodestate *state_in);
+
+signed char base64_decode_value(signed char value_in);
+
+int base64_decode_block(const char *code_in, int length_in, char *plaintext_out,
+ struct base64_decodestate *state_in);
+
+#endif /* _BASE64_H_ */
diff --git a/lib/bfd.c b/lib/bfd.c
index 7b711a9fba..29b8d85d8d 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -461,14 +461,14 @@ static bool _bfd_sess_valid(const struct bfd_session_params *bsp)
return true;
}
-static int _bfd_sess_send(struct thread *t)
+static void _bfd_sess_send(struct thread *t)
{
struct bfd_session_params *bsp = THREAD_ARG(t);
int rv;
/* Validate configuration before trying to send bogus data. */
if (!_bfd_sess_valid(bsp))
- return 0;
+ return;
if (bsp->lastev == BSE_INSTALL) {
bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE
@@ -478,7 +478,7 @@ static int _bfd_sess_send(struct thread *t)
/* If not installed and asked for uninstall, do nothing. */
if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER)
- return 0;
+ return;
rv = zclient_bfd_command(bsglobal.zc, &bsp->args);
/* Command was sent successfully. */
@@ -504,8 +504,6 @@ static int _bfd_sess_send(struct thread *t)
bsp->lastev == BSE_INSTALL ? "installed"
: "uninstalled");
}
-
- return 0;
}
static void _bfd_sess_remove(struct bfd_session_params *bsp)
diff --git a/lib/checksum.c b/lib/checksum.c
index 3473370041..6c5f06de45 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -9,13 +9,24 @@
#include <zebra.h>
#include "checksum.h"
-int /* return checksum in low-order 16 bits */
- in_cksum(void *parg, int nbytes)
+#define add_carry(dst, add) \
+ do { \
+ typeof(dst) _add = (add); \
+ dst += _add; \
+ if (dst < _add) \
+ dst++; \
+ } while (0)
+
+uint16_t in_cksumv(const struct iovec *iov, size_t iov_len)
{
- unsigned short *ptr = parg;
- register long sum; /* assumes long == 32 bits */
- unsigned short oddbyte;
- register unsigned short answer; /* assumes unsigned short == 16 bits */
+ const struct iovec *iov_end;
+ uint32_t sum = 0;
+
+ union {
+ uint8_t bytes[2];
+ uint16_t word;
+ } wordbuf;
+ bool have_oddbyte = false;
/*
* Our algorithm is simple, using a 32-bit accumulator (sum),
@@ -23,17 +34,42 @@ int /* return checksum in low-order 16 bits */
* all the carry bits from the top 16 bits into the lower 16 bits.
*/
- sum = 0;
- while (nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
+ for (iov_end = iov + iov_len; iov < iov_end; iov++) {
+ const uint8_t *ptr, *end;
+
+ ptr = (const uint8_t *)iov->iov_base;
+ end = ptr + iov->iov_len;
+ if (ptr == end)
+ continue;
+
+ if (have_oddbyte) {
+ have_oddbyte = false;
+ wordbuf.bytes[1] = *ptr++;
+
+ add_carry(sum, wordbuf.word);
+ }
+
+ while (ptr + 8 <= end) {
+ add_carry(sum, *(const uint32_t *)(ptr + 0));
+ add_carry(sum, *(const uint32_t *)(ptr + 4));
+ ptr += 8;
+ }
+
+ while (ptr + 2 <= end) {
+ add_carry(sum, *(const uint16_t *)ptr);
+ ptr += 2;
+ }
+
+ if (ptr + 1 <= end) {
+ wordbuf.bytes[0] = *ptr++;
+ have_oddbyte = true;
+ }
}
/* mop up an odd byte, if necessary */
- if (nbytes == 1) {
- oddbyte = 0; /* make sure top half is zero */
- *((uint8_t *)&oddbyte) = *(uint8_t *)ptr; /* one byte only */
- sum += oddbyte;
+ if (have_oddbyte) {
+ wordbuf.bytes[1] = 0;
+ add_carry(sum, wordbuf.word);
}
/*
@@ -42,26 +78,7 @@ int /* return checksum in low-order 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
sum += (sum >> 16); /* add carry */
- answer = ~sum; /* ones-complement, then truncate to 16 bits */
- return (answer);
-}
-
-int in_cksum_with_ph4(struct ipv4_ph *ph, void *data, int nbytes)
-{
- uint8_t dat[sizeof(struct ipv4_ph) + nbytes];
-
- memcpy(dat, ph, sizeof(struct ipv4_ph));
- memcpy(dat + sizeof(struct ipv4_ph), data, nbytes);
- return in_cksum(dat, sizeof(dat));
-}
-
-int in_cksum_with_ph6(struct ipv6_ph *ph, void *data, int nbytes)
-{
- uint8_t dat[sizeof(struct ipv6_ph) + nbytes];
-
- memcpy(dat, ph, sizeof(struct ipv6_ph));
- memcpy(dat + sizeof(struct ipv6_ph), data, nbytes);
- return in_cksum(dat, sizeof(dat));
+ return ~sum;
}
/* Fletcher Checksum -- Refer to RFC1008. */
diff --git a/lib/checksum.h b/lib/checksum.h
index 56771d4f24..508c3f38a6 100644
--- a/lib/checksum.h
+++ b/lib/checksum.h
@@ -1,3 +1,6 @@
+#ifndef _FRR_CHECKSUM_H
+#define _FRR_CHECKSUM_H
+
#include <stdint.h>
#include <netinet/in.h>
@@ -24,9 +27,41 @@ struct ipv6_ph {
uint8_t next_hdr;
} __attribute__((packed));
-extern int in_cksum(void *data, int nbytes);
-extern int in_cksum_with_ph4(struct ipv4_ph *ph, void *data, int nbytes);
-extern int in_cksum_with_ph6(struct ipv6_ph *ph, void *data, int nbytes);
+
+extern uint16_t in_cksumv(const struct iovec *iov, size_t iov_len);
+
+static inline uint16_t in_cksum(const void *data, size_t nbytes)
+{
+ struct iovec iov[1];
+
+ iov[0].iov_base = (void *)data;
+ iov[0].iov_len = nbytes;
+ return in_cksumv(iov, array_size(iov));
+}
+
+static inline uint16_t in_cksum_with_ph4(const struct ipv4_ph *ph,
+ const void *data, size_t nbytes)
+{
+ struct iovec iov[2];
+
+ iov[0].iov_base = (void *)ph;
+ iov[0].iov_len = sizeof(*ph);
+ iov[1].iov_base = (void *)data;
+ iov[1].iov_len = nbytes;
+ return in_cksumv(iov, array_size(iov));
+}
+
+static inline uint16_t in_cksum_with_ph6(const struct ipv6_ph *ph,
+ const void *data, size_t nbytes)
+{
+ struct iovec iov[2];
+
+ iov[0].iov_base = (void *)ph;
+ iov[0].iov_len = sizeof(*ph);
+ iov[1].iov_base = (void *)data;
+ iov[1].iov_len = nbytes;
+ return in_cksumv(iov, array_size(iov));
+}
#define FLETCHER_CHECKSUM_VALIDATE 0xffff
extern uint16_t fletcher_checksum(uint8_t *, const size_t len,
@@ -35,3 +70,5 @@ extern uint16_t fletcher_checksum(uint8_t *, const size_t len,
#ifdef __cplusplus
}
#endif
+
+#endif /* _FRR_CHECKSUM_H */
diff --git a/lib/command.c b/lib/command.c
index ebdbf162d1..1989668bf0 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -2239,9 +2239,9 @@ DEFUN (banner_motd_file,
int cmd = cmd_banner_motd_file(filename);
if (cmd == CMD_ERR_NO_FILE)
- vty_out(vty, "%s does not exist", filename);
+ vty_out(vty, "%s does not exist\n", filename);
else if (cmd == CMD_WARNING_CONFIG_FAILED)
- vty_out(vty, "%s must be in %s", filename, SYSCONFDIR);
+ vty_out(vty, "%s must be in %s\n", filename, SYSCONFDIR);
return cmd;
}
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index 898fe98aad..0f56fbac83 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -237,18 +237,16 @@ void frr_pthread_stop_all(void)
*/
/* dummy task for sleeper pipe */
-static int fpt_dummy(struct thread *thread)
+static void fpt_dummy(struct thread *thread)
{
- return 0;
}
/* poison pill task to end event loop */
-static int fpt_finish(struct thread *thread)
+static void fpt_finish(struct thread *thread)
{
struct frr_pthread *fpt = THREAD_ARG(thread);
atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
- return 0;
}
/* stop function, called from other threads to halt this one */
diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c
index e572558de1..db5c4c91a2 100644
--- a/lib/frr_zmq.c
+++ b/lib/frr_zmq.c
@@ -56,7 +56,7 @@ void frrzmq_finish(void)
}
}
-static int frrzmq_read_msg(struct thread *t)
+static void frrzmq_read_msg(struct thread *t)
{
struct frrzmq_cb **cbp = THREAD_ARG(t);
struct frrzmq_cb *cb;
@@ -67,10 +67,10 @@ static int frrzmq_read_msg(struct thread *t)
size_t moresz;
if (!cbp)
- return 1;
+ return;
cb = (*cbp);
if (!cb || !cb->zmqsock)
- return 1;
+ return;
while (1) {
zmq_pollitem_t polli = {.socket = cb->zmqsock,
@@ -97,7 +97,7 @@ static int frrzmq_read_msg(struct thread *t)
if (cb->write.cancelled && !cb->write.thread)
XFREE(MTYPE_ZEROMQ_CB, *cbp);
- return 0;
+ return;
}
continue;
}
@@ -129,7 +129,7 @@ static int frrzmq_read_msg(struct thread *t)
if (cb->write.cancelled && !cb->write.thread)
XFREE(MTYPE_ZEROMQ_CB, *cbp);
- return 0;
+ return;
}
/* cb_part may have read additional parts of the
@@ -153,14 +153,13 @@ static int frrzmq_read_msg(struct thread *t)
thread_add_read(t->master, frrzmq_read_msg, cbp,
cb->fd, &cb->read.thread);
- return 0;
+ return;
out_err:
flog_err(EC_LIB_ZMQ, "ZeroMQ read error: %s(%d)", strerror(errno),
errno);
if (cb->read.cb_error)
cb->read.cb_error(cb->read.arg, cb->zmqsock);
- return 1;
}
int _frrzmq_thread_add_read(const struct xref_threadsched *xref,
@@ -215,7 +214,7 @@ int _frrzmq_thread_add_read(const struct xref_threadsched *xref,
return 0;
}
-static int frrzmq_write_msg(struct thread *t)
+static void frrzmq_write_msg(struct thread *t)
{
struct frrzmq_cb **cbp = THREAD_ARG(t);
struct frrzmq_cb *cb;
@@ -223,10 +222,10 @@ static int frrzmq_write_msg(struct thread *t)
int ret;
if (!cbp)
- return 1;
+ return;
cb = (*cbp);
if (!cb || !cb->zmqsock)
- return 1;
+ return;
while (1) {
zmq_pollitem_t polli = {.socket = cb->zmqsock,
@@ -252,7 +251,7 @@ static int frrzmq_write_msg(struct thread *t)
if (cb->read.cancelled && !cb->read.thread)
XFREE(MTYPE_ZEROMQ_CB, *cbp);
- return 0;
+ return;
}
continue;
}
@@ -263,14 +262,13 @@ static int frrzmq_write_msg(struct thread *t)
thread_add_write(t->master, frrzmq_write_msg, cbp,
cb->fd, &cb->write.thread);
- return 0;
+ return;
out_err:
flog_err(EC_LIB_ZMQ, "ZeroMQ write error: %s(%d)", strerror(errno),
errno);
if (cb->write.cb_error)
cb->write.cb_error(cb->write.arg, cb->zmqsock);
- return 1;
}
int _frrzmq_thread_add_write(const struct xref_threadsched *xref,
diff --git a/lib/if.c b/lib/if.c
index a2918b6d74..83fa85ecc1 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -490,7 +490,8 @@ struct connected *if_lookup_address(const void *matchaddr, int family,
addr.family = AF_INET6;
addr.u.prefix6 = *((struct in6_addr *)matchaddr);
addr.prefixlen = IPV6_MAX_BITLEN;
- }
+ } else
+ assert(!"Attempted lookup of family not supported");
match = NULL;
diff --git a/lib/lib_errors.c b/lib/lib_errors.c
index acc9a05c33..a658e4c295 100644
--- a/lib/lib_errors.c
+++ b/lib/lib_errors.c
@@ -69,6 +69,12 @@ static struct log_ref ferr_lib_warn[] = {
.suggestion = "Gather log data and open an Issue",
},
{
+ .code = EC_LIB_TIMER_TOO_LONG,
+ .title = "The Event subsystem has detected an internal timer that is scheduled to pop in greater than one year",
+ .description = "The Event subsystem has detected a timer being started that will pop in a timer that is greater than one year. This is a bug, please collect log data and open an issue.",
+ .suggestion = "Gather log data and open an Issue",
+ },
+ {
.code = EC_LIB_RMAP_RECURSION_LIMIT,
.title = "Reached the Route-Map Recursion Limit",
.description = "The Route-Map subsystem has detected a route-map depth of RMAP_RECURSION_LIMIT and has stopped processing",
diff --git a/lib/lib_errors.h b/lib/lib_errors.h
index 64ac6c1ceb..91f206f74a 100644
--- a/lib/lib_errors.h
+++ b/lib/lib_errors.h
@@ -48,6 +48,7 @@ enum lib_log_refs {
EC_LIB_SLOW_THREAD_WALL,
EC_LIB_STARVE_THREAD,
EC_LIB_NO_THREAD,
+ EC_LIB_TIMER_TOO_LONG,
EC_LIB_RMAP_RECURSION_LIMIT,
EC_LIB_BACKUP_CONFIG,
EC_LIB_VRF_LENGTH,
diff --git a/lib/libfrr.c b/lib/libfrr.c
index d5e326be41..10b3aad89e 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -962,7 +962,7 @@ static void frr_daemonize(void)
* to read the config in after thread execution starts, so that
* we can match this behavior.
*/
-static int frr_config_read_in(struct thread *t)
+static void frr_config_read_in(struct thread *t)
{
hook_call(frr_config_pre, master);
@@ -1000,8 +1000,6 @@ static int frr_config_read_in(struct thread *t)
}
hook_call(frr_config_post, master);
-
- return 0;
}
void frr_config_fork(void)
@@ -1097,7 +1095,7 @@ static void frr_terminal_close(int isexit)
static struct thread *daemon_ctl_thread = NULL;
-static int frr_daemon_ctl(struct thread *t)
+static void frr_daemon_ctl(struct thread *t)
{
char buf[1];
ssize_t nr;
@@ -1106,7 +1104,7 @@ static int frr_daemon_ctl(struct thread *t)
if (nr < 0 && (errno == EINTR || errno == EAGAIN))
goto out;
if (nr <= 0)
- return 0;
+ return;
switch (buf[0]) {
case 'S': /* SIGTSTP */
@@ -1131,7 +1129,6 @@ static int frr_daemon_ctl(struct thread *t)
out:
thread_add_read(master, frr_daemon_ctl, NULL, daemon_ctl_sock,
&daemon_ctl_thread);
- return 0;
}
void frr_detach(void)
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 70c71b18c4..1e25f6a1e2 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -347,7 +347,7 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty)
return ret;
}
-static int nb_cli_confirmed_commit_timeout(struct thread *thread)
+static void nb_cli_confirmed_commit_timeout(struct thread *thread)
{
struct vty *vty = THREAD_ARG(thread);
@@ -357,8 +357,6 @@ static int nb_cli_confirmed_commit_timeout(struct thread *thread)
nb_cli_confirmed_commit_rollback(vty);
nb_cli_confirmed_commit_clean(vty);
-
- return 0;
}
static int nb_cli_commit(struct vty *vty, bool force,
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index e1c8983fca..27eaefd071 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -283,7 +283,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op,
return ITER_RECURSE;
}
-static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
+static void frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
{
struct nb_context context = {};
struct nb_config *candidate;
@@ -313,9 +313,9 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
0, "Couldn't apply configuration changes")
!= CONFD_OK) {
flog_err_confd("cdb_sub_abort_trans");
- return -1;
+ return;
}
- return 0;
+ return;
}
/*
@@ -346,25 +346,23 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
errmsg)
!= CONFD_OK) {
flog_err_confd("cdb_sub_abort_trans");
- return -1;
+ return;
}
} else {
/* Acknowledge the notification. */
if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY)
!= CONFD_OK) {
flog_err_confd("cdb_sync_subscription_socket");
- return -1;
+ return;
}
/* No configuration changes. */
if (!transaction)
nb_config_free(candidate);
}
-
- return 0;
}
-static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen)
+static void frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen)
{
/*
* No need to process the configuration changes again as we're already
@@ -385,10 +383,8 @@ static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen)
/* Acknowledge the notification. */
if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) != CONFD_OK) {
flog_err_confd("cdb_sync_subscription_socket");
- return -1;
+ return;
}
-
- return 0;
}
static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen)
@@ -417,7 +413,7 @@ static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen)
return 0;
}
-static int frr_confd_cdb_read_cb(struct thread *thread)
+static void frr_confd_cdb_read_cb(struct thread *thread)
{
int fd = THREAD_FD(thread);
enum cdb_sub_notification cdb_ev;
@@ -430,19 +426,22 @@ static int frr_confd_cdb_read_cb(struct thread *thread)
if (cdb_read_subscription_socket2(fd, &cdb_ev, &flags, &subp, &reslen)
!= CONFD_OK) {
flog_err_confd("cdb_read_subscription_socket2");
- return -1;
+ return;
}
switch (cdb_ev) {
case CDB_SUB_PREPARE:
- return frr_confd_cdb_read_cb_prepare(fd, subp, reslen);
+ frr_confd_cdb_read_cb_prepare(fd, subp, reslen);
+ break;
case CDB_SUB_COMMIT:
- return frr_confd_cdb_read_cb_commit(fd, subp, reslen);
+ frr_confd_cdb_read_cb_commit(fd, subp, reslen);
+ break;
case CDB_SUB_ABORT:
- return frr_confd_cdb_read_cb_abort(fd, subp, reslen);
+ frr_confd_cdb_read_cb_abort(fd, subp, reslen);
+ break;
default:
flog_err_confd("unknown CDB event");
- return -1;
+ break;
}
}
@@ -1186,7 +1185,7 @@ static int frr_confd_dp_read(struct confd_daemon_ctx *dctx, int fd)
return 0;
}
-static int frr_confd_dp_ctl_read(struct thread *thread)
+static void frr_confd_dp_ctl_read(struct thread *thread)
{
struct confd_daemon_ctx *dctx = THREAD_ARG(thread);
int fd = THREAD_FD(thread);
@@ -1194,11 +1193,9 @@ static int frr_confd_dp_ctl_read(struct thread *thread)
thread_add_read(master, frr_confd_dp_ctl_read, dctx, fd, &t_dp_ctl);
frr_confd_dp_read(dctx, fd);
-
- return 0;
}
-static int frr_confd_dp_worker_read(struct thread *thread)
+static void frr_confd_dp_worker_read(struct thread *thread)
{
struct confd_daemon_ctx *dctx = THREAD_ARG(thread);
int fd = THREAD_FD(thread);
@@ -1206,8 +1203,6 @@ static int frr_confd_dp_worker_read(struct thread *thread)
thread_add_read(master, frr_confd_dp_worker_read, dctx, fd, &t_dp_worker);
frr_confd_dp_read(dctx, fd);
-
- return 0;
}
static int frr_confd_subscribe_state(const struct lysc_node *snode, void *arg)
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index f5c2a91a50..e2a6290035 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -215,7 +215,7 @@ template <typename Q, typename S> class NewRpcState : RpcStateBase
}
- static int c_callback(struct thread *thread)
+ static void c_callback(struct thread *thread)
{
auto _tag = static_cast<NewRpcState<Q, S> *>(thread->arg);
/*
@@ -234,7 +234,7 @@ template <typename Q, typename S> class NewRpcState : RpcStateBase
pthread_cond_signal(&_tag->cond);
pthread_mutex_unlock(&_tag->cmux);
- return 0;
+ return;
}
const char *name;
@@ -1410,7 +1410,7 @@ static int frr_grpc_finish(void)
* fork. This is done by scheduling this init function as an event task, since
* the event loop doesn't run until after fork.
*/
-static int frr_grpc_module_very_late_init(struct thread *thread)
+static void frr_grpc_module_very_late_init(struct thread *thread)
{
const char *args = THIS_MODULE->load_args;
uint port = GRPC_DEFAULT_PORT;
@@ -1428,11 +1428,10 @@ static int frr_grpc_module_very_late_init(struct thread *thread)
if (frr_grpc_init(port) < 0)
goto error;
- return 0;
+ return;
error:
flog_err(EC_LIB_GRPC_INIT, "failed to initialize the gRPC module");
- return -1;
}
static int frr_grpc_module_late_init(struct thread_master *tm)
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 86a159e507..0158d8ea0a 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -41,7 +41,7 @@ static sr_session_ctx_t *session;
static sr_conn_ctx_t *connection;
static struct nb_transaction *transaction;
-static int frr_sr_read_cb(struct thread *thread);
+static void frr_sr_read_cb(struct thread *thread);
static int frr_sr_finish(void);
/* Convert FRR YANG data value to sysrepo YANG data value. */
@@ -526,7 +526,7 @@ static int frr_sr_notification_send(const char *xpath, struct list *arguments)
return NB_OK;
}
-static int frr_sr_read_cb(struct thread *thread)
+static void frr_sr_read_cb(struct thread *thread)
{
struct yang_module *module = THREAD_ARG(thread);
int fd = THREAD_FD(thread);
@@ -536,12 +536,10 @@ static int frr_sr_read_cb(struct thread *thread)
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO, "%s: sr_fd_event_process(): %s",
__func__, sr_strerror(ret));
- return -1;
+ return;
}
thread_add_read(master, frr_sr_read_cb, module, fd, &module->sr_thread);
-
- return 0;
}
static void frr_sr_subscribe_config(struct yang_module *module)
diff --git a/lib/pullwr.c b/lib/pullwr.c
index 15563d2471..5e836984b2 100644
--- a/lib/pullwr.c
+++ b/lib/pullwr.c
@@ -51,7 +51,7 @@ struct pullwr {
DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller");
DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF, "pull-driven write buffer");
-static int pullwr_run(struct thread *t);
+static void pullwr_run(struct thread *t);
struct pullwr *_pullwr_new(struct thread_master *tm, int fd,
void *arg,
@@ -189,7 +189,7 @@ void pullwr_write(struct pullwr *pullwr, const void *data, size_t len)
pullwr_bump(pullwr);
}
-static int pullwr_run(struct thread *t)
+static void pullwr_run(struct thread *t)
{
struct pullwr *pullwr = THREAD_ARG(t);
struct iovec iov[2];
@@ -222,7 +222,7 @@ static int pullwr_run(struct thread *t)
* into idle, i.e. no calling thread_add_write()
*/
pullwr_resize(pullwr, 0);
- return 0;
+ return;
}
niov = pullwr_iov(pullwr, iov);
@@ -233,12 +233,12 @@ static int pullwr_run(struct thread *t)
if (errno == EAGAIN || errno == EWOULDBLOCK)
break;
pullwr->err(pullwr->arg, pullwr, false);
- return 0;
+ return;
}
if (nwr == 0) {
pullwr->err(pullwr->arg, pullwr, true);
- return 0;
+ return;
}
pullwr->total_written += nwr;
@@ -258,7 +258,6 @@ static int pullwr_run(struct thread *t)
*/
if (!maxspun)
pullwr_resize(pullwr, 0);
- return 0;
}
void pullwr_stats(struct pullwr *pullwr, uint64_t *total_written,
diff --git a/lib/resolver.c b/lib/resolver.c
index 29138bbc8d..93fa84bbe9 100644
--- a/lib/resolver.c
+++ b/lib/resolver.c
@@ -104,17 +104,15 @@ static void resolver_fd_drop_maybe(struct resolver_fd *resfd)
static void resolver_update_timeouts(struct resolver_state *r);
-static int resolver_cb_timeout(struct thread *t)
+static void resolver_cb_timeout(struct thread *t)
{
struct resolver_state *r = THREAD_ARG(t);
ares_process(r->channel, NULL, NULL);
resolver_update_timeouts(r);
-
- return 0;
}
-static int resolver_cb_socket_readable(struct thread *t)
+static void resolver_cb_socket_readable(struct thread *t)
{
struct resolver_fd *resfd = THREAD_ARG(t);
struct resolver_state *r = resfd->state;
@@ -127,11 +125,9 @@ static int resolver_cb_socket_readable(struct thread *t)
*/
ares_process_fd(r->channel, resfd->fd, ARES_SOCKET_BAD);
resolver_update_timeouts(r);
-
- return 0;
}
-static int resolver_cb_socket_writable(struct thread *t)
+static void resolver_cb_socket_writable(struct thread *t)
{
struct resolver_fd *resfd = THREAD_ARG(t);
struct resolver_state *r = resfd->state;
@@ -144,8 +140,6 @@ static int resolver_cb_socket_writable(struct thread *t)
*/
ares_process_fd(r->channel, ARES_SOCKET_BAD, resfd->fd);
resolver_update_timeouts(r);
-
- return 0;
}
static void resolver_update_timeouts(struct resolver_state *r)
@@ -232,7 +226,7 @@ static void ares_address_cb(void *arg, int status, int timeouts,
callback(query, NULL, i, &addr[0]);
}
-static int resolver_cb_literal(struct thread *t)
+static void resolver_cb_literal(struct thread *t)
{
struct resolver_query *query = THREAD_ARG(t);
void (*callback)(struct resolver_query *, const char *, int,
@@ -242,7 +236,6 @@ static int resolver_cb_literal(struct thread *t)
query->callback = NULL;
callback(query, ARES_SUCCESS, 1, &query->literal_addr);
- return 0;
}
void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id,
diff --git a/lib/routemap.c b/lib/routemap.c
index 7f733c8114..9afe18d10b 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -1799,12 +1799,11 @@ static struct list *route_map_get_index_list(struct route_node **rn,
/*
* This function returns the route-map index that best matches the prefix.
*/
-static struct route_map_index *route_map_get_index(struct route_map *map,
- const struct prefix *prefix,
- void *object,
- uint8_t *match_ret)
+static struct route_map_index *
+route_map_get_index(struct route_map *map, const struct prefix *prefix,
+ void *object, enum route_map_cmd_result_t *match_ret)
{
- int ret = 0;
+ enum route_map_cmd_result_t ret = RMAP_NOMATCH;
struct list *candidate_rmap_list = NULL;
struct route_node *rn = NULL;
struct listnode *ln = NULL, *nn = NULL;
@@ -2559,7 +2558,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
if ((!map->optimization_disabled)
&& (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
index = route_map_get_index(map, prefix, match_object,
- (uint8_t *)&match_ret);
+ &match_ret);
if (index) {
index->applied++;
if (rmap_debug)
diff --git a/lib/sigevent.c b/lib/sigevent.c
index 00bc31f517..0f20bc0270 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -143,7 +143,7 @@ int frr_sigevent_process(void)
#ifdef SIGEVENT_SCHEDULE_THREAD
/* timer thread to check signals. shouldn't be needed */
-int frr_signal_timer(struct thread *t)
+void frr_signal_timer(struct thread *t)
{
struct frr_sigevent_master_t *sigm;
@@ -151,7 +151,7 @@ int frr_signal_timer(struct thread *t)
sigm->t = NULL;
thread_add_timer(sigm->t->master, frr_signal_timer, &sigmaster,
FRR_SIGNAL_TIMER_INTERVAL, &sigm->t);
- return frr_sigevent_process();
+ frr_sigevent_process();
}
#endif /* SIGEVENT_SCHEDULE_THREAD */
diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c
index a273e93463..117b7d3e88 100644
--- a/lib/spf_backoff.c
+++ b/lib/spf_backoff.c
@@ -117,17 +117,16 @@ void spf_backoff_free(struct spf_backoff *backoff)
XFREE(MTYPE_SPF_BACKOFF, backoff);
}
-static int spf_backoff_timetolearn_elapsed(struct thread *thread)
+static void spf_backoff_timetolearn_elapsed(struct thread *thread)
{
struct spf_backoff *backoff = THREAD_ARG(thread);
backoff->state = SPF_BACKOFF_LONG_WAIT;
backoff_debug("SPF Back-off(%s) TIMETOLEARN elapsed, move to state %s",
backoff->name, spf_backoff_state2str(backoff->state));
- return 0;
}
-static int spf_backoff_holddown_elapsed(struct thread *thread)
+static void spf_backoff_holddown_elapsed(struct thread *thread)
{
struct spf_backoff *backoff = THREAD_ARG(thread);
@@ -136,7 +135,6 @@ static int spf_backoff_holddown_elapsed(struct thread *thread)
backoff->state = SPF_BACKOFF_QUIET;
backoff_debug("SPF Back-off(%s) HOLDDOWN elapsed, move to state %s",
backoff->name, spf_backoff_state2str(backoff->state));
- return 0;
}
long spf_backoff_schedule(struct spf_backoff *backoff)
diff --git a/lib/subdir.am b/lib/subdir.am
index 648ab7f14a..b505e235ca 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -8,6 +8,7 @@ lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST
lib_libfrr_la_SOURCES = \
lib/agg_table.c \
lib/atomlist.c \
+ lib/base64.c \
lib/bfd.c \
lib/buffer.c \
lib/checksum.c \
@@ -113,6 +114,7 @@ lib_libfrr_la_SOURCES = \
lib/zlog.c \
lib/zlog_5424.c \
lib/zlog_5424_cli.c \
+ lib/zlog_live.c \
lib/zlog_targets.c \
lib/printf/printf-pos.c \
lib/printf/vfprintf.c \
@@ -177,6 +179,7 @@ clippy_scan += \
pkginclude_HEADERS += \
lib/agg_table.h \
lib/atomlist.h \
+ lib/base64.h \
lib/bfd.h \
lib/bitfield.h \
lib/buffer.h \
@@ -287,6 +290,7 @@ pkginclude_HEADERS += \
lib/zebra.h \
lib/zlog.h \
lib/zlog_5424.h \
+ lib/zlog_live.h \
lib/zlog_targets.h \
lib/pbr.h \
lib/routing_nb.h \
diff --git a/lib/systemd.c b/lib/systemd.c
index 2238dc9f3d..1c9a6f122e 100644
--- a/lib/systemd.c
+++ b/lib/systemd.c
@@ -80,14 +80,13 @@ void systemd_send_stopping(void)
static struct thread_master *systemd_master = NULL;
-static int systemd_send_watchdog(struct thread *t)
+static void systemd_send_watchdog(struct thread *t)
{
systemd_send_information("WATCHDOG=1");
assert(watchdog_msec > 0);
thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL,
watchdog_msec, NULL);
- return 1;
}
void systemd_send_started(struct thread_master *m)
diff --git a/lib/thread.c b/lib/thread.c
index ada7a9cc80..90074b3d89 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -498,6 +498,41 @@ DEFUN (clear_thread_cpu,
return CMD_SUCCESS;
}
+static void show_thread_timers_helper(struct vty *vty, struct thread_master *m)
+{
+ const char *name = m->name ? m->name : "main";
+ char underline[strlen(name) + 1];
+ struct thread *thread;
+
+ memset(underline, '-', sizeof(underline));
+ underline[sizeof(underline) - 1] = '\0';
+
+ vty_out(vty, "\nShowing timers for %s\n", name);
+ vty_out(vty, "-------------------%s\n", underline);
+
+ frr_each (thread_timer_list, &m->timer, thread) {
+ vty_out(vty, " %-50s%pTH\n", thread->hist->funcname, thread);
+ }
+}
+
+DEFPY_NOSH (show_thread_timers,
+ show_thread_timers_cmd,
+ "show thread timers",
+ SHOW_STR
+ "Thread information\n"
+ "Show all timers and how long they have in the system\n")
+{
+ struct listnode *node;
+ struct thread_master *m;
+
+ frr_with_mutex (&masters_mtx) {
+ for (ALL_LIST_ELEMENTS_RO(masters, node, m))
+ show_thread_timers_helper(vty, m);
+ }
+
+ return CMD_SUCCESS;
+}
+
void thread_cmd_init(void)
{
install_element(VIEW_NODE, &show_thread_cpu_cmd);
@@ -509,6 +544,8 @@ void thread_cmd_init(void)
install_element(CONFIG_NODE, &no_service_cputime_warning_cmd);
install_element(CONFIG_NODE, &service_walltime_warning_cmd);
install_element(CONFIG_NODE, &no_service_walltime_warning_cmd);
+
+ install_element(VIEW_NODE, &show_thread_timers_cmd);
}
/* CLI end ------------------------------------------------------------------ */
@@ -773,7 +810,7 @@ char *thread_timer_to_hhmmss(char *buf, int buf_size,
/* Get new thread. */
static struct thread *thread_get(struct thread_master *m, uint8_t type,
- int (*func)(struct thread *), void *arg,
+ void (*func)(struct thread *), void *arg,
const struct xref_threadsched *xref)
{
struct thread *thread = thread_list_pop(&m->unuse);
@@ -930,7 +967,7 @@ done:
/* Add new read thread. */
void _thread_add_read_write(const struct xref_threadsched *xref,
struct thread_master *m,
- int (*func)(struct thread *), void *arg, int fd,
+ void (*func)(struct thread *), void *arg, int fd,
struct thread **t_ptr)
{
int dir = xref->thread_type;
@@ -1010,7 +1047,7 @@ void _thread_add_read_write(const struct xref_threadsched *xref,
static void _thread_add_timer_timeval(const struct xref_threadsched *xref,
struct thread_master *m,
- int (*func)(struct thread *), void *arg,
+ void (*func)(struct thread *), void *arg,
struct timeval *time_relative,
struct thread **t_ptr)
{
@@ -1052,12 +1089,18 @@ static void _thread_add_timer_timeval(const struct xref_threadsched *xref,
if (thread_timer_list_first(&m->timer) == thread)
AWAKEN(m);
}
+#define ONEYEAR2SEC (60 * 60 * 24 * 365)
+ if (time_relative->tv_sec > ONEYEAR2SEC)
+ flog_err(
+ EC_LIB_TIMER_TOO_LONG,
+ "Timer: %pTHD is created with an expiration that is greater than 1 year",
+ thread);
}
/* Add timer event thread. */
void _thread_add_timer(const struct xref_threadsched *xref,
- struct thread_master *m, int (*func)(struct thread *),
+ struct thread_master *m, void (*func)(struct thread *),
void *arg, long timer, struct thread **t_ptr)
{
struct timeval trel;
@@ -1073,8 +1116,8 @@ void _thread_add_timer(const struct xref_threadsched *xref,
/* Add timer event thread with "millisecond" resolution */
void _thread_add_timer_msec(const struct xref_threadsched *xref,
struct thread_master *m,
- int (*func)(struct thread *), void *arg, long timer,
- struct thread **t_ptr)
+ void (*func)(struct thread *), void *arg,
+ long timer, struct thread **t_ptr)
{
struct timeval trel;
@@ -1088,15 +1131,16 @@ void _thread_add_timer_msec(const struct xref_threadsched *xref,
/* Add timer event thread with "timeval" resolution */
void _thread_add_timer_tv(const struct xref_threadsched *xref,
- struct thread_master *m, int (*func)(struct thread *),
- void *arg, struct timeval *tv, struct thread **t_ptr)
+ struct thread_master *m,
+ void (*func)(struct thread *), void *arg,
+ struct timeval *tv, struct thread **t_ptr)
{
_thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr);
}
/* Add simple event thread. */
void _thread_add_event(const struct xref_threadsched *xref,
- struct thread_master *m, int (*func)(struct thread *),
+ struct thread_master *m, void (*func)(struct thread *),
void *arg, int val, struct thread **t_ptr)
{
struct thread *thread = NULL;
@@ -1840,6 +1884,27 @@ unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
unsigned long *cputime)
{
#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+
+#ifdef __FreeBSD__
+ /*
+ * FreeBSD appears to have an issue when calling clock_gettime
+ * with CLOCK_THREAD_CPUTIME_ID really close to each other
+ * occassionally the now time will be before the start time.
+ * This is not good and FRR is ending up with CPU HOG's
+ * when the subtraction wraps to very large numbers
+ *
+ * What we are going to do here is cheat a little bit
+ * and notice that this is a problem and just correct
+ * it so that it is impossible to happen
+ */
+ if (start->cpu.tv_sec == now->cpu.tv_sec &&
+ start->cpu.tv_nsec > now->cpu.tv_nsec)
+ now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
+ else if (start->cpu.tv_sec > now->cpu.tv_sec) {
+ now->cpu.tv_sec = start->cpu.tv_sec;
+ now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
+ }
+#endif
*cputime = (now->cpu.tv_sec - start->cpu.tv_sec) * TIMER_SECOND_MICRO
+ (now->cpu.tv_nsec - start->cpu.tv_nsec) / 1000;
#else
@@ -2008,7 +2073,7 @@ void thread_call(struct thread *thread)
/* Execute thread */
void _thread_execute(const struct xref_threadsched *xref,
- struct thread_master *m, int (*func)(struct thread *),
+ struct thread_master *m, void (*func)(struct thread *),
void *arg, int val)
{
struct thread *thread;
diff --git a/lib/thread.h b/lib/thread.h
index 0c2a4ba869..a2049ae52a 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -114,7 +114,7 @@ struct thread {
struct thread_timer_list_item timeritem;
struct thread **ref; /* external reference (if given) */
struct thread_master *master; /* pointer to the struct thread_master */
- int (*func)(struct thread *); /* event function */
+ void (*func)(struct thread *); /* event function */
void *arg; /* event argument */
union {
int val; /* second argument of the event. */
@@ -134,7 +134,7 @@ struct thread {
#endif
struct cpu_thread_history {
- int (*func)(struct thread *);
+ void (*func)(struct thread *);
atomic_size_t total_cpu_warn;
atomic_size_t total_wall_warn;
atomic_size_t total_starv_warn;
@@ -227,32 +227,32 @@ extern void thread_master_free_unused(struct thread_master *);
extern void _thread_add_read_write(const struct xref_threadsched *xref,
struct thread_master *master,
- int (*fn)(struct thread *), void *arg,
+ void (*fn)(struct thread *), void *arg,
int fd, struct thread **tref);
extern void _thread_add_timer(const struct xref_threadsched *xref,
struct thread_master *master,
- int (*fn)(struct thread *), void *arg, long t,
+ void (*fn)(struct thread *), void *arg, long t,
struct thread **tref);
extern void _thread_add_timer_msec(const struct xref_threadsched *xref,
struct thread_master *master,
- int (*fn)(struct thread *), void *arg,
+ void (*fn)(struct thread *), void *arg,
long t, struct thread **tref);
extern void _thread_add_timer_tv(const struct xref_threadsched *xref,
struct thread_master *master,
- int (*fn)(struct thread *), void *arg,
+ void (*fn)(struct thread *), void *arg,
struct timeval *tv, struct thread **tref);
extern void _thread_add_event(const struct xref_threadsched *xref,
struct thread_master *master,
- int (*fn)(struct thread *), void *arg, int val,
+ void (*fn)(struct thread *), void *arg, int val,
struct thread **tref);
extern void _thread_execute(const struct xref_threadsched *xref,
struct thread_master *master,
- int (*fn)(struct thread *), void *arg, int val);
+ void (*fn)(struct thread *), void *arg, int val);
extern void thread_cancel(struct thread **event);
extern void thread_cancel_async(struct thread_master *, struct thread **,
diff --git a/lib/vty.c b/lib/vty.c
index 8eaf13619b..78ef9894de 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -65,7 +65,7 @@ DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history");
DECLARE_DLIST(vtys, struct vty, itm);
/* Vty events */
-enum event {
+enum vty_event {
VTY_SERV,
VTY_READ,
VTY_WRITE,
@@ -90,8 +90,8 @@ struct vty_serv {
DECLARE_DLIST(vtyservs, struct vty_serv, itm);
-static void vty_event_serv(enum event event, struct vty_serv *);
-static void vty_event(enum event, struct vty *);
+static void vty_event_serv(enum vty_event event, struct vty_serv *);
+static void vty_event(enum vty_event, struct vty *);
/* Extern host structure from command.c */
extern struct host host;
@@ -1299,7 +1299,7 @@ static void vty_buffer_reset(struct vty *vty)
}
/* Read data via vty socket. */
-static int vty_read(struct thread *thread)
+static void vty_read(struct thread *thread)
{
int i;
int nbytes;
@@ -1312,10 +1312,8 @@ static int vty_read(struct thread *thread)
if (nbytes < 0) {
if (ERRNO_IO_RETRY(errno)) {
vty_event(VTY_READ, vty);
- return 0;
+ return;
}
- vty->monitor = 0; /* disable monitoring to avoid
- infinite recursion */
flog_err(
EC_LIB_SOCKET,
"%s: read error on vty client fd %d, closing: %s",
@@ -1464,6 +1462,11 @@ static int vty_read(struct thread *thread)
vty_out(vty, "\n");
buffer_flush_available(vty->obuf, vty->wfd);
vty_execute(vty);
+
+ if (vty->pass_fd != -1) {
+ close(vty->pass_fd);
+ vty->pass_fd = -1;
+ }
break;
case '\t':
vty_complete_command(vty);
@@ -1496,11 +1499,10 @@ static int vty_read(struct thread *thread)
vty_event(VTY_WRITE, vty);
vty_event(VTY_READ, vty);
}
- return 0;
}
/* Flush buffer to the vty. */
-static int vty_flush(struct thread *thread)
+static void vty_flush(struct thread *thread)
{
int erase;
buffer_status_t flushrc;
@@ -1525,14 +1527,12 @@ static int vty_flush(struct thread *thread)
vty->lines >= 0 ? vty->lines : vty->height, erase, 0);
switch (flushrc) {
case BUFFER_ERROR:
- vty->monitor =
- 0; /* disable monitoring to avoid infinite recursion */
zlog_info("buffer_flush failed on vty client fd %d/%d, closing",
vty->fd, vty->wfd);
buffer_reset(vty->lbuf);
buffer_reset(vty->obuf);
vty_close(vty);
- return 0;
+ return;
case BUFFER_EMPTY:
if (vty->status == VTY_CLOSE)
vty_close(vty);
@@ -1549,8 +1549,6 @@ static int vty_flush(struct thread *thread)
vty_event(VTY_WRITE, vty);
break;
}
-
- return 0;
}
/* Allocate new vty struct. */
@@ -1564,6 +1562,7 @@ struct vty *vty_new(void)
new->obuf = buffer_new(0); /* Use default buffer size. */
new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
new->max = VTY_BUFSIZ;
+ new->pass_fd = -1;
return new;
}
@@ -1753,7 +1752,7 @@ struct vty *vty_stdio(void (*atclose)(int isexit))
}
/* Accept connection from the network. */
-static int vty_accept(struct thread *thread)
+static void vty_accept(struct thread *thread)
{
struct vty_serv *vtyserv = THREAD_ARG(thread);
int vty_sock;
@@ -1774,7 +1773,7 @@ static int vty_accept(struct thread *thread)
if (vty_sock < 0) {
flog_err(EC_LIB_SOCKET, "can't accept vty socket : %s",
safe_strerror(errno));
- return -1;
+ return;
}
set_nonblocking(vty_sock);
set_cloexec(vty_sock);
@@ -1783,7 +1782,7 @@ static int vty_accept(struct thread *thread)
close(vty_sock);
zlog_info("Vty unable to convert prefix from sockunion %pSU",
&su);
- return -1;
+ return;
}
/* VTY's accesslist apply. */
@@ -1792,7 +1791,7 @@ static int vty_accept(struct thread *thread)
&& (access_list_apply(acl, &p) == FILTER_DENY)) {
zlog_info("Vty connection refused from %pSU", &su);
close(vty_sock);
- return 0;
+ return;
}
}
@@ -1803,7 +1802,7 @@ static int vty_accept(struct thread *thread)
&& (access_list_apply(acl, &p) == FILTER_DENY)) {
zlog_info("Vty connection refused from %pSU", &su);
close(vty_sock);
- return 0;
+ return;
}
}
@@ -1817,8 +1816,6 @@ static int vty_accept(struct thread *thread)
zlog_info("Vty connection from %pSU", &su);
vty_create(vty_sock, &su);
-
- return 0;
}
static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
@@ -1968,7 +1965,7 @@ static void vty_serv_un(const char *path)
/* #define VTYSH_DEBUG 1 */
-static int vtysh_accept(struct thread *thread)
+static void vtysh_accept(struct thread *thread)
{
struct vty_serv *vtyserv = THREAD_ARG(thread);
int accept_sock = vtyserv->sock;
@@ -1988,7 +1985,7 @@ static int vtysh_accept(struct thread *thread)
if (sock < 0) {
flog_err(EC_LIB_SOCKET, "can't accept vty socket : %s",
safe_strerror(errno));
- return -1;
+ return;
}
if (set_nonblocking(sock) < 0) {
@@ -1997,7 +1994,7 @@ static int vtysh_accept(struct thread *thread)
"vtysh_accept: could not set vty socket %d to non-blocking, %s, closing",
sock, safe_strerror(errno));
close(sock);
- return -1;
+ return;
}
set_cloexec(sock);
@@ -2013,19 +2010,70 @@ static int vtysh_accept(struct thread *thread)
vtys_add_tail(vtysh_sessions, vty);
vty_event(VTYSH_READ, vty);
+}
- return 0;
+static int vtysh_do_pass_fd(struct vty *vty)
+{
+ struct iovec iov[1] = {
+ {
+ .iov_base = vty->pass_fd_status,
+ .iov_len = sizeof(vty->pass_fd_status),
+ },
+ };
+ union {
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr align;
+ } u;
+ struct msghdr mh = {
+ .msg_iov = iov,
+ .msg_iovlen = array_size(iov),
+ .msg_control = u.buf,
+ .msg_controllen = sizeof(u.buf),
+ };
+ struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh);
+ ssize_t ret;
+
+ cmh->cmsg_level = SOL_SOCKET;
+ cmh->cmsg_type = SCM_RIGHTS;
+ cmh->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmh), &vty->pass_fd, sizeof(int));
+
+ ret = sendmsg(vty->wfd, &mh, 0);
+ if (ret < 0 && ERRNO_IO_RETRY(errno))
+ return BUFFER_PENDING;
+
+ close(vty->pass_fd);
+ vty->pass_fd = -1;
+ vty->status = VTY_NORMAL;
+
+ if (ret <= 0)
+ return BUFFER_ERROR;
+
+ /* resume accepting commands (suspended in vtysh_read) */
+ vty_event(VTYSH_READ, vty);
+
+ if ((size_t)ret < sizeof(vty->pass_fd_status)) {
+ size_t remains = sizeof(vty->pass_fd_status) - ret;
+
+ buffer_put(vty->obuf, vty->pass_fd_status + ret, remains);
+ return BUFFER_PENDING;
+ }
+ return BUFFER_EMPTY;
}
static int vtysh_flush(struct vty *vty)
{
- switch (buffer_flush_available(vty->obuf, vty->wfd)) {
+ int ret;
+
+ ret = buffer_flush_available(vty->obuf, vty->wfd);
+ if (ret == BUFFER_EMPTY && vty->status == VTY_PASSFD)
+ ret = vtysh_do_pass_fd(vty);
+
+ switch (ret) {
case BUFFER_PENDING:
vty_event(VTYSH_WRITE, vty);
break;
case BUFFER_ERROR:
- vty->monitor =
- 0; /* disable monitoring to avoid infinite recursion */
flog_err(EC_LIB_SOCKET, "%s: write error to fd %d, closing",
__func__, vty->fd);
buffer_reset(vty->lbuf);
@@ -2038,7 +2086,15 @@ static int vtysh_flush(struct vty *vty)
return 0;
}
-static int vtysh_read(struct thread *thread)
+void vty_pass_fd(struct vty *vty, int fd)
+{
+ if (vty->pass_fd != -1)
+ close(vty->pass_fd);
+
+ vty->pass_fd = fd;
+}
+
+static void vtysh_read(struct thread *thread)
{
int ret;
int sock;
@@ -2055,10 +2111,8 @@ static int vtysh_read(struct thread *thread)
if (nbytes < 0) {
if (ERRNO_IO_RETRY(errno)) {
vty_event(VTYSH_READ, vty);
- return 0;
+ return;
}
- vty->monitor = 0; /* disable monitoring to avoid
- infinite recursion */
flog_err(
EC_LIB_SOCKET,
"%s: read failed on vtysh client fd %d, closing: %s",
@@ -2070,7 +2124,7 @@ static int vtysh_read(struct thread *thread)
#ifdef VTYSH_DEBUG
printf("close vtysh\n");
#endif /* VTYSH_DEBUG */
- return 0;
+ return;
}
#ifdef VTYSH_DEBUG
@@ -2097,6 +2151,26 @@ static int vtysh_read(struct thread *thread)
printf("vtysh node: %d\n", vty->node);
#endif /* VTYSH_DEBUG */
+ if (vty->pass_fd != -1) {
+ memset(vty->pass_fd_status, 0, 4);
+ vty->pass_fd_status[3] = ret;
+ vty->status = VTY_PASSFD;
+
+ if (!vty->t_write)
+ vty_event(VTYSH_WRITE, vty);
+
+ /* this introduces a "sequence point"
+ * command output is written normally,
+ * read processing is suspended until
+ * buffer is empty
+ * then retcode + FD is written
+ * then normal processing resumes
+ *
+ * => skip vty_event(VTYSH_READ, vty)!
+ */
+ return;
+ }
+
/* hack for asynchronous "write integrated"
* - other commands in "buf" will be ditched
* - input during pending config-write is
@@ -2112,7 +2186,7 @@ static int vtysh_read(struct thread *thread)
if (!vty->t_write && (vtysh_flush(vty) < 0))
/* Try to flush results; exit if a write
* error occurs. */
- return 0;
+ return;
}
}
}
@@ -2121,16 +2195,13 @@ static int vtysh_read(struct thread *thread)
vty_close(vty);
else
vty_event(VTYSH_READ, vty);
-
- return 0;
}
-static int vtysh_write(struct thread *thread)
+static void vtysh_write(struct thread *thread)
{
struct vty *vty = THREAD_ARG(thread);
vtysh_flush(vty);
- return 0;
}
#endif /* VTYSH */
@@ -2171,6 +2242,12 @@ void vty_close(struct vty *vty)
THREAD_OFF(vty->t_write);
THREAD_OFF(vty->t_timeout);
+ if (vty->pass_fd != -1) {
+ close(vty->pass_fd);
+ vty->pass_fd = -1;
+ }
+ zlog_live_close(&vty->live_log);
+
/* Flush buffer. */
buffer_flush_all(vty->obuf, vty->wfd);
@@ -2221,7 +2298,7 @@ void vty_close(struct vty *vty)
}
/* When time out occur output message then close connection. */
-static int vty_timeout(struct thread *thread)
+static void vty_timeout(struct thread *thread)
{
struct vty *vty;
@@ -2236,8 +2313,6 @@ static int vty_timeout(struct thread *thread)
/* Close connection. */
vty->status = VTY_CLOSE;
vty_close(vty);
-
- return 0;
}
/* Read up configuration file from file_name. */
@@ -2608,7 +2683,7 @@ int vty_config_node_exit(struct vty *vty)
/* Master of the threads. */
static struct thread_master *vty_master;
-static void vty_event_serv(enum event event, struct vty_serv *vty_serv)
+static void vty_event_serv(enum vty_event event, struct vty_serv *vty_serv)
{
switch (event) {
case VTY_SERV:
@@ -2626,7 +2701,7 @@ static void vty_event_serv(enum event event, struct vty_serv *vty_serv)
}
}
-static void vty_event(enum event event, struct vty *vty)
+static void vty_event(enum vty_event event, struct vty *vty)
{
switch (event) {
#ifdef VTYSH
@@ -2673,8 +2748,9 @@ DEFUN_NOSH (config_who,
struct vty *v;
frr_each (vtys, vty_sessions, v)
- vty_out(vty, "%svty[%d] connected from %s.\n",
- v->config ? "*" : " ", v->fd, v->address);
+ vty_out(vty, "%svty[%d] connected from %s%s.\n",
+ v->config ? "*" : " ", v->fd, v->address,
+ zlog_live_is_null(&v->live_log) ? "" : ", live log");
return CMD_SUCCESS;
}
@@ -2867,35 +2943,56 @@ DEFUN (no_service_advanced_vty,
return CMD_SUCCESS;
}
-DEFUN_NOSH (terminal_monitor,
- terminal_monitor_cmd,
- "terminal monitor",
- "Set terminal line parameters\n"
- "Copy debug output to the current terminal line\n")
+DEFUN_NOSH(terminal_monitor,
+ terminal_monitor_cmd,
+ "terminal monitor [detach]",
+ "Set terminal line parameters\n"
+ "Copy debug output to the current terminal line\n"
+ "Keep logging feed open independent of VTY session\n")
{
- vty->monitor = 1;
+ int fd_ret = -1;
+
+ if (vty->type != VTY_SHELL_SERV) {
+ vty_out(vty, "%% not supported\n");
+ return CMD_WARNING;
+ }
+
+ if (argc == 3) {
+ struct zlog_live_cfg detach_log = {};
+
+ zlog_live_open(&detach_log, LOG_DEBUG, &fd_ret);
+ zlog_live_disown(&detach_log);
+ } else
+ zlog_live_open(&vty->live_log, LOG_DEBUG, &fd_ret);
+
+ if (fd_ret == -1) {
+ vty_out(vty, "%% error opening live log: %m\n");
+ return CMD_WARNING;
+ }
+
+ vty_pass_fd(vty, fd_ret);
return CMD_SUCCESS;
}
-DEFUN_NOSH (terminal_no_monitor,
- terminal_no_monitor_cmd,
- "terminal no monitor",
- "Set terminal line parameters\n"
- NO_STR
- "Copy debug output to the current terminal line\n")
+DEFUN_NOSH(no_terminal_monitor,
+ no_terminal_monitor_cmd,
+ "no terminal monitor",
+ NO_STR
+ "Set terminal line parameters\n"
+ "Copy debug output to the current terminal line\n")
{
- vty->monitor = 0;
+ zlog_live_close(&vty->live_log);
return CMD_SUCCESS;
}
-DEFUN_NOSH (no_terminal_monitor,
- no_terminal_monitor_cmd,
- "no terminal monitor",
- NO_STR
- "Set terminal line parameters\n"
- "Copy debug output to the current terminal line\n")
+DEFUN_NOSH(terminal_no_monitor,
+ terminal_no_monitor_cmd,
+ "terminal no monitor",
+ "Set terminal line parameters\n"
+ NO_STR
+ "Copy debug output to the current terminal line\n")
{
- return terminal_no_monitor(self, vty, argc, argv);
+ return no_terminal_monitor(self, vty, argc, argv);
}
diff --git a/lib/vty.h b/lib/vty.h
index 9ffbce3268..e42a3b210f 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -34,6 +34,7 @@
#include "qobj.h"
#include "compiler.h"
#include "northbound.h"
+#include "zlog_live.h"
#ifdef __cplusplus
extern "C" {
@@ -161,7 +162,22 @@ struct vty {
unsigned char escape;
/* Current vty status. */
- enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status;
+ enum {
+ VTY_NORMAL,
+ VTY_CLOSE,
+ VTY_MORE,
+ VTY_MORELINE,
+ VTY_PASSFD,
+ } status;
+
+ /* vtysh socket/fd passing (for terminal monitor) */
+ int pass_fd;
+
+ /* CLI command return value (likely CMD_SUCCESS) when pass_fd != -1 */
+ uint8_t pass_fd_status[4];
+
+ /* live logging target / terminal monitor */
+ struct zlog_live_cfg live_log;
/* IAC handling: was the last character received the
IAC (interpret-as-command) escape character (and therefore the next
@@ -186,9 +202,6 @@ struct vty {
/* Configure lines. */
int lines;
- /* Terminal monitor. */
- int monitor;
-
/* Read and write thread. */
struct thread *t_read;
struct thread *t_write;
@@ -329,6 +342,11 @@ extern bool vty_set_include(struct vty *vty, const char *regexp);
*/
extern int vty_json(struct vty *vty, struct json_object *json);
+/* post fd to be passed to the vtysh client
+ * fd is owned by the VTY code after this and will be closed when done
+ */
+extern void vty_pass_fd(struct vty *vty, int fd);
+
extern bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir);
extern void vty_time_print(struct vty *, int);
diff --git a/lib/wheel.c b/lib/wheel.c
index 1a0469b256..463410bea4 100644
--- a/lib/wheel.c
+++ b/lib/wheel.c
@@ -29,9 +29,9 @@ DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List");
static int debug_timer_wheel = 0;
-static int wheel_timer_thread(struct thread *t);
+static void wheel_timer_thread(struct thread *t);
-static int wheel_timer_thread_helper(struct thread *t)
+static void wheel_timer_thread_helper(struct thread *t)
{
struct listnode *node, *nextnode;
unsigned long long curr_slot;
@@ -63,19 +63,15 @@ static int wheel_timer_thread_helper(struct thread *t)
wheel->slots_to_skip = slots_to_skip;
thread_add_timer_msec(wheel->master, wheel_timer_thread, wheel,
wheel->nexttime * slots_to_skip, &wheel->timer);
-
- return 0;
}
-static int wheel_timer_thread(struct thread *t)
+static void wheel_timer_thread(struct thread *t)
{
struct timer_wheel *wheel;
wheel = THREAD_ARG(t);
thread_execute(wheel->master, wheel_timer_thread_helper, wheel, 0);
-
- return 0;
}
struct timer_wheel *wheel_init(struct thread_master *master, int period,
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 86afe4082e..92869594dd 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -238,7 +238,7 @@ void work_queue_unplug(struct work_queue *wq)
* will reschedule itself if required,
* otherwise work_queue_item_add
*/
-int work_queue_run(struct thread *thread)
+void work_queue_run(struct thread *thread)
{
struct work_queue *wq;
struct work_queue_item *item, *titem;
@@ -388,6 +388,4 @@ stats:
} else if (wq->spec.completion_func)
wq->spec.completion_func(wq);
-
- return 0;
}
diff --git a/lib/workqueue.h b/lib/workqueue.h
index b076ed0d28..39202dcda7 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -177,7 +177,7 @@ extern void work_queue_unplug(struct work_queue *wq);
bool work_queue_is_scheduled(struct work_queue *);
/* Helpers, exported for thread.c and command.c */
-extern int work_queue_run(struct thread *);
+extern void work_queue_run(struct thread *);
extern void workqueue_cmd_init(void);
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c
index 85aa003db7..bee76c6e0f 100644
--- a/lib/yang_wrappers.c
+++ b/lib/yang_wrappers.c
@@ -19,6 +19,7 @@
#include <zebra.h>
+#include "base64.h"
#include "log.h"
#include "lib_errors.h"
#include "northbound.h"
@@ -677,6 +678,64 @@ void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt,
}
/*
+ * Primitive type: binary.
+ */
+struct yang_data *yang_data_new_binary(const char *xpath, const char *value,
+ size_t len)
+{
+ char *value_str;
+ struct base64_encodestate s;
+ int cnt;
+ char *c;
+ struct yang_data *data;
+
+ value_str = (char *)malloc(len * 2);
+ base64_init_encodestate(&s);
+ cnt = base64_encode_block(value, len, value_str, &s);
+ c = value_str + cnt;
+ cnt = base64_encode_blockend(c, &s);
+ c += cnt;
+ *c = 0;
+ data = yang_data_new(xpath, value_str);
+ free(value_str);
+ return data;
+}
+
+size_t yang_dnode_get_binary_buf(char *buf, size_t size,
+ const struct lyd_node *dnode,
+ const char *xpath_fmt, ...)
+{
+ const char *canon;
+ size_t cannon_len;
+ size_t decode_len;
+ size_t ret_len;
+ size_t cnt;
+ char *value_str;
+ struct base64_decodestate s;
+
+ canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt);
+ cannon_len = strlen(canon);
+ decode_len = cannon_len;
+ value_str = (char *)malloc(decode_len);
+ base64_init_decodestate(&s);
+ cnt = base64_decode_block(canon, cannon_len, value_str, &s);
+
+ ret_len = size > cnt ? cnt : size;
+ memcpy(buf, value_str, ret_len);
+ if (size < cnt) {
+ char xpath[XPATH_MAXLEN];
+
+ yang_dnode_get_path(dnode, xpath, sizeof(xpath));
+ flog_warn(EC_LIB_YANG_DATA_TRUNCATED,
+ "%s: value was truncated [xpath %s]", __func__,
+ xpath);
+ }
+ free(value_str);
+ return ret_len;
+}
+
+
+/*
* Primitive type: empty.
*/
struct yang_data *yang_data_new_empty(const char *xpath)
diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h
index d781dfb1e4..56b314876f 100644
--- a/lib/yang_wrappers.h
+++ b/lib/yang_wrappers.h
@@ -118,6 +118,13 @@ extern const char *yang_get_default_string(const char *xpath_fmt, ...);
extern void yang_get_default_string_buf(char *buf, size_t size,
const char *xpath_fmt, ...);
+/* binary */
+extern struct yang_data *yang_data_new_binary(const char *xpath,
+ const char *value, size_t len);
+extern size_t yang_dnode_get_binary_buf(char *buf, size_t size,
+ const struct lyd_node *dnode,
+ const char *xpath_fmt, ...);
+
/* empty */
extern struct yang_data *yang_data_new_empty(const char *xpath);
extern bool yang_dnode_get_empty(const struct lyd_node *dnode,
diff --git a/lib/zclient.c b/lib/zclient.c
index ab2dd09896..930adf6a7a 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -47,10 +47,10 @@ DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient");
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs");
/* Zebra client events. */
-enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
+enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
/* Prototype for event manager. */
-static void zclient_event(enum event, struct zclient *);
+static void zclient_event(enum zclient_event, struct zclient *);
static void zebra_interface_if_set_value(struct stream *s,
struct interface *ifp);
@@ -263,20 +263,21 @@ static enum zclient_send_status zclient_failed(struct zclient *zclient)
return ZCLIENT_SEND_FAILURE;
}
-static int zclient_flush_data(struct thread *thread)
+static void zclient_flush_data(struct thread *thread)
{
struct zclient *zclient = THREAD_ARG(thread);
zclient->t_write = NULL;
if (zclient->sock < 0)
- return -1;
+ return;
switch (buffer_flush_available(zclient->wb, zclient->sock)) {
case BUFFER_ERROR:
flog_err(
EC_LIB_ZAPI_SOCKET,
"%s: buffer_flush_available failed on zclient fd %d, closing",
__func__, zclient->sock);
- return zclient_failed(zclient);
+ zclient_failed(zclient);
+ return;
case BUFFER_PENDING:
zclient->t_write = NULL;
thread_add_write(zclient->master, zclient_flush_data, zclient,
@@ -287,7 +288,6 @@ static int zclient_flush_data(struct thread *thread)
(*zclient->zebra_buffer_write_ready)();
break;
}
- return 0;
}
/*
@@ -754,7 +754,7 @@ void zclient_init(struct zclient *zclient, int redist_default,
/* This function is a wrapper function for calling zclient_start from
timer or event thread. */
-static int zclient_connect(struct thread *t)
+static void zclient_connect(struct thread *t)
{
struct zclient *zclient;
@@ -764,7 +764,7 @@ static int zclient_connect(struct thread *t)
if (zclient_debug)
zlog_debug("zclient_connect is called");
- return zclient_start(zclient);
+ zclient_start(zclient);
}
enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command,
@@ -3864,7 +3864,7 @@ static zclient_handler *const lib_handlers[] = {
};
/* Zebra client message read function. */
-static int zclient_read(struct thread *thread)
+static void zclient_read(struct thread *thread)
{
size_t already;
uint16_t length, command;
@@ -3888,11 +3888,12 @@ static int zclient_read(struct thread *thread)
zlog_debug(
"zclient connection closed socket [%d].",
zclient->sock);
- return zclient_failed(zclient);
+ zclient_failed(zclient);
+ return;
}
if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) {
zclient_event(ZCLIENT_READ, zclient);
- return 0;
+ return;
}
already = ZEBRA_HEADER_SIZE;
}
@@ -3912,14 +3913,16 @@ static int zclient_read(struct thread *thread)
EC_LIB_ZAPI_MISSMATCH,
"%s: socket %d version mismatch, marker %d, version %d",
__func__, zclient->sock, marker, version);
- return zclient_failed(zclient);
+ zclient_failed(zclient);
+ return;
}
if (length < ZEBRA_HEADER_SIZE) {
flog_err(EC_LIB_ZAPI_MISSMATCH,
"%s: socket %d message length %u is less than %d ",
__func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
- return zclient_failed(zclient);
+ zclient_failed(zclient);
+ return;
}
/* Length check. */
@@ -3947,12 +3950,13 @@ static int zclient_read(struct thread *thread)
zlog_debug(
"zclient connection closed socket [%d].",
zclient->sock);
- return zclient_failed(zclient);
+ zclient_failed(zclient);
+ return;
}
if (nbyte != (ssize_t)(length - already)) {
/* Try again later. */
zclient_event(ZCLIENT_READ, zclient);
- return 0;
+ return;
}
}
@@ -3969,13 +3973,11 @@ static int zclient_read(struct thread *thread)
if (zclient->sock < 0)
/* Connection was closed during packet processing. */
- return -1;
+ return;
/* Register read thread. */
stream_reset(zclient->ibuf);
zclient_event(ZCLIENT_READ, zclient);
-
- return 0;
}
void zclient_redistribute(int command, struct zclient *zclient, afi_t afi,
@@ -4036,7 +4038,7 @@ void zclient_redistribute_default(int command, struct zclient *zclient,
zebra_redistribute_default_send(command, zclient, afi, vrf_id);
}
-static void zclient_event(enum event event, struct zclient *zclient)
+static void zclient_event(enum zclient_event event, struct zclient *zclient)
{
switch (event) {
case ZCLIENT_SCHEDULE:
diff --git a/lib/zlog.c b/lib/zlog.c
index 1b0751559d..85606d2624 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -908,6 +908,11 @@ size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out, uint32_t flags)
return bputs(out, msg->ts_3164_str);
}
+void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts)
+{
+ memcpy(ts, &msg->ts, sizeof(*ts));
+}
+
void zlog_set_prefix_ec(bool enable)
{
atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed);
diff --git a/lib/zlog.h b/lib/zlog.h
index 6e84fe8923..a530c589a8 100644
--- a/lib/zlog.h
+++ b/lib/zlog.h
@@ -183,8 +183,11 @@ extern void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen,
/* default is local time zone */
#define ZLOG_TS_UTC (1 << 10)
+struct timespec;
+
extern size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out,
uint32_t flags);
+extern void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts);
/* "mmm dd hh:mm:ss" for RFC3164 syslog. Only ZLOG_TS_UTC for flags. */
extern size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out,
diff --git a/lib/zlog_5424.c b/lib/zlog_5424.c
index 740d6bfba8..9da7c55fc5 100644
--- a/lib/zlog_5424.c
+++ b/lib/zlog_5424.c
@@ -799,7 +799,7 @@ static void zlog_5424_cycle(struct zlog_cfg_5424 *zcf, int fd)
rcu_free(MTYPE_LOG_5424, oldt, zt.rcu_head);
}
-static int zlog_5424_reconnect(struct thread *t)
+static void zlog_5424_reconnect(struct thread *t)
{
struct zlog_cfg_5424 *zcf = THREAD_ARG(t);
int fd = THREAD_FD(t);
@@ -812,7 +812,7 @@ static int zlog_5424_reconnect(struct thread *t)
/* logger is sending us something?!?! */
thread_add_read(t->master, zlog_5424_reconnect, zcf, fd,
&zcf->t_reconnect);
- return 0;
+ return;
}
if (ret == 0)
@@ -832,7 +832,6 @@ static int zlog_5424_reconnect(struct thread *t)
frr_with_mutex (&zcf->cfg_mtx) {
zlog_5424_cycle(zcf, fd);
}
- return 0;
}
static int zlog_5424_unix(struct sockaddr_un *suna, int sock_type)
diff --git a/lib/zlog_live.c b/lib/zlog_live.c
new file mode 100644
index 0000000000..fbe0e5ee49
--- /dev/null
+++ b/lib/zlog_live.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2019-22 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "zebra.h"
+
+#include "zlog_live.h"
+
+#include "memory.h"
+#include "frrcu.h"
+#include "zlog.h"
+#include "printfrr.h"
+
+DEFINE_MTYPE_STATIC(LOG, LOG_LIVE, "log vtysh live target");
+
+enum {
+ STATE_NORMAL = 0,
+ STATE_FD_DEAD,
+ STATE_DISOWNED,
+};
+
+struct zlt_live {
+ struct zlog_target zt;
+
+ atomic_uint_fast32_t fd;
+ struct rcu_head_close head_close;
+ struct rcu_head head_self;
+
+ atomic_uint_fast32_t state;
+};
+
+static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[],
+ size_t nmsgs)
+{
+ struct zlt_live *zte = container_of(zt, struct zlt_live, zt);
+ struct zlog_live_hdr hdrs[nmsgs], *hdr = hdrs;
+ struct mmsghdr mmhs[nmsgs], *mmh = mmhs;
+ struct iovec iovs[nmsgs * 3], *iov = iovs;
+ struct timespec ts;
+ size_t i, textlen;
+ int fd;
+ uint_fast32_t state;
+
+ fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
+
+ if (fd < 0)
+ return;
+
+ memset(mmhs, 0, sizeof(mmhs));
+ memset(hdrs, 0, sizeof(hdrs));
+
+ for (i = 0; i < nmsgs; i++) {
+ const struct fmt_outpos *argpos;
+ size_t n_argpos, arghdrlen;
+ struct zlog_msg *msg = msgs[i];
+ int prio = zlog_msg_prio(msg);
+
+ if (prio > zt->prio_min)
+ continue;
+
+ zlog_msg_args(msg, &arghdrlen, &n_argpos, &argpos);
+
+ mmh->msg_hdr.msg_iov = iov;
+
+ iov->iov_base = hdr;
+ iov->iov_len = sizeof(*hdr);
+ iov++;
+
+ if (n_argpos) {
+ iov->iov_base = (char *)argpos;
+ iov->iov_len = sizeof(*argpos) * n_argpos;
+ iov++;
+ }
+
+ iov->iov_base = (char *)zlog_msg_text(msg, &textlen);
+ iov->iov_len = textlen;
+ iov++;
+
+ zlog_msg_tsraw(msg, &ts);
+
+ hdr->ts_sec = ts.tv_sec;
+ hdr->ts_nsec = ts.tv_nsec;
+ hdr->prio = zlog_msg_prio(msg);
+ hdr->flags = 0;
+ hdr->textlen = textlen;
+ hdr->arghdrlen = arghdrlen;
+ hdr->n_argpos = n_argpos;
+
+ mmh->msg_hdr.msg_iovlen = iov - mmh->msg_hdr.msg_iov;
+ mmh++;
+ hdr++;
+ }
+
+ size_t msgtotal = mmh - mmhs;
+ ssize_t sent;
+
+ for (size_t msgpos = 0; msgpos < msgtotal; msgpos += sent) {
+ sent = sendmmsg(fd, mmhs + msgpos, msgtotal - msgpos, 0);
+
+ if (sent <= 0)
+ goto out_err;
+ }
+ return;
+
+out_err:
+ fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed);
+ if (fd < 0)
+ return;
+
+ rcu_close(&zte->head_close, fd);
+ zlog_target_replace(zt, NULL);
+
+ state = STATE_NORMAL;
+ atomic_compare_exchange_strong_explicit(
+ &zte->state, &state, STATE_FD_DEAD, memory_order_relaxed,
+ memory_order_relaxed);
+ if (state == STATE_DISOWNED)
+ rcu_free(MTYPE_LOG_LIVE, zte, head_self);
+}
+
+static void zlog_live_sigsafe(struct zlog_target *zt, const char *text,
+ size_t len)
+{
+ struct zlt_live *zte = container_of(zt, struct zlt_live, zt);
+ struct zlog_live_hdr hdr[1];
+ struct iovec iovs[2], *iov = iovs;
+ struct timespec ts;
+ int fd;
+
+ fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
+ if (fd < 0)
+ return;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ hdr->ts_sec = ts.tv_sec;
+ hdr->ts_nsec = ts.tv_nsec;
+ hdr->prio = LOG_CRIT;
+ hdr->flags = 0;
+ hdr->textlen = len;
+ hdr->n_argpos = 0;
+
+ iov->iov_base = (char *)hdr;
+ iov->iov_len = sizeof(hdr);
+ iov++;
+
+ iov->iov_base = (char *)text;
+ iov->iov_len = len;
+ iov++;
+
+ writev(fd, iovs, iov - iovs);
+}
+
+void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min, int *other_fd)
+{
+ int sockets[2];
+ struct zlt_live *zte;
+ struct zlog_target *zt;
+
+ if (cfg->target)
+ zlog_live_close(cfg);
+
+ *other_fd = -1;
+ if (prio_min == ZLOG_DISABLED)
+ return;
+
+ /* the only reason for SEQPACKET here is getting close notifications.
+ * otherwise if you open a bunch of vtysh connections with live logs
+ * and close them all, the fds will stick around until we get an error
+ * when trying to log something to them at some later point -- which
+ * eats up fds and might be *much* later for some daemons.
+ */
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) < 0) {
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {
+ zlog_warn("%% could not open socket pair: %m");
+ return;
+ }
+ } else
+ /* SEQPACKET only: try to zap read direction */
+ shutdown(sockets[0], SHUT_RD);
+
+ *other_fd = sockets[1];
+
+ zt = zlog_target_clone(MTYPE_LOG_LIVE, NULL, sizeof(*zte));
+ zte = container_of(zt, struct zlt_live, zt);
+ cfg->target = zte;
+
+ zte->fd = sockets[0];
+ zte->zt.prio_min = prio_min;
+ zte->zt.logfn = zlog_live;
+ zte->zt.logfn_sigsafe = zlog_live_sigsafe;
+
+ zlog_target_replace(NULL, zt);
+}
+
+void zlog_live_close(struct zlog_live_cfg *cfg)
+{
+ struct zlt_live *zte;
+ int fd;
+
+ if (!cfg->target)
+ return;
+
+ zte = cfg->target;
+ cfg->target = NULL;
+
+ fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed);
+
+ if (fd >= 0) {
+ rcu_close(&zte->head_close, fd);
+ zlog_target_replace(&zte->zt, NULL);
+ }
+ rcu_free(MTYPE_LOG_LIVE, zte, head_self);
+}
+
+void zlog_live_disown(struct zlog_live_cfg *cfg)
+{
+ struct zlt_live *zte;
+ uint_fast32_t state;
+
+ if (!cfg->target)
+ return;
+
+ zte = cfg->target;
+ cfg->target = NULL;
+
+ state = STATE_NORMAL;
+ atomic_compare_exchange_strong_explicit(
+ &zte->state, &state, STATE_DISOWNED, memory_order_relaxed,
+ memory_order_relaxed);
+ if (state == STATE_FD_DEAD)
+ rcu_free(MTYPE_LOG_LIVE, zte, head_self);
+}
diff --git a/lib/zlog_live.h b/lib/zlog_live.h
new file mode 100644
index 0000000000..c948baeab1
--- /dev/null
+++ b/lib/zlog_live.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019-22 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRR_ZLOG_LIVE_H
+#define _FRR_ZLOG_LIVE_H
+
+#include "printfrr.h"
+
+struct zlog_live_hdr {
+ uint64_t ts_sec;
+ uint32_t ts_nsec;
+ uint32_t prio;
+ uint32_t flags;
+ uint32_t textlen;
+
+ uint32_t arghdrlen;
+ uint32_t n_argpos;
+ struct fmt_outpos argpos[0];
+};
+
+struct zlt_live;
+
+struct zlog_live_cfg {
+ struct zlt_live *target;
+
+ /* nothing else here */
+};
+
+extern void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min,
+ int *other_fd);
+
+static inline bool zlog_live_is_null(struct zlog_live_cfg *cfg)
+{
+ return cfg->target == NULL;
+}
+
+extern void zlog_live_close(struct zlog_live_cfg *cfg);
+extern void zlog_live_disown(struct zlog_live_cfg *cfg);
+
+#endif /* _FRR_ZLOG_5424_H */