diff options
| author | David Lamparter <equinox@opensourcerouting.org> | 2024-01-25 22:11:44 +0100 | 
|---|---|---|
| committer | David Lamparter <equinox@opensourcerouting.org> | 2024-03-10 12:42:02 +0100 | 
| commit | 5f16c640c248bba898addb3ff36b84d212f6e8e6 (patch) | |
| tree | 97ba2b439fdf292edefd36e1e6eec0bca21bea25 | |
| parent | aa6ceeeb5b1f92280ee79716e68d31c9a8686230 (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.am | 2 | ||||
| -rw-r--r-- | lib/zlog.c | 97 | ||||
| -rw-r--r-- | lib/zlog.h | 3 | ||||
| -rw-r--r-- | lib/zlog_recirculate.c | 56 | ||||
| -rw-r--r-- | lib/zlog_recirculate.h | 12 | 
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  | 
