]> git.proxmox.com Git - mirror_frr.git/blame - lib/zlog_live.c
lib: add a few more bits to live log header
[mirror_frr.git] / lib / zlog_live.c
CommitLineData
0798d276
DL
1/*
2 * Copyright (c) 2019-22 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "zebra.h"
18
19#include "zlog_live.h"
20
21#include "memory.h"
22#include "frrcu.h"
23#include "zlog.h"
24#include "printfrr.h"
2eda953a 25#include "network.h"
0798d276
DL
26
27DEFINE_MTYPE_STATIC(LOG, LOG_LIVE, "log vtysh live target");
28
29enum {
30 STATE_NORMAL = 0,
31 STATE_FD_DEAD,
32 STATE_DISOWNED,
33};
34
35struct zlt_live {
36 struct zlog_target zt;
37
38 atomic_uint_fast32_t fd;
39 struct rcu_head_close head_close;
40 struct rcu_head head_self;
41
42 atomic_uint_fast32_t state;
43};
44
45static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[],
46 size_t nmsgs)
47{
48 struct zlt_live *zte = container_of(zt, struct zlt_live, zt);
49 struct zlog_live_hdr hdrs[nmsgs], *hdr = hdrs;
50 struct mmsghdr mmhs[nmsgs], *mmh = mmhs;
51 struct iovec iovs[nmsgs * 3], *iov = iovs;
52 struct timespec ts;
53 size_t i, textlen;
54 int fd;
55 uint_fast32_t state;
56
57 fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
58
59 if (fd < 0)
60 return;
61
62 memset(mmhs, 0, sizeof(mmhs));
63 memset(hdrs, 0, sizeof(hdrs));
64
65 for (i = 0; i < nmsgs; i++) {
66 const struct fmt_outpos *argpos;
834585bd 67 size_t n_argpos, texthdrlen;
0798d276
DL
68 struct zlog_msg *msg = msgs[i];
69 int prio = zlog_msg_prio(msg);
834585bd
DL
70 const struct xref_logmsg *xref;
71 intmax_t pid, tid;
0798d276
DL
72
73 if (prio > zt->prio_min)
74 continue;
75
834585bd 76 zlog_msg_args(msg, &texthdrlen, &n_argpos, &argpos);
0798d276
DL
77
78 mmh->msg_hdr.msg_iov = iov;
79
80 iov->iov_base = hdr;
81 iov->iov_len = sizeof(*hdr);
82 iov++;
83
84 if (n_argpos) {
85 iov->iov_base = (char *)argpos;
86 iov->iov_len = sizeof(*argpos) * n_argpos;
87 iov++;
88 }
89
90 iov->iov_base = (char *)zlog_msg_text(msg, &textlen);
91 iov->iov_len = textlen;
92 iov++;
93
94 zlog_msg_tsraw(msg, &ts);
834585bd
DL
95 zlog_msg_pid(msg, &pid, &tid);
96 xref = zlog_msg_xref(msg);
0798d276
DL
97
98 hdr->ts_sec = ts.tv_sec;
99 hdr->ts_nsec = ts.tv_nsec;
834585bd
DL
100 hdr->pid = pid;
101 hdr->tid = tid;
102 hdr->prio = prio;
0798d276
DL
103 hdr->flags = 0;
104 hdr->textlen = textlen;
834585bd 105 hdr->texthdrlen = texthdrlen;
0798d276 106 hdr->n_argpos = n_argpos;
834585bd
DL
107 if (xref) {
108 memcpy(hdr->uid, xref->xref.xrefdata->uid,
109 sizeof(hdr->uid));
110 hdr->ec = xref->ec;
111 } else {
112 memset(hdr->uid, 0, sizeof(hdr->uid));
113 hdr->ec = 0;
114 }
115 hdr->hdrlen = sizeof(*hdr) + sizeof(*argpos) * n_argpos;
0798d276
DL
116
117 mmh->msg_hdr.msg_iovlen = iov - mmh->msg_hdr.msg_iov;
118 mmh++;
119 hdr++;
120 }
121
122 size_t msgtotal = mmh - mmhs;
123 ssize_t sent;
124
125 for (size_t msgpos = 0; msgpos < msgtotal; msgpos += sent) {
126 sent = sendmmsg(fd, mmhs + msgpos, msgtotal - msgpos, 0);
127
2eda953a
DL
128 if (sent <= 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
129 break;
0798d276
DL
130 if (sent <= 0)
131 goto out_err;
132 }
133 return;
134
135out_err:
136 fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed);
137 if (fd < 0)
138 return;
139
140 rcu_close(&zte->head_close, fd);
141 zlog_target_replace(zt, NULL);
142
143 state = STATE_NORMAL;
144 atomic_compare_exchange_strong_explicit(
145 &zte->state, &state, STATE_FD_DEAD, memory_order_relaxed,
146 memory_order_relaxed);
147 if (state == STATE_DISOWNED)
148 rcu_free(MTYPE_LOG_LIVE, zte, head_self);
149}
150
151static void zlog_live_sigsafe(struct zlog_target *zt, const char *text,
152 size_t len)
153{
154 struct zlt_live *zte = container_of(zt, struct zlt_live, zt);
1609a9d6 155 struct zlog_live_hdr hdr[1] = {};
0798d276
DL
156 struct iovec iovs[2], *iov = iovs;
157 struct timespec ts;
158 int fd;
159
160 fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
161 if (fd < 0)
162 return;
163
1609a9d6 164 clock_gettime(CLOCK_REALTIME, &ts);
0798d276
DL
165
166 hdr->ts_sec = ts.tv_sec;
167 hdr->ts_nsec = ts.tv_nsec;
168 hdr->prio = LOG_CRIT;
0798d276 169 hdr->textlen = len;
0798d276
DL
170
171 iov->iov_base = (char *)hdr;
172 iov->iov_len = sizeof(hdr);
173 iov++;
174
175 iov->iov_base = (char *)text;
176 iov->iov_len = len;
177 iov++;
178
179 writev(fd, iovs, iov - iovs);
180}
181
182void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min, int *other_fd)
183{
184 int sockets[2];
185 struct zlt_live *zte;
186 struct zlog_target *zt;
187
188 if (cfg->target)
189 zlog_live_close(cfg);
190
191 *other_fd = -1;
192 if (prio_min == ZLOG_DISABLED)
193 return;
194
195 /* the only reason for SEQPACKET here is getting close notifications.
196 * otherwise if you open a bunch of vtysh connections with live logs
197 * and close them all, the fds will stick around until we get an error
198 * when trying to log something to them at some later point -- which
199 * eats up fds and might be *much* later for some daemons.
200 */
201 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) < 0) {
202 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {
203 zlog_warn("%% could not open socket pair: %m");
204 return;
205 }
206 } else
207 /* SEQPACKET only: try to zap read direction */
208 shutdown(sockets[0], SHUT_RD);
209
210 *other_fd = sockets[1];
211
212 zt = zlog_target_clone(MTYPE_LOG_LIVE, NULL, sizeof(*zte));
213 zte = container_of(zt, struct zlt_live, zt);
214 cfg->target = zte;
215
2eda953a 216 set_nonblocking(sockets[0]);
0798d276
DL
217 zte->fd = sockets[0];
218 zte->zt.prio_min = prio_min;
219 zte->zt.logfn = zlog_live;
220 zte->zt.logfn_sigsafe = zlog_live_sigsafe;
221
222 zlog_target_replace(NULL, zt);
223}
224
225void zlog_live_close(struct zlog_live_cfg *cfg)
226{
227 struct zlt_live *zte;
228 int fd;
229
230 if (!cfg->target)
231 return;
232
233 zte = cfg->target;
234 cfg->target = NULL;
235
236 fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed);
237
238 if (fd >= 0) {
239 rcu_close(&zte->head_close, fd);
240 zlog_target_replace(&zte->zt, NULL);
241 }
242 rcu_free(MTYPE_LOG_LIVE, zte, head_self);
243}
244
245void zlog_live_disown(struct zlog_live_cfg *cfg)
246{
247 struct zlt_live *zte;
248 uint_fast32_t state;
249
250 if (!cfg->target)
251 return;
252
253 zte = cfg->target;
254 cfg->target = NULL;
255
256 state = STATE_NORMAL;
257 atomic_compare_exchange_strong_explicit(
258 &zte->state, &state, STATE_DISOWNED, memory_order_relaxed,
259 memory_order_relaxed);
260 if (state == STATE_FD_DEAD)
261 rcu_free(MTYPE_LOG_LIVE, zte, head_self);
262}