summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2024-01-25 22:11:44 +0100
committerDavid Lamparter <equinox@opensourcerouting.org>2024-03-10 12:42:02 +0100
commit5f16c640c248bba898addb3ff36b84d212f6e8e6 (patch)
tree97ba2b439fdf292edefd36e1e6eec0bca21bea25
parentaa6ceeeb5b1f92280ee79716e68d31c9a8686230 (diff)
lib: allow recirculating/relaying log messages
This is primarily intended for ldpd with its split-process architecture. The LDE/LDPE subprocesses currently lose the extended zlog functionality. The zlog_live target already encapsulates all necessary bits for vtysh. Reuse it for a relay function to be used in the main ldpd process. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
-rw-r--r--lib/subdir.am2
-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
5 files changed, 170 insertions, 0 deletions
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/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