Skip to content

Commit

Permalink
lib: allow recirculating/relaying log messages
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
eqvinox committed Mar 10, 2024
1 parent aa6ceee commit 5f16c64
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/subdir.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down
97 changes: 97 additions & 0 deletions lib/zlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "printfrr.h"
#include "frrcu.h"
#include "zlog.h"
#include "zlog_live.h"
#include "libfrr_trace.h"
#include "frrevent.h"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions lib/zlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
56 changes: 56 additions & 0 deletions lib/zlog_recirculate.c
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions lib/zlog_recirculate.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 5f16c64

Please sign in to comment.