1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2015-21 David Lamparter, for NetDEF, Inc.
6 /* when you work on this code, please install a fuzzer (e.g. AFL) and run
7 * tests/lib/fuzz_zlog.c
9 * The most likely type of bug in this code is an off-by-one error in the
10 * buffer management pieces, and this isn't easily covered by an unit test
11 * or topotests. Fuzzing is the best tool here, but the CI can't do that
12 * since it's quite resource intensive.
17 #include "zlog_5424.h"
26 #include "frr_pthread.h"
31 #include "lib/version.h"
32 #include "lib/lib_errors.h"
34 DEFINE_MTYPE_STATIC(LOG
, LOG_5424
, "extended log target");
35 DEFINE_MTYPE_STATIC(LOG
, LOG_5424_ROTATE
, "extended log rotate helper");
37 /* the actual log target data structure
39 * remember this is RCU'd by the core zlog functions. Changing anything
40 * works by allocating a new struct, filling it, adding it, and removing the
44 struct zlog_target zt
;
46 atomic_uint_fast32_t fd
;
48 enum zlog_5424_format fmt
;
52 /* the various extra pieces to add... */
59 /* some formats may or may not include the trailing \n */
62 /* for DGRAM & SEQPACKET sockets, send 1 log message per packet, since
63 * the socket preserves packet boundaries. On Linux, this uses
64 * sendmmsg() for efficiency, on other systems we need a syscall each.
68 /* for DGRAM, in order to not have to reconnect, we need to use
69 * sendto()/sendmsg() with the destination given; otherwise we'll get
70 * ENOTCONN. (We do a connect(), which serves to verify the type of
71 * socket, but if the receiver goes away, the kernel disconnects the
72 * socket so writev() no longer works since the destination is now
75 struct sockaddr_storage sa
;
78 /* these are both getting set, but current_err is cleared on success,
79 * so we know whether the error is current or past.
81 int last_err
, current_err
;
82 atomic_size_t lost_msgs
;
83 struct timeval last_err_ts
;
85 struct rcu_head_close head_close
;
88 static int zlog_5424_open(struct zlog_cfg_5424
*zcf
, int sock_type
);
90 /* rough header length estimate
91 * ============================
95 * 49^ longest filename (pceplib/test/pcep_utils_double_linked_list_test.h)
96 * 5^ highest line number (48530, bgpd/bgp_nb_config.c)
97 * 65^ longest function name
98 * (lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy)
99 * 11 unique id ("XXXXX-XXXXX")
100 * 10 EC ("4294967295" or "0xffffffff")
101 * 35 ISO8601 TS at full length ("YYYY-MM-DD HH:MM:SS.NNNNNNNNN+ZZ:ZZ")
105 * rarely used (hopefully...):
106 * 26^ FRR_VERSION ("10.10.10-dev-gffffffffffff")
110 * x16 highest number of format parameters currently
111 * 40 estimate for hostname + 2*daemon + pid
113 * specific format overhead:
115 * RFC3164 - shorter than the others
116 * RFC5424 - 175 + "<999>1 "=7 + 52 (location@50145) + 40 (host/...)
117 * rarely: + 65 + 26 (for [origin])
118 * args: 16 * (8 + per-arg (20?)) = ~448
120 * so without "args@", origin or (future) keywords, around 256 seems OK
121 * with args@ and/or origin and/or keywords, 512 seems more reasonable
123 * but - note the code allocates this amount multiplied by the number of
124 * messages in the incoming batch (minimum 3), this means short messages and
125 * long messages smooth each other out.
127 * Since the code handles space-exceeded by grabbing a bunch of stack memory,
128 * a reasonable middle ground estimate is desirable here, so ...
130 * let's go with 128 + args?128. (remember the minimum 3 multiplier)
132 * low_space is the point where we don't try to fit another message in & just
133 * submit what we have to the kernel.
135 * The zlog code only buffers debug & informational messages, so in production
136 * usage most of the calls will be writing out only 1 message. This makes
137 * the min *3 multiplier quite useful.
140 static inline size_t zlog_5424_bufsz(struct zlt_5424
*zte
, size_t nmsgs
,
148 return ret
* MAX(nmsgs
, 3);
156 /* stack-based keyword support is likely to bump this to 3 or 4 */
157 #define IOV_PER_MSG 2
158 _Static_assert(IOV_MAX
>= IOV_PER_MSG
,
159 "this code won't work with IOV_MAX < IOV_PER_MSG");
161 /* the following functions are quite similar, but trying to merge them just
162 * makes a big mess. check the others when touching one.
164 * timestamp keywords hostname
165 * RFC5424 ISO8601 yes yes
166 * RFC3164 RFC3164 no yes
167 * local RFC3164 no no
168 * journald ISO8601(unused) yes (unused)
171 static size_t zlog_5424_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
175 struct fbuf
*fbuf
= state
->fbuf
;
176 char *orig_pos
= fbuf
->pos
;
178 int prio
= zlog_msg_prio(msg
);
181 zlog_msg_pid(msg
, &pid
, &tid
);
183 need
+= bprintfrr(fbuf
, "<%d>1 ", prio
| zte
->facility
);
184 need
+= zlog_msg_ts(msg
, fbuf
, zte
->ts_flags
);
185 need
+= bprintfrr(fbuf
, " %s %s %jd %.*s ", cmd_hostname_get() ?: "-",
186 zlog_progname
, pid
, (int)(zlog_prefixsz
- 2),
192 "[origin enterpriseId=\"50145\" software=\"FRRouting\" swVersion=\"%s\"]",
195 const struct xref_logmsg
*xref
;
196 struct xrefdata
*xrefdata
;
198 need
+= bprintfrr(fbuf
, "[location@50145 tid=\"%jd\"", tid
);
199 if (zlog_instance
> 0)
200 need
+= bprintfrr(fbuf
, " instance=\"%d\"", zlog_instance
);
202 xref
= zlog_msg_xref(msg
);
203 xrefdata
= xref
? xref
->xref
.xrefdata
: NULL
;
206 need
+= bprintfrr(fbuf
, " id=\"%s\"", xrefdata
->uid
);
207 if (zte
->kw_ec
&& prio
<= LOG_WARNING
)
208 need
+= bprintfrr(fbuf
, " ec=\"%u\"", xref
->ec
);
209 if (zte
->kw_location
)
211 fbuf
, " file=\"%s\" line=\"%d\" func=\"%s\"",
212 xref
->xref
.file
, xref
->xref
.line
,
215 need
+= bputch(fbuf
, ']');
217 size_t hdrlen
, n_argpos
;
218 const struct fmt_outpos
*argpos
;
221 text
= zlog_msg_text(msg
, &textlen
);
222 zlog_msg_args(msg
, &hdrlen
, &n_argpos
, &argpos
);
224 if (zte
->kw_args
&& n_argpos
) {
225 need
+= bputs(fbuf
, "[args@50145");
227 for (size_t i
= 0; i
< n_argpos
; i
++) {
228 int len
= argpos
[i
].off_end
- argpos
[i
].off_start
;
230 need
+= bprintfrr(fbuf
, " arg%zu=%*pSQsq", i
+ 1, len
,
231 text
+ argpos
[i
].off_start
);
234 need
+= bputch(fbuf
, ']');
237 need
+= bputch(fbuf
, ' ');
239 if (orig_pos
+ need
> fbuf
->buf
+ fbuf
->len
) {
240 /* not enough space in the buffer for headers. the loop in
241 * zlog_5424() will flush other messages that are already in
242 * the buffer, grab a bigger buffer if needed, and try again.
244 fbuf
->pos
= orig_pos
;
248 /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
249 state
->iov
->iov_base
= orig_pos
;
250 state
->iov
->iov_len
= fbuf
->pos
- orig_pos
;
253 state
->iov
->iov_base
= (char *)text
+ hdrlen
;
254 state
->iov
->iov_len
= textlen
- hdrlen
+ zte
->use_nl
;
259 static size_t zlog_3164_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
263 struct fbuf
*fbuf
= state
->fbuf
;
264 char *orig_pos
= fbuf
->pos
;
266 int prio
= zlog_msg_prio(msg
);
269 zlog_msg_pid(msg
, &pid
, &tid
);
271 need
+= bprintfrr(fbuf
, "<%d>", prio
| zte
->facility
);
272 need
+= zlog_msg_ts_3164(msg
, fbuf
, zte
->ts_flags
);
273 if (zte
->fmt
!= ZLOG_FMT_LOCAL
) {
274 need
+= bputch(fbuf
, ' ');
275 need
+= bputs(fbuf
, cmd_hostname_get() ?: "-");
277 need
+= bprintfrr(fbuf
, " %s[%jd]: ", zlog_progname
, pid
);
279 if (orig_pos
+ need
> fbuf
->buf
+ fbuf
->len
) {
280 /* not enough space in the buffer for headers. loop in
281 * zlog_5424() will flush other messages that are already in
282 * the buffer, grab a bigger buffer if needed, and try again.
284 fbuf
->pos
= orig_pos
;
288 /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
289 state
->iov
->iov_base
= orig_pos
;
290 state
->iov
->iov_len
= fbuf
->pos
- orig_pos
;
293 state
->iov
->iov_base
= (char *)zlog_msg_text(msg
, &textlen
);
294 state
->iov
->iov_len
= textlen
+ zte
->use_nl
;
299 static size_t zlog_journald_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
303 struct fbuf
*fbuf
= state
->fbuf
;
304 char *orig_pos
= fbuf
->pos
;
306 int prio
= zlog_msg_prio(msg
);
309 zlog_msg_pid(msg
, &pid
, &tid
);
311 need
+= bprintfrr(fbuf
,
313 "SYSLOG_FACILITY=%d\n"
317 prio
, zte
->facility
, tid
, zlog_progname
);
318 need
+= zlog_msg_ts(msg
, fbuf
, zte
->ts_flags
);
319 need
+= bputch(fbuf
, '\n');
320 if (zlog_instance
> 0)
321 need
+= bprintfrr(fbuf
, "FRR_INSTANCE=%d\n", zlog_instance
);
323 const struct xref_logmsg
*xref
;
324 struct xrefdata
*xrefdata
;
326 xref
= zlog_msg_xref(msg
);
327 xrefdata
= xref
? xref
->xref
.xrefdata
: NULL
;
329 if (zte
->kw_uid
&& xrefdata
->uid
[0])
330 need
+= bprintfrr(fbuf
, "FRR_ID=%s\n", xrefdata
->uid
);
331 if (zte
->kw_ec
&& prio
<= LOG_WARNING
)
332 need
+= bprintfrr(fbuf
, "FRR_EC=%d\n", xref
->ec
);
333 if (zte
->kw_location
)
334 need
+= bprintfrr(fbuf
,
338 xref
->xref
.file
, xref
->xref
.line
,
342 size_t hdrlen
, n_argpos
;
343 const struct fmt_outpos
*argpos
;
346 text
= zlog_msg_text(msg
, &textlen
);
347 zlog_msg_args(msg
, &hdrlen
, &n_argpos
, &argpos
);
349 if (zte
->kw_args
&& n_argpos
) {
350 for (size_t i
= 0; i
< n_argpos
; i
++) {
351 int len
= argpos
[i
].off_end
- argpos
[i
].off_start
;
353 /* rather than escape the value, we could use
354 * journald's binary encoding, but that seems a bit
355 * excessive/unnecessary. 99% of things we print here
356 * will just output 1:1 with %pSE.
358 need
+= bprintfrr(fbuf
, "FRR_ARG%zu=%*pSE\n", i
+ 1,
359 len
, text
+ argpos
[i
].off_start
);
363 need
+= bputs(fbuf
, "MESSAGE=");
365 if (orig_pos
+ need
> fbuf
->buf
+ fbuf
->len
) {
366 /* not enough space in the buffer for headers. loop in
367 * zlog_5424() will flush other messages that are already in
368 * the buffer, grab a bigger buffer if needed, and try again.
370 fbuf
->pos
= orig_pos
;
374 /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
375 state
->iov
->iov_base
= orig_pos
;
376 state
->iov
->iov_len
= fbuf
->pos
- orig_pos
;
379 state
->iov
->iov_base
= (char *)text
+ hdrlen
;
380 state
->iov
->iov_len
= textlen
- hdrlen
+ 1;
385 static size_t zlog_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
390 return zlog_5424_one(zte
, msg
, state
);
393 return zlog_3164_one(zte
, msg
, state
);
394 case ZLOG_FMT_JOURNALD
:
395 return zlog_journald_one(zte
, msg
, state
);
400 static void zlog_5424_err(struct zlt_5424
*zte
, size_t count
)
403 zte
->current_err
= 0;
407 /* only the counter is atomic because otherwise it'd be meaningless */
408 atomic_fetch_add_explicit(&zte
->lost_msgs
, count
, memory_order_relaxed
);
410 /* these are non-atomic and can provide wrong results when read, but
411 * since they're only for debugging / display, that's OK.
413 zte
->current_err
= zte
->last_err
= errno
;
414 monotime(&zte
->last_err_ts
);
417 static void zlog_5424(struct zlog_target
*zt
, struct zlog_msg
*msgs
[],
421 struct zlt_5424
*zte
= container_of(zt
, struct zlt_5424
, zt
);
423 size_t niov
= MIN(IOV_PER_MSG
* nmsgs
, IOV_MAX
);
424 struct iovec iov
[niov
], *iov_last
= iov
+ niov
;
425 struct mmsghdr mmsg
[zte
->packets
? nmsgs
: 1], *mpos
= mmsg
;
428 /* refer to size estimate at top of file */
430 char hdr_buf
[zlog_5424_bufsz(zte
, nmsgs
, &low_space
)];
431 struct fbuf hdr_pos
= {
434 .len
= sizeof(hdr_buf
),
436 struct state state
= {
441 fd
= atomic_load_explicit(&zte
->fd
, memory_order_relaxed
);
443 memset(mmsg
, 0, sizeof(mmsg
));
445 for (i
= 0; i
< array_size(mmsg
); i
++) {
446 mmsg
[i
].msg_hdr
.msg_name
= (struct sockaddr
*)&zte
->sa
;
447 mmsg
[i
].msg_hdr
.msg_namelen
= zte
->sa_len
;
450 mmsg
[0].msg_hdr
.msg_iov
= iov
;
452 for (i
= 0; i
< nmsgs
; i
++) {
453 int prio
= zlog_msg_prio(msgs
[i
]);
456 if (prio
<= zte
->zt
.prio_min
) {
458 mpos
->msg_hdr
.msg_iov
= state
.iov
;
460 need
= zlog_one(zte
, msgs
[i
], &state
);
463 mpos
->msg_hdr
.msg_iovlen
=
464 state
.iov
- mpos
->msg_hdr
.msg_iov
;
470 /* clang-format off */
472 || (size_t)(hdr_pos
.buf
+ hdr_pos
.len
- hdr_pos
.pos
)
475 || state
.iov
+ IOV_PER_MSG
> iov_last
)
476 && state
.iov
> iov
) {
477 /* clang-format on */
480 struct mmsghdr
*sendpos
;
482 for (sendpos
= mmsg
; sendpos
< mpos
;) {
483 ret
= sendmmsg(fd
, sendpos
,
489 zlog_5424_err(zte
, mpos
- sendpos
);
493 ret
= writev(fd
, iov
, state
.iov
- iov
);
495 mpos
->msg_hdr
.msg_iovlen
=
497 ret
= sendmsg(fd
, &mpos
->msg_hdr
, 0);
501 zlog_5424_err(zte
, count
);
503 zlog_5424_err(zte
, 0);
507 hdr_pos
.pos
= hdr_buf
;
511 /* if need == 0, we just put a message (or nothing) in the
512 * buffer and are continuing for more to batch in a single
518 if (need
&& need
<= sizeof(hdr_buf
)) {
519 /* don't need to allocate, just try this msg
520 * again without other msgs already using up
527 /* need > sizeof(hdr_buf), need to grab some memory. Taking
528 * it off the stack is fine here.
531 struct fbuf fbuf2
= {
538 need
= zlog_one(zte
, msgs
[i
], &state
);
542 ret
= writev(fd
, iov
, state
.iov
- iov
);
544 mpos
->msg_hdr
.msg_iovlen
= state
.iov
- iov
;
545 ret
= sendmsg(fd
, &mpos
->msg_hdr
, 0);
549 zlog_5424_err(zte
, 1);
551 zlog_5424_err(zte
, 0);
554 state
.fbuf
= &hdr_pos
;
559 assert(state
.iov
== iov
);
562 /* strftime(), gmtime_r() and localtime_r() aren't AS-Safe (they access locale
563 * data), but we need an AS-Safe timestamp below :(
565 static void gmtime_assafe(time_t ts
, struct tm
*res
)
567 res
->tm_sec
= ts
% 60;
569 res
->tm_min
= ts
% 60;
571 res
->tm_hour
= ts
% 24;
574 ts
-= 11017; /* start on 2020-03-01, 11017 days since 1970-01-01 */
576 /* 1461 days = 3 regular years + 1 leap year
577 * this works until 2100, which isn't a leap year
579 * struct tm.tm_year starts at 1900.
581 res
->tm_year
= 2000 - 1900 + 4 * (ts
/ 1461);
590 res
->tm_year
+= ts
/ 365;
593 /* note we're starting in march like the romans did... */
594 if (ts
>= 306) /* Jan 1 of next year */
597 static time_t months
[13] = {
598 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 365,
600 const size_t month_max
= array_size(months
) - 1;
602 for (size_t i
= 0; i
< month_max
; i
++) {
603 if (ts
< months
[i
+ 1]) {
604 res
->tm_mon
= ((i
+ 2) % 12);
605 res
->tm_mday
= 1 + ts
- months
[i
];
611 /* one of the greatest advantages of this logging target: unlike syslog(),
612 * which is not AS-Safe, we can send crashlogs to syslog here.
614 static void zlog_5424_sigsafe(struct zlog_target
*zt
, const char *text
,
617 static const char *const months_3164
[12] = {
618 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
619 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
622 struct zlt_5424
*zte
= container_of(zt
, struct zlt_5424
, zt
);
623 struct iovec iov
[3], *iovp
= iov
;
631 intmax_t pid
= (intmax_t)getpid();
636 gmtime_assafe(time(NULL
), &tm
);
639 "<%d>1 %04u-%02u-%02uT%02u:%02u:%02uZ - %s %jd %.*s ",
640 zte
->facility
| LOG_CRIT
, tm
.tm_year
+ 1900,
641 tm
.tm_mon
+ 1, tm
.tm_mday
, tm
.tm_hour
, tm
.tm_min
,
642 tm
.tm_sec
, zlog_progname
, pid
, (int)(zlog_prefixsz
- 2),
648 /* this will unfortuantely be wrong by the timezone offset
649 * if the user selected non-UTC. But not much we can do
652 gmtime_assafe(time(NULL
), &tm
);
653 bprintfrr(&fbuf
, "<%d>%3s %2u %02u:%02u:%02u %s%s[%jd]: ",
654 zte
->facility
| LOG_CRIT
, months_3164
[tm
.tm_mon
],
655 tm
.tm_mday
, tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
,
656 (zte
->fmt
== ZLOG_FMT_LOCAL
) ? "" : "- ",
660 case ZLOG_FMT_JOURNALD
:
663 "SYSLOG_FACILITY=%d\n"
666 LOG_CRIT
, zte
->facility
, zlog_progname
);
670 iovp
->iov_base
= fbuf
.buf
;
671 iovp
->iov_len
= fbuf
.pos
- fbuf
.buf
;
674 iovp
->iov_base
= (char *)text
;
679 iovp
->iov_base
= (char *)"\n";
684 fd
= atomic_load_explicit(&zte
->fd
, memory_order_relaxed
);
687 writev(fd
, iov
, iovp
- iov
);
689 struct msghdr mh
= {};
691 mh
.msg_name
= (struct sockaddr
*)&zte
->sa
;
692 mh
.msg_namelen
= zte
->sa_len
;
694 mh
.msg_iovlen
= iovp
- iov
;
699 /* housekeeping & configuration */
701 void zlog_5424_init(struct zlog_cfg_5424
*zcf
)
703 pthread_mutex_init(&zcf
->cfg_mtx
, NULL
);
706 static void zlog_5424_target_free(struct zlt_5424
*zlt
)
711 rcu_close(&zlt
->head_close
, zlt
->fd
);
712 rcu_free(MTYPE_LOG_5424
, zlt
, zt
.rcu_head
);
715 void zlog_5424_fini(struct zlog_cfg_5424
*zcf
, bool keepopen
)
721 struct zlt_5424
*ztf
;
722 struct zlog_target
*zt
;
724 zt
= zlog_target_replace(&zcf
->active
->zt
, NULL
);
725 ztf
= container_of(zt
, struct zlt_5424
, zt
);
726 zlog_5424_target_free(ztf
);
728 pthread_mutex_destroy(&zcf
->cfg_mtx
);
731 static void zlog_5424_cycle(struct zlog_cfg_5424
*zcf
, int fd
)
733 struct zlog_target
*old
;
734 struct zlt_5424
*zlt
= NULL
, *oldt
;
737 struct zlog_target
*zt
;
739 /* all of this is swapped in by zlog_target_replace() below,
740 * the old target is RCU-freed afterwards.
742 zt
= zlog_target_clone(MTYPE_LOG_5424
, &zcf
->active
->zt
,
744 zlt
= container_of(zt
, struct zlt_5424
, zt
);
747 zlt
->kw_version
= zcf
->kw_version
;
748 zlt
->kw_location
= zcf
->kw_location
;
749 zlt
->kw_uid
= zcf
->kw_uid
;
750 zlt
->kw_ec
= zcf
->kw_ec
;
751 zlt
->kw_args
= zcf
->kw_args
;
753 zlt
->facility
= zcf
->facility
;
755 /* DGRAM & SEQPACKET = 1 log message per packet */
756 zlt
->packets
= (zcf
->sock_type
== SOCK_DGRAM
) ||
757 (zcf
->sock_type
== SOCK_SEQPACKET
);
759 zlt
->sa_len
= zcf
->sa_len
;
761 zlt
->zt
.prio_min
= zcf
->prio_min
;
762 zlt
->zt
.logfn
= zlog_5424
;
763 zlt
->zt
.logfn_sigsafe
= zlog_5424_sigsafe
;
767 case ZLOG_FMT_JOURNALD
:
768 zlt
->ts_flags
= zcf
->ts_flags
;
769 zlt
->ts_flags
&= ZLOG_TS_PREC
| ZLOG_TS_UTC
;
770 zlt
->ts_flags
|= ZLOG_TS_ISO8601
;
774 zlt
->ts_flags
= zcf
->ts_flags
& ZLOG_TS_UTC
;
781 old
= zcf
->active
? &zcf
->active
->zt
: NULL
;
782 old
= zlog_target_replace(old
, &zlt
->zt
);
785 /* oldt->fd == fd happens for zlog_5424_apply_meta() */
786 oldt
= container_of(old
, struct zlt_5424
, zt
);
787 if (oldt
&& oldt
->fd
!= (unsigned int)fd
)
788 rcu_close(&oldt
->head_close
, oldt
->fd
);
789 rcu_free(MTYPE_LOG_5424
, oldt
, zt
.rcu_head
);
792 static void zlog_5424_reconnect(struct event
*t
)
794 struct zlog_cfg_5424
*zcf
= THREAD_ARG(t
);
795 int fd
= THREAD_FD(t
);
800 ret
= read(fd
, dummy
, sizeof(dummy
));
802 /* logger is sending us something?!?! */
803 event_add_read(t
->master
, zlog_5424_reconnect
, zcf
, fd
,
809 zlog_warn("logging socket %pSE closed by peer",
812 zlog_warn("logging socket %pSE error: %m",
816 /* do NOT close() anything here; other threads may still be writing
817 * and their messages need to be lost rather than end up on a random
818 * other fd that got reassigned the same number, like a BGP session!
820 fd
= zlog_5424_open(zcf
, -1);
822 frr_with_mutex (&zcf
->cfg_mtx
) {
823 zlog_5424_cycle(zcf
, fd
);
827 static int zlog_5424_unix(struct sockaddr_un
*suna
, int sock_type
)
830 int size
= 1 * 1024 * 1024, prev_size
;
834 fd
= socket(AF_UNIX
, sock_type
, 0);
838 if (connect(fd
, (struct sockaddr
*)suna
, sizeof(*suna
))) {
839 /* zlog_5424_open() will print the error for connect() */
846 opt_size
= sizeof(prev_size
);
847 if (getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &prev_size
, &opt_size
))
850 /* setsockopt_so_sendbuf() logs on error; we don't really care that
851 * much here. Also, never shrink the buffer below the initial size.
853 while (size
> prev_size
&&
854 setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &size
, sizeof(size
)) == -1)
860 static int zlog_5424_open(struct zlog_cfg_5424
*zcf
, int sock_type
)
866 bool do_chown
= false;
867 bool need_reconnect
= false;
868 static const int unix_types
[] = {
873 struct sockaddr_un sa
;
879 case ZLOG_5424_DST_NONE
:
882 case ZLOG_5424_DST_FD
:
885 optlen
= sizeof(sock_type
);
886 if (!getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &sock_type
, &optlen
)) {
887 zcf
->sock_type
= sock_type
;
888 need_reconnect
= (zcf
->sock_type
!= SOCK_DGRAM
);
892 case ZLOG_5424_DST_FIFO
:
896 if (!zcf
->file_nocreate
) {
897 frr_with_privs (lib_privs
) {
900 prevmask
= umask(0777 ^ zcf
->file_mode
);
901 err
= mkfifo(zcf
->filename
, 0666);
906 else if (errno
!= EEXIST
)
913 case ZLOG_5424_DST_FILE
:
917 frr_with_privs (lib_privs
) {
918 fd
= open(zcf
->filename
, flags
| O_WRONLY
| O_APPEND
|
919 O_CLOEXEC
| O_NOCTTY
);
923 if (zcf
->file_nocreate
|| flags
) {
924 flog_err_sys(EC_LIB_SYSTEM_CALL
,
925 "could not open log file %pSE: %m",
930 frr_with_privs (lib_privs
) {
933 prevmask
= umask(0777 ^ zcf
->file_mode
);
934 fd
= open(zcf
->filename
,
935 O_WRONLY
| O_APPEND
| O_CLOEXEC
| O_NOCTTY
|
945 frr_with_privs (lib_privs
) {
946 fd
= open(zcf
->filename
,
947 O_WRONLY
| O_APPEND
| O_CLOEXEC
| O_NOCTTY
);
952 flog_err_sys(EC_LIB_SYSTEM_CALL
,
953 "could not open or create log file %pSE: %m",
957 case ZLOG_5424_DST_UNIX
:
961 memset(&sa
, 0, sizeof(sa
));
962 sa
.sun_family
= AF_UNIX
;
963 strlcpy(sa
.sun_path
, zcf
->filename
, sizeof(sa
.sun_path
));
965 /* check if ZLOG_5424_DST_FD needs a touch when changing
966 * something here. the user can pass in a pre-opened unix
967 * socket through a fd at startup.
969 frr_with_privs (lib_privs
) {
971 fd
= zlog_5424_unix(&sa
, sock_type
);
973 for (size_t i
= 0; i
< array_size(unix_types
);
975 fd
= zlog_5424_unix(&sa
, unix_types
[i
]);
977 zcf
->sock_type
= unix_types
[i
];
988 "could not connect to log unix path %pSE: %m",
990 need_reconnect
= true;
992 /* datagram sockets are connectionless, restarting
993 * the receiver may lose some packets but will resume
994 * working afterwards without any action from us.
996 need_reconnect
= (zcf
->sock_type
!= SOCK_DGRAM
);
1001 /* viable on both DST_FD and DST_UNIX path */
1002 if (zcf
->sock_type
== SOCK_DGRAM
) {
1003 zcf
->sa_len
= sizeof(zcf
->sa
);
1004 if (getpeername(fd
, (struct sockaddr
*)&zcf
->sa
,
1008 "could not get remote address for log socket. logging may break if log receiver restarts.");
1014 uid_t uid
= zcf
->file_uid
;
1015 gid_t gid
= zcf
->file_gid
;
1017 if (uid
!= (uid_t
)-1 || gid
!= (gid_t
)-1) {
1018 frr_with_privs (lib_privs
) {
1019 err
= fchown(fd
, uid
, gid
);
1024 "failed to chown() log file %pSE: %m",
1029 if (need_reconnect
) {
1030 assert(zcf
->master
);
1033 event_add_read(zcf
->master
, zlog_5424_reconnect
, zcf
,
1034 fd
, &zcf
->t_reconnect
);
1035 zcf
->reconn_backoff_cur
= zcf
->reconn_backoff
;
1038 event_add_timer_msec(zcf
->master
, zlog_5424_reconnect
,
1039 zcf
, zcf
->reconn_backoff_cur
,
1042 zcf
->reconn_backoff_cur
+= zcf
->reconn_backoff_cur
/ 2;
1043 if (zcf
->reconn_backoff_cur
> zcf
->reconn_backoff_max
)
1044 zcf
->reconn_backoff_cur
=
1045 zcf
->reconn_backoff_max
;
1052 bool zlog_5424_apply_dst(struct zlog_cfg_5424
*zcf
)
1056 event_cancel(&zcf
->t_reconnect
);
1058 if (zcf
->prio_min
!= ZLOG_DISABLED
)
1059 fd
= zlog_5424_open(zcf
, -1);
1061 frr_with_mutex (&zcf
->cfg_mtx
) {
1062 zlog_5424_cycle(zcf
, fd
);
1068 bool zlog_5424_apply_meta(struct zlog_cfg_5424
*zcf
)
1070 frr_with_mutex (&zcf
->cfg_mtx
) {
1072 zlog_5424_cycle(zcf
, zcf
->active
->fd
);
1078 void zlog_5424_state(struct zlog_cfg_5424
*zcf
, size_t *lost_msgs
,
1079 int *last_errno
, bool *stale_errno
, struct timeval
*err_ts
)
1084 ? atomic_load_explicit(&zcf
->active
->lost_msgs
,
1085 memory_order_relaxed
)
1088 *last_errno
= zcf
->active
? zcf
->active
->last_err
: 0;
1090 *stale_errno
= zcf
->active
? !zcf
->active
->current_err
: 0;
1091 if (err_ts
&& zcf
->active
)
1092 *err_ts
= zcf
->active
->last_err_ts
;
1095 struct rcu_close_rotate
{
1096 struct rcu_head_close head_close
;
1097 struct rcu_head head_self
;
1100 bool zlog_5424_rotate(struct zlog_cfg_5424
*zcf
)
1102 struct rcu_close_rotate
*rcr
;
1105 frr_with_mutex (&zcf
->cfg_mtx
) {
1109 event_cancel(&zcf
->t_reconnect
);
1111 /* need to retain the socket type because it also influences
1112 * other fields (packets) and we can't atomically swap these
1113 * out. But we really want the atomic swap so we neither lose
1114 * nor duplicate log messages, particularly for file targets.
1116 * (zlog_5424_apply_dst / zlog_target_replace will cause
1117 * duplicate log messages if another thread logs something
1118 * while we're right in the middle of swapping out the log
1121 fd
= zlog_5424_open(zcf
, zcf
->sock_type
);
1125 fd
= atomic_exchange_explicit(&zcf
->active
->fd
,
1127 memory_order_relaxed
);
1130 rcr
= XCALLOC(MTYPE_LOG_5424_ROTATE
, sizeof(*rcr
));
1131 rcu_close(&rcr
->head_close
, fd
);
1132 rcu_free(MTYPE_LOG_5424_ROTATE
, rcr
, head_self
);