]> git.proxmox.com Git - mirror_frr.git/blob - lib/zlog_5424.c
Merge pull request #10987 from opensourcerouting/fix/bgp_conditional_advertisements_r...
[mirror_frr.git] / lib / zlog_5424.c
1 /*
2 * Copyright (c) 2015-21 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 /* when you work on this code, please install a fuzzer (e.g. AFL) and run
18 * tests/lib/fuzz_zlog.c
19 *
20 * The most likely type of bug in this code is an off-by-one error in the
21 * buffer management pieces, and this isn't easily covered by an unit test
22 * or topotests. Fuzzing is the best tool here, but the CI can't do that
23 * since it's quite resource intensive.
24 */
25
26 #include "zebra.h"
27
28 #include "zlog_5424.h"
29
30 #include <sys/un.h>
31 #include <syslog.h>
32
33 #include "memory.h"
34 #include "frrcu.h"
35 #include "printfrr.h"
36 #include "typerb.h"
37 #include "frr_pthread.h"
38 #include "command.h"
39 #include "monotime.h"
40 #include "thread.h"
41
42 #include "lib/version.h"
43 #include "lib/lib_errors.h"
44
45 DEFINE_MTYPE_STATIC(LOG, LOG_5424, "extended log target");
46 DEFINE_MTYPE_STATIC(LOG, LOG_5424_ROTATE, "extended log rotate helper");
47
48 /* the actual log target data structure
49 *
50 * remember this is RCU'd by the core zlog functions. Changing anything
51 * works by allocating a new struct, filling it, adding it, and removing the
52 * old one.
53 */
54 struct zlt_5424 {
55 struct zlog_target zt;
56
57 atomic_uint_fast32_t fd;
58
59 enum zlog_5424_format fmt;
60 uint32_t ts_flags;
61 int facility;
62
63 /* the various extra pieces to add... */
64 bool kw_version : 1;
65 bool kw_location : 1;
66 bool kw_uid : 1;
67 bool kw_ec : 1;
68 bool kw_args : 1;
69
70 /* some formats may or may not include the trailing \n */
71 bool use_nl : 1;
72
73 /* for DGRAM & SEQPACKET sockets, send 1 log message per packet, since
74 * the socket preserves packet boundaries. On Linux, this uses
75 * sendmmsg() for efficiency, on other systems we need a syscall each.
76 */
77 bool packets : 1;
78
79 /* for DGRAM, in order to not have to reconnect, we need to use
80 * sendto()/sendmsg() with the destination given; otherwise we'll get
81 * ENOTCONN. (We do a connect(), which serves to verify the type of
82 * socket, but if the receiver goes away, the kernel disconnects the
83 * socket so writev() no longer works since the destination is now
84 * unspecified.)
85 */
86 struct sockaddr_storage sa;
87 socklen_t sa_len;
88
89 /* these are both getting set, but current_err is cleared on success,
90 * so we know whether the error is current or past.
91 */
92 int last_err, current_err;
93 atomic_size_t lost_msgs;
94 struct timeval last_err_ts;
95
96 struct rcu_head_close head_close;
97 };
98
99 static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type);
100
101 /* rough header length estimate
102 * ============================
103 *
104 * ^ = might grow
105 *
106 * 49^ longest filename (pceplib/test/pcep_utils_double_linked_list_test.h)
107 * 5^ highest line number (48530, bgpd/bgp_nb_config.c)
108 * 65^ longest function name
109 * (lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy)
110 * 11 unique id ("XXXXX-XXXXX")
111 * 10 EC ("4294967295" or "0xffffffff")
112 * 35 ISO8601 TS at full length ("YYYY-MM-DD HH:MM:SS.NNNNNNNNN+ZZ:ZZ")
113 * ---
114 * 175
115 *
116 * rarely used (hopefully...):
117 * 26^ FRR_VERSION ("10.10.10-dev-gffffffffffff")
118 * ---
119 * 201
120 *
121 * x16 highest number of format parameters currently
122 * 40 estimate for hostname + 2*daemon + pid
123 *
124 * specific format overhead:
125 *
126 * RFC3164 - shorter than the others
127 * RFC5424 - 175 + "<999>1 "=7 + 52 (location@50145) + 40 (host/...)
128 * rarely: + 65 + 26 (for [origin])
129 * args: 16 * (8 + per-arg (20?)) = ~448
130 *
131 * so without "args@", origin or (future) keywords, around 256 seems OK
132 * with args@ and/or origin and/or keywords, 512 seems more reasonable
133 *
134 * but - note the code allocates this amount multiplied by the number of
135 * messages in the incoming batch (minimum 3), this means short messages and
136 * long messages smooth each other out.
137 *
138 * Since the code handles space-exceeded by grabbing a bunch of stack memory,
139 * a reasonable middle ground estimate is desirable here, so ...
140 * *drumroll*
141 * let's go with 128 + args?128. (remember the minimum 3 multiplier)
142 *
143 * low_space is the point where we don't try to fit another message in & just
144 * submit what we have to the kernel.
145 *
146 * The zlog code only buffers debug & informational messages, so in production
147 * usage most of the calls will be writing out only 1 message. This makes
148 * the min *3 multiplier quite useful.
149 */
150
151 static inline size_t zlog_5424_bufsz(struct zlt_5424 *zte, size_t nmsgs,
152 size_t *low_space)
153 {
154 size_t ret = 128;
155
156 if (zte->kw_args)
157 ret += 128;
158 *low_space = ret;
159 return ret * MAX(nmsgs, 3);
160 }
161
162 struct state {
163 struct fbuf *fbuf;
164 struct iovec *iov;
165 };
166
167 /* stack-based keyword support is likely to bump this to 3 or 4 */
168 #define IOV_PER_MSG 2
169 _Static_assert(IOV_MAX >= IOV_PER_MSG,
170 "this code won't work with IOV_MAX < IOV_PER_MSG");
171
172 /* the following functions are quite similar, but trying to merge them just
173 * makes a big mess. check the others when touching one.
174 *
175 * timestamp keywords hostname
176 * RFC5424 ISO8601 yes yes
177 * RFC3164 RFC3164 no yes
178 * local RFC3164 no no
179 * journald ISO8601(unused) yes (unused)
180 */
181
182 static size_t zlog_5424_one(struct zlt_5424 *zte, struct zlog_msg *msg,
183 struct state *state)
184 {
185 size_t textlen;
186 struct fbuf *fbuf = state->fbuf;
187 char *orig_pos = fbuf->pos;
188 size_t need = 0;
189 int prio = zlog_msg_prio(msg);
190 intmax_t pid, tid;
191
192 zlog_msg_pid(msg, &pid, &tid);
193
194 need += bprintfrr(fbuf, "<%d>1 ", prio | zte->facility);
195 need += zlog_msg_ts(msg, fbuf, zte->ts_flags);
196 need += bprintfrr(fbuf, " %s %s %jd %.*s ", cmd_hostname_get() ?: "-",
197 zlog_progname, pid, (int)(zlog_prefixsz - 2),
198 zlog_prefix);
199
200 if (zte->kw_version)
201 need += bprintfrr(
202 fbuf,
203 "[origin enterpriseId=\"50145\" software=\"FRRouting\" swVersion=\"%s\"]",
204 FRR_VERSION);
205
206 const struct xref_logmsg *xref;
207 struct xrefdata *xrefdata;
208
209 need += bprintfrr(fbuf, "[location@50145 tid=\"%jd\"", tid);
210 if (zlog_instance > 0)
211 need += bprintfrr(fbuf, " instance=\"%d\"", zlog_instance);
212
213 xref = zlog_msg_xref(msg);
214 xrefdata = xref ? xref->xref.xrefdata : NULL;
215 if (xrefdata) {
216 if (zte->kw_uid)
217 need += bprintfrr(fbuf, " id=\"%s\"", xrefdata->uid);
218 if (zte->kw_ec && prio <= LOG_WARNING)
219 need += bprintfrr(fbuf, " ec=\"%u\"", xref->ec);
220 if (zte->kw_location)
221 need += bprintfrr(
222 fbuf, " file=\"%s\" line=\"%d\" func=\"%s\"",
223 xref->xref.file, xref->xref.line,
224 xref->xref.func);
225 }
226 need += bputch(fbuf, ']');
227
228 size_t hdrlen, n_argpos;
229 const struct fmt_outpos *argpos;
230 const char *text;
231
232 text = zlog_msg_text(msg, &textlen);
233 zlog_msg_args(msg, &hdrlen, &n_argpos, &argpos);
234
235 if (zte->kw_args && n_argpos) {
236 need += bputs(fbuf, "[args@50145");
237
238 for (size_t i = 0; i < n_argpos; i++) {
239 int len = argpos[i].off_end - argpos[i].off_start;
240
241 need += bprintfrr(fbuf, " arg%zu=%*pSQsq", i + 1, len,
242 text + argpos[i].off_start);
243 }
244
245 need += bputch(fbuf, ']');
246 }
247
248 need += bputch(fbuf, ' ');
249
250 if (orig_pos + need > fbuf->buf + fbuf->len) {
251 /* not enough space in the buffer for headers. the loop in
252 * zlog_5424() will flush other messages that are already in
253 * the buffer, grab a bigger buffer if needed, and try again.
254 */
255 fbuf->pos = orig_pos;
256 return need;
257 }
258
259 /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
260 state->iov->iov_base = orig_pos;
261 state->iov->iov_len = fbuf->pos - orig_pos;
262 state->iov++;
263
264 state->iov->iov_base = (char *)text + hdrlen;
265 state->iov->iov_len = textlen - hdrlen + zte->use_nl;
266 state->iov++;
267 return 0;
268 }
269
270 static size_t zlog_3164_one(struct zlt_5424 *zte, struct zlog_msg *msg,
271 struct state *state)
272 {
273 size_t textlen;
274 struct fbuf *fbuf = state->fbuf;
275 char *orig_pos = fbuf->pos;
276 size_t need = 0;
277 int prio = zlog_msg_prio(msg);
278 intmax_t pid, tid;
279
280 zlog_msg_pid(msg, &pid, &tid);
281
282 need += bprintfrr(fbuf, "<%d>", prio | zte->facility);
283 need += zlog_msg_ts_3164(msg, fbuf, zte->ts_flags);
284 if (zte->fmt != ZLOG_FMT_LOCAL) {
285 need += bputch(fbuf, ' ');
286 need += bputs(fbuf, cmd_hostname_get() ?: "-");
287 }
288 need += bprintfrr(fbuf, " %s[%jd]: ", zlog_progname, pid);
289
290 if (orig_pos + need > fbuf->buf + fbuf->len) {
291 /* not enough space in the buffer for headers. loop in
292 * zlog_5424() will flush other messages that are already in
293 * the buffer, grab a bigger buffer if needed, and try again.
294 */
295 fbuf->pos = orig_pos;
296 return need;
297 }
298
299 /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
300 state->iov->iov_base = orig_pos;
301 state->iov->iov_len = fbuf->pos - orig_pos;
302 state->iov++;
303
304 state->iov->iov_base = (char *)zlog_msg_text(msg, &textlen);
305 state->iov->iov_len = textlen + zte->use_nl;
306 state->iov++;
307 return 0;
308 }
309
310 static size_t zlog_journald_one(struct zlt_5424 *zte, struct zlog_msg *msg,
311 struct state *state)
312 {
313 size_t textlen;
314 struct fbuf *fbuf = state->fbuf;
315 char *orig_pos = fbuf->pos;
316 size_t need = 0;
317 int prio = zlog_msg_prio(msg);
318 intmax_t pid, tid;
319
320 zlog_msg_pid(msg, &pid, &tid);
321
322 need += bprintfrr(fbuf,
323 "PRIORITY=%d\n"
324 "SYSLOG_FACILITY=%d\n"
325 "TID=%jd\n"
326 "FRR_DAEMON=%s\n"
327 "SYSLOG_TIMESTAMP=",
328 prio, zte->facility, tid, zlog_progname);
329 need += zlog_msg_ts(msg, fbuf, zte->ts_flags);
330 need += bputch(fbuf, '\n');
331 if (zlog_instance > 0)
332 need += bprintfrr(fbuf, "FRR_INSTANCE=%d\n", zlog_instance);
333
334 const struct xref_logmsg *xref;
335 struct xrefdata *xrefdata;
336
337 xref = zlog_msg_xref(msg);
338 xrefdata = xref ? xref->xref.xrefdata : NULL;
339 if (xrefdata) {
340 if (zte->kw_uid && xrefdata->uid[0])
341 need += bprintfrr(fbuf, "FRR_ID=%s\n", xrefdata->uid);
342 if (zte->kw_ec && prio <= LOG_WARNING)
343 need += bprintfrr(fbuf, "FRR_EC=%d\n", xref->ec);
344 if (zte->kw_location)
345 need += bprintfrr(fbuf,
346 "CODE_FILE=%s\n"
347 "CODE_LINE=%d\n"
348 "CODE_FUNC=%s\n",
349 xref->xref.file, xref->xref.line,
350 xref->xref.func);
351 }
352
353 size_t hdrlen, n_argpos;
354 const struct fmt_outpos *argpos;
355 const char *text;
356
357 text = zlog_msg_text(msg, &textlen);
358 zlog_msg_args(msg, &hdrlen, &n_argpos, &argpos);
359
360 if (zte->kw_args && n_argpos) {
361 for (size_t i = 0; i < n_argpos; i++) {
362 int len = argpos[i].off_end - argpos[i].off_start;
363
364 /* rather than escape the value, we could use
365 * journald's binary encoding, but that seems a bit
366 * excessive/unnecessary. 99% of things we print here
367 * will just output 1:1 with %pSE.
368 */
369 need += bprintfrr(fbuf, "FRR_ARG%zu=%*pSE\n", i + 1,
370 len, text + argpos[i].off_start);
371 }
372 }
373
374 need += bputs(fbuf, "MESSAGE=");
375
376 if (orig_pos + need > fbuf->buf + fbuf->len) {
377 /* not enough space in the buffer for headers. loop in
378 * zlog_5424() will flush other messages that are already in
379 * the buffer, grab a bigger buffer if needed, and try again.
380 */
381 fbuf->pos = orig_pos;
382 return need;
383 }
384
385 /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
386 state->iov->iov_base = orig_pos;
387 state->iov->iov_len = fbuf->pos - orig_pos;
388 state->iov++;
389
390 state->iov->iov_base = (char *)text + hdrlen;
391 state->iov->iov_len = textlen - hdrlen + 1;
392 state->iov++;
393 return 0;
394 }
395
396 static size_t zlog_one(struct zlt_5424 *zte, struct zlog_msg *msg,
397 struct state *state)
398 {
399 switch (zte->fmt) {
400 case ZLOG_FMT_5424:
401 return zlog_5424_one(zte, msg, state);
402 case ZLOG_FMT_3164:
403 case ZLOG_FMT_LOCAL:
404 return zlog_3164_one(zte, msg, state);
405 case ZLOG_FMT_JOURNALD:
406 return zlog_journald_one(zte, msg, state);
407 }
408 return 0;
409 }
410
411 static void zlog_5424_err(struct zlt_5424 *zte, size_t count)
412 {
413 if (!count) {
414 zte->current_err = 0;
415 return;
416 }
417
418 /* only the counter is atomic because otherwise it'd be meaningless */
419 atomic_fetch_add_explicit(&zte->lost_msgs, count, memory_order_relaxed);
420
421 /* these are non-atomic and can provide wrong results when read, but
422 * since they're only for debugging / display, that's OK.
423 */
424 zte->current_err = zte->last_err = errno;
425 monotime(&zte->last_err_ts);
426 }
427
428 static void zlog_5424(struct zlog_target *zt, struct zlog_msg *msgs[],
429 size_t nmsgs)
430 {
431 size_t i;
432 struct zlt_5424 *zte = container_of(zt, struct zlt_5424, zt);
433 int fd, ret;
434 size_t niov = MIN(IOV_PER_MSG * nmsgs, IOV_MAX);
435 struct iovec iov[niov], *iov_last = iov + niov;
436 struct mmsghdr mmsg[zte->packets ? nmsgs : 1], *mpos = mmsg;
437 size_t count = 0;
438
439 /* refer to size estimate at top of file */
440 size_t low_space;
441 char hdr_buf[zlog_5424_bufsz(zte, nmsgs, &low_space)];
442 struct fbuf hdr_pos = {
443 .buf = hdr_buf,
444 .pos = hdr_buf,
445 .len = sizeof(hdr_buf),
446 };
447 struct state state = {
448 .fbuf = &hdr_pos,
449 .iov = iov,
450 };
451
452 fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
453
454 memset(mmsg, 0, sizeof(mmsg));
455 if (zte->sa_len) {
456 for (i = 0; i < array_size(mmsg); i++) {
457 mmsg[i].msg_hdr.msg_name = (struct sockaddr *)&zte->sa;
458 mmsg[i].msg_hdr.msg_namelen = zte->sa_len;
459 }
460 }
461 mmsg[0].msg_hdr.msg_iov = iov;
462
463 for (i = 0; i < nmsgs; i++) {
464 int prio = zlog_msg_prio(msgs[i]);
465 size_t need = 0;
466
467 if (prio <= zte->zt.prio_min) {
468 if (zte->packets)
469 mpos->msg_hdr.msg_iov = state.iov;
470
471 need = zlog_one(zte, msgs[i], &state);
472
473 if (zte->packets) {
474 mpos->msg_hdr.msg_iovlen =
475 state.iov - mpos->msg_hdr.msg_iov;
476 mpos++;
477 }
478 count++;
479 }
480
481 /* clang-format off */
482 if ((need
483 || (size_t)(hdr_pos.buf + hdr_pos.len - hdr_pos.pos)
484 < low_space
485 || i + 1 == nmsgs
486 || state.iov + IOV_PER_MSG > iov_last)
487 && state.iov > iov) {
488 /* clang-format on */
489
490 if (zte->packets) {
491 struct mmsghdr *sendpos;
492
493 for (sendpos = mmsg; sendpos < mpos;) {
494 ret = sendmmsg(fd, sendpos,
495 mpos - sendpos, 0);
496 if (ret <= 0)
497 break;
498 sendpos += ret;
499 }
500 zlog_5424_err(zte, mpos - sendpos);
501 mpos = mmsg;
502 } else {
503 if (!zte->sa_len)
504 ret = writev(fd, iov, state.iov - iov);
505 else {
506 mpos->msg_hdr.msg_iovlen =
507 state.iov - iov;
508 ret = sendmsg(fd, &mpos->msg_hdr, 0);
509 }
510
511 if (ret < 0)
512 zlog_5424_err(zte, count);
513 else
514 zlog_5424_err(zte, 0);
515 }
516
517 count = 0;
518 hdr_pos.pos = hdr_buf;
519 state.iov = iov;
520 }
521
522 /* if need == 0, we just put a message (or nothing) in the
523 * buffer and are continuing for more to batch in a single
524 * writev()
525 */
526 if (need == 0)
527 continue;
528
529 if (need && need <= sizeof(hdr_buf)) {
530 /* don't need to allocate, just try this msg
531 * again without other msgs already using up
532 * buffer space
533 */
534 i--;
535 continue;
536 }
537
538 /* need > sizeof(hdr_buf), need to grab some memory. Taking
539 * it off the stack is fine here.
540 */
541 char buf2[need];
542 struct fbuf fbuf2 = {
543 .buf = buf2,
544 .pos = buf2,
545 .len = sizeof(buf2),
546 };
547
548 state.fbuf = &fbuf2;
549 need = zlog_one(zte, msgs[i], &state);
550 assert(need == 0);
551
552 if (!zte->sa_len)
553 ret = writev(fd, iov, state.iov - iov);
554 else {
555 mpos->msg_hdr.msg_iovlen = state.iov - iov;
556 ret = sendmsg(fd, &mpos->msg_hdr, 0);
557 }
558
559 if (ret < 0)
560 zlog_5424_err(zte, 1);
561 else
562 zlog_5424_err(zte, 0);
563
564 count = 0;
565 state.fbuf = &hdr_pos;
566 state.iov = iov;
567 mpos = mmsg;
568 }
569
570 assert(state.iov == iov);
571 }
572
573 /* strftime(), gmtime_r() and localtime_r() aren't AS-Safe (they access locale
574 * data), but we need an AS-Safe timestamp below :(
575 */
576 static void gmtime_assafe(time_t ts, struct tm *res)
577 {
578 res->tm_sec = ts % 60;
579 ts /= 60;
580 res->tm_min = ts % 60;
581 ts /= 60;
582 res->tm_hour = ts % 24;
583 ts /= 24;
584
585 ts -= 11017; /* start on 2020-03-01, 11017 days since 1970-01-01 */
586
587 /* 1461 days = 3 regular years + 1 leap year
588 * this works until 2100, which isn't a leap year
589 *
590 * struct tm.tm_year starts at 1900.
591 */
592 res->tm_year = 2000 - 1900 + 4 * (ts / 1461);
593 ts = ts % 1461;
594
595 if (ts == 1460) {
596 res->tm_year += 4;
597 res->tm_mon = 1;
598 res->tm_mday = 29;
599 return;
600 }
601 res->tm_year += ts / 365;
602 ts %= 365;
603
604 /* note we're starting in march like the romans did... */
605 if (ts >= 306) /* Jan 1 of next year */
606 res->tm_year++;
607
608 static unsigned int months[13] = {
609 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 365,
610 };
611
612 for (size_t i = 0; i < array_size(months); i++) {
613 if ((unsigned int)ts < months[i + 1]) {
614 res->tm_mon = ((i + 2) % 12);
615 res->tm_mday = 1 + ts - months[i];
616 break;
617 }
618 }
619 }
620
621 /* one of the greatest advantages of this logging target: unlike syslog(),
622 * which is not AS-Safe, we can send crashlogs to syslog here.
623 */
624 static void zlog_5424_sigsafe(struct zlog_target *zt, const char *text,
625 size_t len)
626 {
627 static const char *const months_3164[12] = {
628 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
629 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
630 };
631
632 struct zlt_5424 *zte = container_of(zt, struct zlt_5424, zt);
633 struct iovec iov[3], *iovp = iov;
634 char buf[256];
635 struct fbuf fbuf = {
636 .buf = buf,
637 .pos = buf,
638 .len = sizeof(buf),
639 };
640 int fd;
641 intmax_t pid = (intmax_t)getpid();
642 struct tm tm;
643
644 switch (zte->fmt) {
645 case ZLOG_FMT_5424:
646 gmtime_assafe(time(NULL), &tm);
647 bprintfrr(
648 &fbuf,
649 "<%d>1 %04u-%02u-%02uT%02u:%02u:%02uZ - %s %jd %.*s ",
650 zte->facility | LOG_CRIT, tm.tm_year + 1900,
651 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
652 tm.tm_sec, zlog_progname, pid, (int)(zlog_prefixsz - 2),
653 zlog_prefix);
654 break;
655
656 case ZLOG_FMT_3164:
657 case ZLOG_FMT_LOCAL:
658 /* this will unfortuantely be wrong by the timezone offset
659 * if the user selected non-UTC. But not much we can do
660 * about that...
661 */
662 gmtime_assafe(time(NULL), &tm);
663 bprintfrr(&fbuf, "<%d>%3s %2u %02u:%02u:%02u %s%s[%jd]: ",
664 zte->facility | LOG_CRIT, months_3164[tm.tm_mon],
665 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
666 (zte->fmt == ZLOG_FMT_LOCAL) ? "" : "- ",
667 zlog_progname, pid);
668 break;
669
670 case ZLOG_FMT_JOURNALD:
671 bprintfrr(&fbuf,
672 "PRIORITY=%d\n"
673 "SYSLOG_FACILITY=%d\n"
674 "FRR_DAEMON=%s\n"
675 "MESSAGE=",
676 LOG_CRIT, zte->facility, zlog_progname);
677 break;
678 }
679
680 iovp->iov_base = fbuf.buf;
681 iovp->iov_len = fbuf.pos - fbuf.buf;
682 iovp++;
683
684 iovp->iov_base = (char *)text;
685 iovp->iov_len = len;
686 iovp++;
687
688 if (zte->use_nl) {
689 iovp->iov_base = (char *)"\n";
690 iovp->iov_len = 1;
691 iovp++;
692 }
693
694 fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
695
696 if (!zte->sa_len)
697 writev(fd, iov, iovp - iov);
698 else {
699 struct msghdr mh = {};
700
701 mh.msg_name = (struct sockaddr *)&zte->sa;
702 mh.msg_namelen = zte->sa_len;
703 mh.msg_iov = iov;
704 mh.msg_iovlen = iovp - iov;
705 sendmsg(fd, &mh, 0);
706 }
707 }
708
709 /* housekeeping & configuration */
710
711 void zlog_5424_init(struct zlog_cfg_5424 *zcf)
712 {
713 pthread_mutex_init(&zcf->cfg_mtx, NULL);
714 }
715
716 static void zlog_5424_target_free(struct zlt_5424 *zlt)
717 {
718 if (!zlt)
719 return;
720
721 rcu_close(&zlt->head_close, zlt->fd);
722 rcu_free(MTYPE_LOG_5424, zlt, zt.rcu_head);
723 }
724
725 void zlog_5424_fini(struct zlog_cfg_5424 *zcf, bool keepopen)
726 {
727 if (keepopen)
728 zcf->active = NULL;
729
730 if (zcf->active) {
731 struct zlt_5424 *ztf;
732 struct zlog_target *zt;
733
734 zt = zlog_target_replace(&zcf->active->zt, NULL);
735 ztf = container_of(zt, struct zlt_5424, zt);
736 zlog_5424_target_free(ztf);
737 }
738 pthread_mutex_destroy(&zcf->cfg_mtx);
739 }
740
741 static void zlog_5424_cycle(struct zlog_cfg_5424 *zcf, int fd)
742 {
743 struct zlog_target *old;
744 struct zlt_5424 *zlt = NULL, *oldt;
745
746 if (fd >= 0) {
747 struct zlog_target *zt;
748
749 /* all of this is swapped in by zlog_target_replace() below,
750 * the old target is RCU-freed afterwards.
751 */
752 zt = zlog_target_clone(MTYPE_LOG_5424, &zcf->active->zt,
753 sizeof(*zlt));
754 zlt = container_of(zt, struct zlt_5424, zt);
755
756 zlt->fd = fd;
757 zlt->kw_version = zcf->kw_version;
758 zlt->kw_location = zcf->kw_location;
759 zlt->kw_uid = zcf->kw_uid;
760 zlt->kw_ec = zcf->kw_ec;
761 zlt->kw_args = zcf->kw_args;
762 zlt->use_nl = true;
763 zlt->facility = zcf->facility;
764
765 /* DGRAM & SEQPACKET = 1 log message per packet */
766 zlt->packets = (zcf->sock_type == SOCK_DGRAM) ||
767 (zcf->sock_type == SOCK_SEQPACKET);
768 zlt->sa = zcf->sa;
769 zlt->sa_len = zcf->sa_len;
770 zlt->fmt = zcf->fmt;
771 zlt->zt.prio_min = zcf->prio_min;
772 zlt->zt.logfn = zlog_5424;
773 zlt->zt.logfn_sigsafe = zlog_5424_sigsafe;
774
775 switch (zcf->fmt) {
776 case ZLOG_FMT_5424:
777 case ZLOG_FMT_JOURNALD:
778 zlt->ts_flags = zcf->ts_flags;
779 zlt->ts_flags &= ZLOG_TS_PREC | ZLOG_TS_UTC;
780 zlt->ts_flags |= ZLOG_TS_ISO8601;
781 break;
782 case ZLOG_FMT_3164:
783 case ZLOG_FMT_LOCAL:
784 zlt->ts_flags = zcf->ts_flags & ZLOG_TS_UTC;
785 if (zlt->packets)
786 zlt->use_nl = false;
787 break;
788 }
789 }
790
791 old = zcf->active ? &zcf->active->zt : NULL;
792 old = zlog_target_replace(old, &zlt->zt);
793 zcf->active = zlt;
794
795 /* oldt->fd == fd happens for zlog_5424_apply_meta() */
796 oldt = container_of(old, struct zlt_5424, zt);
797 if (oldt && oldt->fd != (unsigned int)fd)
798 rcu_close(&oldt->head_close, oldt->fd);
799 rcu_free(MTYPE_LOG_5424, oldt, zt.rcu_head);
800 }
801
802 static void zlog_5424_reconnect(struct thread *t)
803 {
804 struct zlog_cfg_5424 *zcf = THREAD_ARG(t);
805 int fd = THREAD_FD(t);
806 char dummy[256];
807 ssize_t ret;
808
809 if (zcf->active) {
810 ret = read(fd, dummy, sizeof(dummy));
811 if (ret > 0) {
812 /* logger is sending us something?!?! */
813 thread_add_read(t->master, zlog_5424_reconnect, zcf, fd,
814 &zcf->t_reconnect);
815 return;
816 }
817
818 if (ret == 0)
819 zlog_warn("logging socket %pSE closed by peer",
820 zcf->filename);
821 else
822 zlog_warn("logging socket %pSE error: %m",
823 zcf->filename);
824 }
825
826 /* do NOT close() anything here; other threads may still be writing
827 * and their messages need to be lost rather than end up on a random
828 * other fd that got reassigned the same number, like a BGP session!
829 */
830 fd = zlog_5424_open(zcf, -1);
831
832 frr_with_mutex (&zcf->cfg_mtx) {
833 zlog_5424_cycle(zcf, fd);
834 }
835 }
836
837 static int zlog_5424_unix(struct sockaddr_un *suna, int sock_type)
838 {
839 int fd;
840 int size = 1 * 1024 * 1024, prev_size;
841 socklen_t opt_size;
842 int save_errno;
843
844 fd = socket(AF_UNIX, sock_type, 0);
845 if (fd < 0)
846 return -1;
847
848 if (connect(fd, (struct sockaddr *)suna, sizeof(*suna))) {
849 /* zlog_5424_open() will print the error for connect() */
850 save_errno = errno;
851 close(fd);
852 errno = save_errno;
853 return -1;
854 }
855
856 opt_size = sizeof(prev_size);
857 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &prev_size, &opt_size))
858 return fd;
859
860 /* setsockopt_so_sendbuf() logs on error; we don't really care that
861 * much here. Also, never shrink the buffer below the initial size.
862 */
863 while (size > prev_size &&
864 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1)
865 size /= 2;
866
867 return fd;
868 }
869
870 static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type)
871 {
872 int fd = -1;
873 int flags = 0;
874 int err;
875 socklen_t optlen;
876 bool do_chown = false;
877 bool need_reconnect = false;
878 static const int unix_types[] = {
879 SOCK_STREAM,
880 SOCK_SEQPACKET,
881 SOCK_DGRAM,
882 };
883 struct sockaddr_un sa;
884
885 zcf->sock_type = -1;
886 zcf->sa_len = 0;
887
888 switch (zcf->dst) {
889 case ZLOG_5424_DST_NONE:
890 break;
891
892 case ZLOG_5424_DST_FD:
893 fd = dup(zcf->fd);
894
895 optlen = sizeof(sock_type);
896 if (!getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen)) {
897 zcf->sock_type = sock_type;
898 need_reconnect = (zcf->sock_type != SOCK_DGRAM);
899 }
900 break;
901
902 case ZLOG_5424_DST_FIFO:
903 if (!zcf->filename)
904 break;
905
906 if (!zcf->file_nocreate) {
907 frr_with_privs (lib_privs) {
908 mode_t prevmask;
909
910 prevmask = umask(0777 ^ zcf->file_mode);
911 err = mkfifo(zcf->filename, 0666);
912 umask(prevmask);
913 }
914 if (err == 0)
915 do_chown = true;
916 else if (errno != EEXIST)
917 break;
918 }
919
920 flags = O_NONBLOCK;
921 /* fallthru */
922
923 case ZLOG_5424_DST_FILE:
924 if (!zcf->filename)
925 break;
926
927 frr_with_privs (lib_privs) {
928 fd = open(zcf->filename, flags | O_WRONLY | O_APPEND |
929 O_CLOEXEC | O_NOCTTY);
930 }
931 if (fd >= 0)
932 break;
933 if (zcf->file_nocreate || flags) {
934 flog_err_sys(EC_LIB_SYSTEM_CALL,
935 "could not open log file %pSE: %m",
936 zcf->filename);
937 break;
938 }
939
940 frr_with_privs (lib_privs) {
941 mode_t prevmask;
942
943 prevmask = umask(0777 ^ zcf->file_mode);
944 fd = open(zcf->filename,
945 O_WRONLY | O_APPEND | O_CLOEXEC | O_NOCTTY |
946 O_CREAT | O_EXCL,
947 zcf->file_mode);
948 umask(prevmask);
949 }
950 if (fd >= 0) {
951 do_chown = true;
952 break;
953 }
954
955 frr_with_privs (lib_privs) {
956 fd = open(zcf->filename,
957 O_WRONLY | O_APPEND | O_CLOEXEC | O_NOCTTY);
958 }
959 if (fd >= 0)
960 break;
961
962 flog_err_sys(EC_LIB_SYSTEM_CALL,
963 "could not open or create log file %pSE: %m",
964 zcf->filename);
965 break;
966
967 case ZLOG_5424_DST_UNIX:
968 if (!zcf->filename)
969 break;
970
971 memset(&sa, 0, sizeof(sa));
972 sa.sun_family = AF_UNIX;
973 strlcpy(sa.sun_path, zcf->filename, sizeof(sa.sun_path));
974
975 /* check if ZLOG_5424_DST_FD needs a touch when changing
976 * something here. the user can pass in a pre-opened unix
977 * socket through a fd at startup.
978 */
979 frr_with_privs (lib_privs) {
980 if (sock_type != -1)
981 fd = zlog_5424_unix(&sa, sock_type);
982 else {
983 for (size_t i = 0; i < array_size(unix_types);
984 i++) {
985 fd = zlog_5424_unix(&sa, unix_types[i]);
986 if (fd != -1) {
987 zcf->sock_type = unix_types[i];
988 break;
989 }
990 }
991 }
992 }
993 if (fd == -1) {
994 zcf->sock_type = -1;
995
996 flog_err_sys(
997 EC_LIB_SYSTEM_CALL,
998 "could not connect to log unix path %pSE: %m",
999 zcf->filename);
1000 need_reconnect = true;
1001 } else {
1002 /* datagram sockets are connectionless, restarting
1003 * the receiver may lose some packets but will resume
1004 * working afterwards without any action from us.
1005 */
1006 need_reconnect = (zcf->sock_type != SOCK_DGRAM);
1007 }
1008 break;
1009 }
1010
1011 /* viable on both DST_FD and DST_UNIX path */
1012 if (zcf->sock_type == SOCK_DGRAM) {
1013 zcf->sa_len = sizeof(zcf->sa);
1014 if (getpeername(fd, (struct sockaddr *)&zcf->sa,
1015 &zcf->sa_len)) {
1016 flog_err_sys(
1017 EC_LIB_SYSTEM_CALL,
1018 "could not get remote address for log socket. logging may break if log receiver restarts.");
1019 zcf->sa_len = 0;
1020 }
1021 }
1022
1023 if (do_chown) {
1024 uid_t uid = zcf->file_uid;
1025 gid_t gid = zcf->file_gid;
1026
1027 if (uid != (uid_t)-1 || gid != (gid_t)-1) {
1028 frr_with_privs (lib_privs) {
1029 err = fchown(fd, uid, gid);
1030 }
1031 if (err)
1032 flog_err_sys(
1033 EC_LIB_SYSTEM_CALL,
1034 "failed to chown() log file %pSE: %m",
1035 zcf->filename);
1036 }
1037 }
1038
1039 if (need_reconnect) {
1040 assert(zcf->master);
1041
1042 if (fd != -1) {
1043 thread_add_read(zcf->master, zlog_5424_reconnect, zcf,
1044 fd, &zcf->t_reconnect);
1045 zcf->reconn_backoff_cur = zcf->reconn_backoff;
1046
1047 } else {
1048 thread_add_timer_msec(zcf->master, zlog_5424_reconnect,
1049 zcf, zcf->reconn_backoff_cur,
1050 &zcf->t_reconnect);
1051
1052 zcf->reconn_backoff_cur += zcf->reconn_backoff_cur / 2;
1053 if (zcf->reconn_backoff_cur > zcf->reconn_backoff_max)
1054 zcf->reconn_backoff_cur =
1055 zcf->reconn_backoff_max;
1056 }
1057 }
1058
1059 return fd;
1060 }
1061
1062 bool zlog_5424_apply_dst(struct zlog_cfg_5424 *zcf)
1063 {
1064 int fd = -1;
1065
1066 thread_cancel(&zcf->t_reconnect);
1067
1068 if (zcf->prio_min != ZLOG_DISABLED)
1069 fd = zlog_5424_open(zcf, -1);
1070
1071 frr_with_mutex (&zcf->cfg_mtx) {
1072 zlog_5424_cycle(zcf, fd);
1073 }
1074 return fd != -1;
1075 }
1076
1077
1078 bool zlog_5424_apply_meta(struct zlog_cfg_5424 *zcf)
1079 {
1080 frr_with_mutex (&zcf->cfg_mtx) {
1081 if (zcf->active)
1082 zlog_5424_cycle(zcf, zcf->active->fd);
1083 }
1084
1085 return true;
1086 }
1087
1088 void zlog_5424_state(struct zlog_cfg_5424 *zcf, size_t *lost_msgs,
1089 int *last_errno, bool *stale_errno, struct timeval *err_ts)
1090 {
1091 if (lost_msgs)
1092 *lost_msgs =
1093 zcf->active
1094 ? atomic_load_explicit(&zcf->active->lost_msgs,
1095 memory_order_relaxed)
1096 : 0;
1097 if (last_errno)
1098 *last_errno = zcf->active ? zcf->active->last_err : 0;
1099 if (stale_errno)
1100 *stale_errno = zcf->active ? !zcf->active->current_err : 0;
1101 if (err_ts && zcf->active)
1102 *err_ts = zcf->active->last_err_ts;
1103 }
1104
1105 struct rcu_close_rotate {
1106 struct rcu_head_close head_close;
1107 struct rcu_head head_self;
1108 };
1109
1110 bool zlog_5424_rotate(struct zlog_cfg_5424 *zcf)
1111 {
1112 struct rcu_close_rotate *rcr;
1113 int fd;
1114
1115 frr_with_mutex (&zcf->cfg_mtx) {
1116 if (!zcf->active)
1117 return true;
1118
1119 thread_cancel(&zcf->t_reconnect);
1120
1121 /* need to retain the socket type because it also influences
1122 * other fields (packets) and we can't atomically swap these
1123 * out. But we really want the atomic swap so we neither lose
1124 * nor duplicate log messages, particularly for file targets.
1125 *
1126 * (zlog_5424_apply_dst / zlog_target_replace will cause
1127 * duplicate log messages if another thread logs something
1128 * while we're right in the middle of swapping out the log
1129 * target)
1130 */
1131 fd = zlog_5424_open(zcf, zcf->sock_type);
1132 if (fd < 0)
1133 return false;
1134
1135 fd = atomic_exchange_explicit(&zcf->active->fd,
1136 (uint_fast32_t)fd,
1137 memory_order_relaxed);
1138 }
1139
1140 rcr = XCALLOC(MTYPE_LOG_5424_ROTATE, sizeof(*rcr));
1141 rcu_close(&rcr->head_close, fd);
1142 rcu_free(MTYPE_LOG_5424_ROTATE, rcr, head_self);
1143
1144 return true;
1145 }