2 * Copyright (c) 2015-21 David Lamparter, for NetDEF, Inc.
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.
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.
17 /* when you work on this code, please install a fuzzer (e.g. AFL) and run
18 * tests/lib/fuzz_zlog.c
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.
28 #include "zlog_5424.h"
37 #include "frr_pthread.h"
42 #include "lib/version.h"
43 #include "lib/lib_errors.h"
45 DEFINE_MTYPE_STATIC(LOG
, LOG_5424
, "extended log target");
46 DEFINE_MTYPE_STATIC(LOG
, LOG_5424_ROTATE
, "extended log rotate helper");
48 /* the actual log target data structure
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
55 struct zlog_target zt
;
57 atomic_uint_fast32_t fd
;
59 enum zlog_5424_format fmt
;
63 /* the various extra pieces to add... */
70 /* some formats may or may not include the trailing \n */
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.
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
86 struct sockaddr_storage sa
;
89 /* these are both getting set, but current_err is cleared on success,
90 * so we know whether the error is current or past.
92 int last_err
, current_err
;
93 atomic_size_t lost_msgs
;
94 struct timeval last_err_ts
;
96 struct rcu_head_close head_close
;
99 static int zlog_5424_open(struct zlog_cfg_5424
*zcf
, int sock_type
);
101 /* rough header length estimate
102 * ============================
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")
116 * rarely used (hopefully...):
117 * 26^ FRR_VERSION ("10.10.10-dev-gffffffffffff")
121 * x16 highest number of format parameters currently
122 * 40 estimate for hostname + 2*daemon + pid
124 * specific format overhead:
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
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
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.
138 * Since the code handles space-exceeded by grabbing a bunch of stack memory,
139 * a reasonable middle ground estimate is desirable here, so ...
141 * let's go with 128 + args?128. (remember the minimum 3 multiplier)
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.
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.
151 static inline size_t zlog_5424_bufsz(struct zlt_5424
*zte
, size_t nmsgs
,
159 return ret
* MAX(nmsgs
, 3);
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");
172 /* the following functions are quite similar, but trying to merge them just
173 * makes a big mess. check the others when touching one.
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)
182 static size_t zlog_5424_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
186 struct fbuf
*fbuf
= state
->fbuf
;
187 char *orig_pos
= fbuf
->pos
;
189 int prio
= zlog_msg_prio(msg
);
192 zlog_msg_pid(msg
, &pid
, &tid
);
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),
203 "[origin enterpriseId=\"50145\" software=\"FRRouting\" swVersion=\"%s\"]",
206 const struct xref_logmsg
*xref
;
207 struct xrefdata
*xrefdata
;
209 need
+= bprintfrr(fbuf
, "[location@50145 tid=\"%jd\"", tid
);
210 if (zlog_instance
> 0)
211 need
+= bprintfrr(fbuf
, " instance=\"%d\"", zlog_instance
);
213 xref
= zlog_msg_xref(msg
);
214 xrefdata
= xref
? xref
->xref
.xrefdata
: NULL
;
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
)
222 fbuf
, " file=\"%s\" line=\"%d\" func=\"%s\"",
223 xref
->xref
.file
, xref
->xref
.line
,
226 need
+= bputch(fbuf
, ']');
228 size_t hdrlen
, n_argpos
;
229 const struct fmt_outpos
*argpos
;
232 text
= zlog_msg_text(msg
, &textlen
);
233 zlog_msg_args(msg
, &hdrlen
, &n_argpos
, &argpos
);
235 if (zte
->kw_args
&& n_argpos
) {
236 need
+= bputs(fbuf
, "[args@50145");
238 for (size_t i
= 0; i
< n_argpos
; i
++) {
239 int len
= argpos
[i
].off_end
- argpos
[i
].off_start
;
241 need
+= bprintfrr(fbuf
, " arg%zu=%*pSQsq", i
+ 1, len
,
242 text
+ argpos
[i
].off_start
);
245 need
+= bputch(fbuf
, ']');
248 need
+= bputch(fbuf
, ' ');
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.
255 fbuf
->pos
= orig_pos
;
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
;
264 state
->iov
->iov_base
= (char *)text
+ hdrlen
;
265 state
->iov
->iov_len
= textlen
- hdrlen
+ zte
->use_nl
;
270 static size_t zlog_3164_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
274 struct fbuf
*fbuf
= state
->fbuf
;
275 char *orig_pos
= fbuf
->pos
;
277 int prio
= zlog_msg_prio(msg
);
280 zlog_msg_pid(msg
, &pid
, &tid
);
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() ?: "-");
288 need
+= bprintfrr(fbuf
, " %s[%jd]: ", zlog_progname
, pid
);
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.
295 fbuf
->pos
= orig_pos
;
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
;
304 state
->iov
->iov_base
= (char *)zlog_msg_text(msg
, &textlen
);
305 state
->iov
->iov_len
= textlen
+ zte
->use_nl
;
310 static size_t zlog_journald_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
314 struct fbuf
*fbuf
= state
->fbuf
;
315 char *orig_pos
= fbuf
->pos
;
317 int prio
= zlog_msg_prio(msg
);
320 zlog_msg_pid(msg
, &pid
, &tid
);
322 need
+= bprintfrr(fbuf
,
324 "SYSLOG_FACILITY=%d\n"
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
);
334 const struct xref_logmsg
*xref
;
335 struct xrefdata
*xrefdata
;
337 xref
= zlog_msg_xref(msg
);
338 xrefdata
= xref
? xref
->xref
.xrefdata
: NULL
;
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
,
349 xref
->xref
.file
, xref
->xref
.line
,
353 size_t hdrlen
, n_argpos
;
354 const struct fmt_outpos
*argpos
;
357 text
= zlog_msg_text(msg
, &textlen
);
358 zlog_msg_args(msg
, &hdrlen
, &n_argpos
, &argpos
);
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
;
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.
369 need
+= bprintfrr(fbuf
, "FRR_ARG%zu=%*pSE\n", i
+ 1,
370 len
, text
+ argpos
[i
].off_start
);
374 need
+= bputs(fbuf
, "MESSAGE=");
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.
381 fbuf
->pos
= orig_pos
;
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
;
390 state
->iov
->iov_base
= (char *)text
+ hdrlen
;
391 state
->iov
->iov_len
= textlen
- hdrlen
+ 1;
396 static size_t zlog_one(struct zlt_5424
*zte
, struct zlog_msg
*msg
,
401 return zlog_5424_one(zte
, msg
, state
);
404 return zlog_3164_one(zte
, msg
, state
);
405 case ZLOG_FMT_JOURNALD
:
406 return zlog_journald_one(zte
, msg
, state
);
411 static void zlog_5424_err(struct zlt_5424
*zte
, size_t count
)
414 zte
->current_err
= 0;
418 /* only the counter is atomic because otherwise it'd be meaningless */
419 atomic_fetch_add_explicit(&zte
->lost_msgs
, count
, memory_order_relaxed
);
421 /* these are non-atomic and can provide wrong results when read, but
422 * since they're only for debugging / display, that's OK.
424 zte
->current_err
= zte
->last_err
= errno
;
425 monotime(&zte
->last_err_ts
);
428 static void zlog_5424(struct zlog_target
*zt
, struct zlog_msg
*msgs
[],
432 struct zlt_5424
*zte
= container_of(zt
, struct zlt_5424
, zt
);
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
;
439 /* refer to size estimate at top of file */
441 char hdr_buf
[zlog_5424_bufsz(zte
, nmsgs
, &low_space
)];
442 struct fbuf hdr_pos
= {
445 .len
= sizeof(hdr_buf
),
447 struct state state
= {
452 fd
= atomic_load_explicit(&zte
->fd
, memory_order_relaxed
);
454 memset(mmsg
, 0, sizeof(mmsg
));
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
;
461 mmsg
[0].msg_hdr
.msg_iov
= iov
;
463 for (i
= 0; i
< nmsgs
; i
++) {
464 int prio
= zlog_msg_prio(msgs
[i
]);
467 if (prio
<= zte
->zt
.prio_min
) {
469 mpos
->msg_hdr
.msg_iov
= state
.iov
;
471 need
= zlog_one(zte
, msgs
[i
], &state
);
474 mpos
->msg_hdr
.msg_iovlen
=
475 state
.iov
- mpos
->msg_hdr
.msg_iov
;
481 /* clang-format off */
483 || (size_t)(hdr_pos
.buf
+ hdr_pos
.len
- hdr_pos
.pos
)
486 || state
.iov
+ IOV_PER_MSG
> iov_last
)
487 && state
.iov
> iov
) {
488 /* clang-format on */
491 struct mmsghdr
*sendpos
;
493 for (sendpos
= mmsg
; sendpos
< mpos
;) {
494 ret
= sendmmsg(fd
, sendpos
,
500 zlog_5424_err(zte
, mpos
- sendpos
);
504 ret
= writev(fd
, iov
, state
.iov
- iov
);
506 mpos
->msg_hdr
.msg_iovlen
=
508 ret
= sendmsg(fd
, &mpos
->msg_hdr
, 0);
512 zlog_5424_err(zte
, count
);
514 zlog_5424_err(zte
, 0);
518 hdr_pos
.pos
= hdr_buf
;
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
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
538 /* need > sizeof(hdr_buf), need to grab some memory. Taking
539 * it off the stack is fine here.
542 struct fbuf fbuf2
= {
549 need
= zlog_one(zte
, msgs
[i
], &state
);
553 ret
= writev(fd
, iov
, state
.iov
- iov
);
555 mpos
->msg_hdr
.msg_iovlen
= state
.iov
- iov
;
556 ret
= sendmsg(fd
, &mpos
->msg_hdr
, 0);
560 zlog_5424_err(zte
, 1);
562 zlog_5424_err(zte
, 0);
565 state
.fbuf
= &hdr_pos
;
570 assert(state
.iov
== iov
);
573 /* strftime(), gmtime_r() and localtime_r() aren't AS-Safe (they access locale
574 * data), but we need an AS-Safe timestamp below :(
576 static void gmtime_assafe(time_t ts
, struct tm
*res
)
578 res
->tm_sec
= ts
% 60;
580 res
->tm_min
= ts
% 60;
582 res
->tm_hour
= ts
% 24;
585 ts
-= 11017; /* start on 2020-03-01, 11017 days since 1970-01-01 */
587 /* 1461 days = 3 regular years + 1 leap year
588 * this works until 2100, which isn't a leap year
590 * struct tm.tm_year starts at 1900.
592 res
->tm_year
= 2000 - 1900 + 4 * (ts
/ 1461);
601 res
->tm_year
+= ts
/ 365;
604 /* note we're starting in march like the romans did... */
605 if (ts
>= 306) /* Jan 1 of next year */
608 static unsigned int months
[13] = {
609 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 365,
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
];
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.
624 static void zlog_5424_sigsafe(struct zlog_target
*zt
, const char *text
,
627 static const char *const months_3164
[12] = {
628 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
629 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
632 struct zlt_5424
*zte
= container_of(zt
, struct zlt_5424
, zt
);
633 struct iovec iov
[3], *iovp
= iov
;
641 intmax_t pid
= (intmax_t)getpid();
646 gmtime_assafe(time(NULL
), &tm
);
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),
658 /* this will unfortuantely be wrong by the timezone offset
659 * if the user selected non-UTC. But not much we can do
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
) ? "" : "- ",
670 case ZLOG_FMT_JOURNALD
:
673 "SYSLOG_FACILITY=%d\n"
676 LOG_CRIT
, zte
->facility
, zlog_progname
);
680 iovp
->iov_base
= fbuf
.buf
;
681 iovp
->iov_len
= fbuf
.pos
- fbuf
.buf
;
684 iovp
->iov_base
= (char *)text
;
689 iovp
->iov_base
= (char *)"\n";
694 fd
= atomic_load_explicit(&zte
->fd
, memory_order_relaxed
);
697 writev(fd
, iov
, iovp
- iov
);
699 struct msghdr mh
= {};
701 mh
.msg_name
= (struct sockaddr
*)&zte
->sa
;
702 mh
.msg_namelen
= zte
->sa_len
;
704 mh
.msg_iovlen
= iovp
- iov
;
709 /* housekeeping & configuration */
711 void zlog_5424_init(struct zlog_cfg_5424
*zcf
)
713 pthread_mutex_init(&zcf
->cfg_mtx
, NULL
);
716 static void zlog_5424_target_free(struct zlt_5424
*zlt
)
721 rcu_close(&zlt
->head_close
, zlt
->fd
);
722 rcu_free(MTYPE_LOG_5424
, zlt
, zt
.rcu_head
);
725 void zlog_5424_fini(struct zlog_cfg_5424
*zcf
, bool keepopen
)
731 struct zlt_5424
*ztf
;
732 struct zlog_target
*zt
;
734 zt
= zlog_target_replace(&zcf
->active
->zt
, NULL
);
735 ztf
= container_of(zt
, struct zlt_5424
, zt
);
736 zlog_5424_target_free(ztf
);
738 pthread_mutex_destroy(&zcf
->cfg_mtx
);
741 static void zlog_5424_cycle(struct zlog_cfg_5424
*zcf
, int fd
)
743 struct zlog_target
*old
;
744 struct zlt_5424
*zlt
= NULL
, *oldt
;
747 struct zlog_target
*zt
;
749 /* all of this is swapped in by zlog_target_replace() below,
750 * the old target is RCU-freed afterwards.
752 zt
= zlog_target_clone(MTYPE_LOG_5424
, &zcf
->active
->zt
,
754 zlt
= container_of(zt
, struct zlt_5424
, zt
);
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
;
763 zlt
->facility
= zcf
->facility
;
765 /* DGRAM & SEQPACKET = 1 log message per packet */
766 zlt
->packets
= (zcf
->sock_type
== SOCK_DGRAM
) ||
767 (zcf
->sock_type
== SOCK_SEQPACKET
);
769 zlt
->sa_len
= zcf
->sa_len
;
771 zlt
->zt
.prio_min
= zcf
->prio_min
;
772 zlt
->zt
.logfn
= zlog_5424
;
773 zlt
->zt
.logfn_sigsafe
= zlog_5424_sigsafe
;
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
;
784 zlt
->ts_flags
= zcf
->ts_flags
& ZLOG_TS_UTC
;
791 old
= zcf
->active
? &zcf
->active
->zt
: NULL
;
792 old
= zlog_target_replace(old
, &zlt
->zt
);
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
);
802 static void zlog_5424_reconnect(struct thread
*t
)
804 struct zlog_cfg_5424
*zcf
= THREAD_ARG(t
);
805 int fd
= THREAD_FD(t
);
810 ret
= read(fd
, dummy
, sizeof(dummy
));
812 /* logger is sending us something?!?! */
813 thread_add_read(t
->master
, zlog_5424_reconnect
, zcf
, fd
,
819 zlog_warn("logging socket %pSE closed by peer",
822 zlog_warn("logging socket %pSE error: %m",
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!
830 fd
= zlog_5424_open(zcf
, -1);
832 frr_with_mutex (&zcf
->cfg_mtx
) {
833 zlog_5424_cycle(zcf
, fd
);
837 static int zlog_5424_unix(struct sockaddr_un
*suna
, int sock_type
)
840 int size
= 1 * 1024 * 1024, prev_size
;
844 fd
= socket(AF_UNIX
, sock_type
, 0);
848 if (connect(fd
, (struct sockaddr
*)suna
, sizeof(*suna
))) {
849 /* zlog_5424_open() will print the error for connect() */
856 opt_size
= sizeof(prev_size
);
857 if (getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &prev_size
, &opt_size
))
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.
863 while (size
> prev_size
&&
864 setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &size
, sizeof(size
)) == -1)
870 static int zlog_5424_open(struct zlog_cfg_5424
*zcf
, int sock_type
)
876 bool do_chown
= false;
877 bool need_reconnect
= false;
878 static const int unix_types
[] = {
883 struct sockaddr_un sa
;
889 case ZLOG_5424_DST_NONE
:
892 case ZLOG_5424_DST_FD
:
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
);
902 case ZLOG_5424_DST_FIFO
:
906 if (!zcf
->file_nocreate
) {
907 frr_with_privs (lib_privs
) {
910 prevmask
= umask(0777 ^ zcf
->file_mode
);
911 err
= mkfifo(zcf
->filename
, 0666);
916 else if (errno
!= EEXIST
)
923 case ZLOG_5424_DST_FILE
:
927 frr_with_privs (lib_privs
) {
928 fd
= open(zcf
->filename
, flags
| O_WRONLY
| O_APPEND
|
929 O_CLOEXEC
| O_NOCTTY
);
933 if (zcf
->file_nocreate
|| flags
) {
934 flog_err_sys(EC_LIB_SYSTEM_CALL
,
935 "could not open log file %pSE: %m",
940 frr_with_privs (lib_privs
) {
943 prevmask
= umask(0777 ^ zcf
->file_mode
);
944 fd
= open(zcf
->filename
,
945 O_WRONLY
| O_APPEND
| O_CLOEXEC
| O_NOCTTY
|
955 frr_with_privs (lib_privs
) {
956 fd
= open(zcf
->filename
,
957 O_WRONLY
| O_APPEND
| O_CLOEXEC
| O_NOCTTY
);
962 flog_err_sys(EC_LIB_SYSTEM_CALL
,
963 "could not open or create log file %pSE: %m",
967 case ZLOG_5424_DST_UNIX
:
971 memset(&sa
, 0, sizeof(sa
));
972 sa
.sun_family
= AF_UNIX
;
973 strlcpy(sa
.sun_path
, zcf
->filename
, sizeof(sa
.sun_path
));
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.
979 frr_with_privs (lib_privs
) {
981 fd
= zlog_5424_unix(&sa
, sock_type
);
983 for (size_t i
= 0; i
< array_size(unix_types
);
985 fd
= zlog_5424_unix(&sa
, unix_types
[i
]);
987 zcf
->sock_type
= unix_types
[i
];
998 "could not connect to log unix path %pSE: %m",
1000 need_reconnect
= true;
1002 /* datagram sockets are connectionless, restarting
1003 * the receiver may lose some packets but will resume
1004 * working afterwards without any action from us.
1006 need_reconnect
= (zcf
->sock_type
!= SOCK_DGRAM
);
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
,
1018 "could not get remote address for log socket. logging may break if log receiver restarts.");
1024 uid_t uid
= zcf
->file_uid
;
1025 gid_t gid
= zcf
->file_gid
;
1027 if (uid
!= (uid_t
)-1 || gid
!= (gid_t
)-1) {
1028 frr_with_privs (lib_privs
) {
1029 err
= fchown(fd
, uid
, gid
);
1034 "failed to chown() log file %pSE: %m",
1039 if (need_reconnect
) {
1040 assert(zcf
->master
);
1043 thread_add_read(zcf
->master
, zlog_5424_reconnect
, zcf
,
1044 fd
, &zcf
->t_reconnect
);
1045 zcf
->reconn_backoff_cur
= zcf
->reconn_backoff
;
1048 thread_add_timer_msec(zcf
->master
, zlog_5424_reconnect
,
1049 zcf
, zcf
->reconn_backoff_cur
,
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
;
1062 bool zlog_5424_apply_dst(struct zlog_cfg_5424
*zcf
)
1066 thread_cancel(&zcf
->t_reconnect
);
1068 if (zcf
->prio_min
!= ZLOG_DISABLED
)
1069 fd
= zlog_5424_open(zcf
, -1);
1071 frr_with_mutex (&zcf
->cfg_mtx
) {
1072 zlog_5424_cycle(zcf
, fd
);
1078 bool zlog_5424_apply_meta(struct zlog_cfg_5424
*zcf
)
1080 frr_with_mutex (&zcf
->cfg_mtx
) {
1082 zlog_5424_cycle(zcf
, zcf
->active
->fd
);
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
)
1094 ? atomic_load_explicit(&zcf
->active
->lost_msgs
,
1095 memory_order_relaxed
)
1098 *last_errno
= zcf
->active
? zcf
->active
->last_err
: 0;
1100 *stale_errno
= zcf
->active
? !zcf
->active
->current_err
: 0;
1101 if (err_ts
&& zcf
->active
)
1102 *err_ts
= zcf
->active
->last_err_ts
;
1105 struct rcu_close_rotate
{
1106 struct rcu_head_close head_close
;
1107 struct rcu_head head_self
;
1110 bool zlog_5424_rotate(struct zlog_cfg_5424
*zcf
)
1112 struct rcu_close_rotate
*rcr
;
1115 frr_with_mutex (&zcf
->cfg_mtx
) {
1119 thread_cancel(&zcf
->t_reconnect
);
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.
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
1131 fd
= zlog_5424_open(zcf
, zcf
->sock_type
);
1135 fd
= atomic_exchange_explicit(&zcf
->active
->fd
,
1137 memory_order_relaxed
);
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
);