forked from Mirror/frr
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>
This commit is contained in:
parent
aa6ceeeb5b
commit
5f16c640c2
|
@ -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 \
|
||||
|
|
97
lib/zlog.c
97
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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
56
lib/zlog_recirculate.c
Normal file
56
lib/zlog_recirculate.c
Normal file
|
@ -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);
|
||||
}
|
12
lib/zlog_recirculate.h
Normal file
12
lib/zlog_recirculate.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue