]> git.proxmox.com Git - mirror_frr.git/blob - watchfrr/watchfrr.c
Merge pull request #2829 from donaldsharp/more_upstream
[mirror_frr.git] / watchfrr / watchfrr.c
1 /*
2 * Monitor status of frr daemons and restart if necessary.
3 *
4 * Copyright (C) 2004 Andrew J. Schorr
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22 #include <thread.h>
23 #include <log.h>
24 #include <network.h>
25 #include <sigevent.h>
26 #include <lib/version.h>
27 #include "command.h"
28 #include "memory_vty.h"
29 #include "libfrr.h"
30 #include "lib_errors.h"
31
32 #include <getopt.h>
33 #include <sys/un.h>
34 #include <sys/wait.h>
35 #include <memory.h>
36 #include <systemd.h>
37
38 #include "watchfrr.h"
39 #include "watchfrr_errors.h"
40
41 #ifndef MIN
42 #define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y))
43 #endif
44
45 /* Macros to help randomize timers. */
46 #define JITTER(X) ((random() % ((X)+1))-((X)/2))
47 #define FUZZY(X) ((X)+JITTER((X)/20))
48
49 #define DEFAULT_PERIOD 5
50 #define DEFAULT_TIMEOUT 90
51 #define DEFAULT_RESTART_TIMEOUT 20
52 #define DEFAULT_LOGLEVEL LOG_INFO
53 #define DEFAULT_MIN_RESTART 60
54 #define DEFAULT_MAX_RESTART 600
55
56 #define PING_TOKEN "PING"
57
58 /* Needs to be global, referenced somewhere inside libfrr. */
59 struct thread_master *master;
60 static char pidfile_default[256];
61
62 static bool watch_only = false;
63
64 typedef enum {
65 PHASE_NONE = 0,
66 PHASE_STOPS_PENDING,
67 PHASE_WAITING_DOWN,
68 PHASE_ZEBRA_RESTART_PENDING,
69 PHASE_WAITING_ZEBRA_UP
70 } restart_phase_t;
71
72 static const char *phase_str[] = {
73 "None",
74 "Stop jobs running",
75 "Waiting for other daemons to come down",
76 "Zebra restart job running",
77 "Waiting for zebra to come up",
78 "Start jobs running",
79 };
80
81 #define PHASE_TIMEOUT (3*gs.restart_timeout)
82
83 struct restart_info {
84 const char *name;
85 const char *what;
86 pid_t pid;
87 struct timeval time;
88 long interval;
89 struct thread *t_kill;
90 int kills;
91 };
92
93 static struct global_state {
94 restart_phase_t phase;
95 struct thread *t_phase_hanging;
96 const char *vtydir;
97 long period;
98 long timeout;
99 long restart_timeout;
100 long min_restart_interval;
101 long max_restart_interval;
102 struct daemon *daemons;
103 const char *restart_command;
104 const char *start_command;
105 const char *stop_command;
106 struct restart_info restart;
107 int loglevel;
108 struct daemon *special; /* points to zebra when doing phased restart */
109 int numdaemons;
110 int numpids;
111 int numdown; /* # of daemons that are not UP or UNRESPONSIVE */
112 } gs = {
113 .phase = PHASE_NONE,
114 .vtydir = frr_vtydir,
115 .period = 1000 * DEFAULT_PERIOD,
116 .timeout = DEFAULT_TIMEOUT,
117 .restart_timeout = DEFAULT_RESTART_TIMEOUT,
118 .loglevel = DEFAULT_LOGLEVEL,
119 .min_restart_interval = DEFAULT_MIN_RESTART,
120 .max_restart_interval = DEFAULT_MAX_RESTART,
121 };
122
123 typedef enum {
124 DAEMON_INIT,
125 DAEMON_DOWN,
126 DAEMON_CONNECTING,
127 DAEMON_UP,
128 DAEMON_UNRESPONSIVE
129 } daemon_state_t;
130
131 #define IS_UP(DMN) \
132 (((DMN)->state == DAEMON_UP) || ((DMN)->state == DAEMON_UNRESPONSIVE))
133
134 static const char *state_str[] = {
135 "Init", "Down", "Connecting", "Up", "Unresponsive",
136 };
137
138 struct daemon {
139 const char *name;
140 daemon_state_t state;
141 int fd;
142 struct timeval echo_sent;
143 unsigned int connect_tries;
144 struct thread *t_wakeup;
145 struct thread *t_read;
146 struct thread *t_write;
147 struct daemon *next;
148 struct restart_info restart;
149 };
150
151 #define OPTION_MINRESTART 2000
152 #define OPTION_MAXRESTART 2001
153 #define OPTION_DRY 2002
154
155 static const struct option longopts[] = {
156 {"daemon", no_argument, NULL, 'd'},
157 {"statedir", required_argument, NULL, 'S'},
158 {"loglevel", required_argument, NULL, 'l'},
159 {"interval", required_argument, NULL, 'i'},
160 {"timeout", required_argument, NULL, 't'},
161 {"restart-timeout", required_argument, NULL, 'T'},
162 {"restart", required_argument, NULL, 'r'},
163 {"start-command", required_argument, NULL, 's'},
164 {"kill-command", required_argument, NULL, 'k'},
165 {"dry", no_argument, NULL, OPTION_DRY},
166 {"min-restart-interval", required_argument, NULL, OPTION_MINRESTART},
167 {"max-restart-interval", required_argument, NULL, OPTION_MAXRESTART},
168 {"pid-file", required_argument, NULL, 'p'},
169 {"blank-string", required_argument, NULL, 'b'},
170 {"help", no_argument, NULL, 'h'},
171 {"version", no_argument, NULL, 'v'},
172 {NULL, 0, NULL, 0}};
173
174 static int try_connect(struct daemon *dmn);
175 static int wakeup_send_echo(struct thread *t_wakeup);
176 static void try_restart(struct daemon *dmn);
177 static void phase_check(void);
178
179 static const char *progname;
180 static void printhelp(FILE *target)
181 {
182 fprintf(target,
183 "Usage : %s [OPTION...] <daemon name> ...\n\n\
184 Watchdog program to monitor status of frr daemons and try to restart\n\
185 them if they are down or unresponsive. It determines whether a daemon is\n\
186 up based on whether it can connect to the daemon's vty unix stream socket.\n\
187 It then repeatedly sends echo commands over that socket to determine whether\n\
188 the daemon is responsive. If the daemon crashes, we will receive an EOF\n\
189 on the socket connection and know immediately that the daemon is down.\n\n\
190 The daemons to be monitored should be listed on the command line.\n\n\
191 In order to avoid attempting to restart the daemons in a fast loop,\n\
192 the -m and -M options allow you to control the minimum delay between\n\
193 restart commands. The minimum restart delay is recalculated each time\n\
194 a restart is attempted: if the time since the last restart attempt exceeds\n\
195 twice the -M value, then the restart delay is set to the -m value.\n\
196 Otherwise, the interval is doubled (but capped at the -M value).\n\n",
197 progname);
198
199 fprintf(target,
200 "Options:\n\
201 -d, --daemon Run in daemon mode. In this mode, error messages are sent\n\
202 to syslog instead of stdout.\n\
203 -S, --statedir Set the vty socket directory (default is %s)\n\
204 -l, --loglevel Set the logging level (default is %d).\n\
205 The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\
206 but it can be set higher than %d if extra-verbose debugging\n\
207 messages are desired.\n\
208 --min-restart-interval\n\
209 Set the minimum seconds to wait between invocations of daemon\n\
210 restart commands (default is %d).\n\
211 --max-restart-interval\n\
212 Set the maximum seconds to wait between invocations of daemon\n\
213 restart commands (default is %d).\n\
214 -i, --interval Set the status polling interval in seconds (default is %d)\n\
215 -t, --timeout Set the unresponsiveness timeout in seconds (default is %d)\n\
216 -T, --restart-timeout\n\
217 Set the restart (kill) timeout in seconds (default is %d).\n\
218 If any background jobs are still running after this much\n\
219 time has elapsed, they will be killed.\n\
220 -r, --restart Supply a Bourne shell command to use to restart a single\n\
221 daemon. The command string should include '%%s' where the\n\
222 name of the daemon should be substituted.\n\
223 -s, --start-command\n\
224 Supply a Bourne shell to command to use to start a single\n\
225 daemon. The command string should include '%%s' where the\n\
226 name of the daemon should be substituted.\n\
227 -k, --kill-command\n\
228 Supply a Bourne shell to command to use to stop a single\n\
229 daemon. The command string should include '%%s' where the\n\
230 name of the daemon should be substituted.\n\
231 --dry Do not start or restart anything, just log.\n\
232 -p, --pid-file Set process identifier file name\n\
233 (default is %s).\n\
234 -b, --blank-string\n\
235 When the supplied argument string is found in any of the\n\
236 various shell command arguments (-r, -s, or -k), replace\n\
237 it with a space. This is an ugly hack to circumvent problems\n\
238 passing command-line arguments with embedded spaces.\n\
239 -v, --version Print program version\n\
240 -h, --help Display this help and exit\n",
241 frr_vtydir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG,
242 DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, DEFAULT_PERIOD,
243 DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, pidfile_default);
244 }
245
246 static pid_t run_background(char *shell_cmd)
247 {
248 pid_t child;
249
250 switch (child = fork()) {
251 case -1:
252 flog_err_sys(LIB_ERR_SYSTEM_CALL,
253 "fork failed, cannot run command [%s]: %s",
254 shell_cmd, safe_strerror(errno));
255 return -1;
256 case 0:
257 /* Child process. */
258 /* Use separate process group so child processes can be killed
259 * easily. */
260 if (setpgid(0, 0) < 0)
261 zlog_warn("warning: setpgid(0,0) failed: %s",
262 safe_strerror(errno));
263 {
264 char shell[] = "sh";
265 char dashc[] = "-c";
266 char *const argv[4] = {shell, dashc, shell_cmd, NULL};
267 execv("/bin/sh", argv);
268 flog_err_sys(LIB_ERR_SYSTEM_CALL,
269 "execv(/bin/sh -c '%s') failed: %s",
270 shell_cmd, safe_strerror(errno));
271 _exit(127);
272 }
273 default:
274 /* Parent process: we will reap the child later. */
275 flog_err_sys(LIB_ERR_SYSTEM_CALL,
276 "Forked background command [pid %d]: %s",
277 (int)child, shell_cmd);
278 return child;
279 }
280 }
281
282 static struct timeval *time_elapsed(struct timeval *result,
283 const struct timeval *start_time)
284 {
285 gettimeofday(result, NULL);
286 result->tv_sec -= start_time->tv_sec;
287 result->tv_usec -= start_time->tv_usec;
288 while (result->tv_usec < 0) {
289 result->tv_usec += 1000000L;
290 result->tv_sec--;
291 }
292 return result;
293 }
294
295 static int restart_kill(struct thread *t_kill)
296 {
297 struct restart_info *restart = THREAD_ARG(t_kill);
298 struct timeval delay;
299
300 time_elapsed(&delay, &restart->time);
301 zlog_warn(
302 "Warning: %s %s child process %d still running after "
303 "%ld seconds, sending signal %d",
304 restart->what, restart->name, (int)restart->pid,
305 (long)delay.tv_sec, (restart->kills ? SIGKILL : SIGTERM));
306 kill(-restart->pid, (restart->kills ? SIGKILL : SIGTERM));
307 restart->kills++;
308 restart->t_kill = NULL;
309 thread_add_timer(master, restart_kill, restart, gs.restart_timeout,
310 &restart->t_kill);
311 return 0;
312 }
313
314 static struct restart_info *find_child(pid_t child)
315 {
316 struct daemon *dmn;
317 for (dmn = gs.daemons; dmn; dmn = dmn->next) {
318 if (dmn->restart.pid == child)
319 return &dmn->restart;
320 }
321 return NULL;
322 }
323
324 static void sigchild(void)
325 {
326 pid_t child;
327 int status;
328 const char *name;
329 const char *what;
330 struct restart_info *restart;
331
332 switch (child = waitpid(-1, &status, WNOHANG)) {
333 case -1:
334 flog_err_sys(LIB_ERR_SYSTEM_CALL, "waitpid failed: %s",
335 safe_strerror(errno));
336 return;
337 case 0:
338 zlog_warn("SIGCHLD received, but waitpid did not reap a child");
339 return;
340 }
341
342 if (child == integrated_write_pid) {
343 integrated_write_sigchld(status);
344 return;
345 }
346
347 if ((restart = find_child(child)) != NULL) {
348 name = restart->name;
349 what = restart->what;
350 restart->pid = 0;
351 gs.numpids--;
352 thread_cancel(restart->t_kill);
353 restart->t_kill = NULL;
354 /* Update restart time to reflect the time the command
355 * completed. */
356 gettimeofday(&restart->time, NULL);
357 } else {
358 flog_err_sys(
359 LIB_ERR_SYSTEM_CALL,
360 "waitpid returned status for an unknown child process %d",
361 (int)child);
362 name = "(unknown)";
363 what = "background";
364 }
365 if (WIFSTOPPED(status))
366 zlog_warn("warning: %s %s process %d is stopped", what, name,
367 (int)child);
368 else if (WIFSIGNALED(status))
369 zlog_warn("%s %s process %d terminated due to signal %d", what,
370 name, (int)child, WTERMSIG(status));
371 else if (WIFEXITED(status)) {
372 if (WEXITSTATUS(status) != 0)
373 zlog_warn(
374 "%s %s process %d exited with non-zero status %d",
375 what, name, (int)child, WEXITSTATUS(status));
376 else
377 zlog_debug("%s %s process %d exited normally", what,
378 name, (int)child);
379 } else
380 flog_err_sys(
381 LIB_ERR_SYSTEM_CALL,
382 "cannot interpret %s %s process %d wait status 0x%x",
383 what, name, (int)child, status);
384 phase_check();
385 }
386
387 static int run_job(struct restart_info *restart, const char *cmdtype,
388 const char *command, int force, int update_interval)
389 {
390 struct timeval delay;
391
392 if (gs.loglevel > LOG_DEBUG + 1)
393 zlog_debug("attempting to %s %s", cmdtype, restart->name);
394
395 if (restart->pid) {
396 if (gs.loglevel > LOG_DEBUG + 1)
397 zlog_debug(
398 "cannot %s %s, previous pid %d still running",
399 cmdtype, restart->name, (int)restart->pid);
400 return -1;
401 }
402
403 /* Note: time_elapsed test must come before the force test, since we
404 need
405 to make sure that delay is initialized for use below in updating the
406 restart interval. */
407 if ((time_elapsed(&delay, &restart->time)->tv_sec < restart->interval)
408 && !force) {
409 if (gs.loglevel > LOG_DEBUG + 1)
410 zlog_debug(
411 "postponing %s %s: "
412 "elapsed time %ld < retry interval %ld",
413 cmdtype, restart->name, (long)delay.tv_sec,
414 restart->interval);
415 return -1;
416 }
417
418 gettimeofday(&restart->time, NULL);
419 restart->kills = 0;
420 {
421 char cmd[strlen(command) + strlen(restart->name) + 1];
422 snprintf(cmd, sizeof(cmd), command, restart->name);
423 if ((restart->pid = run_background(cmd)) > 0) {
424 restart->t_kill = NULL;
425 thread_add_timer(master, restart_kill, restart,
426 gs.restart_timeout, &restart->t_kill);
427 restart->what = cmdtype;
428 gs.numpids++;
429 } else
430 restart->pid = 0;
431 }
432
433 /* Calculate the new restart interval. */
434 if (update_interval) {
435 if (delay.tv_sec > 2 * gs.max_restart_interval)
436 restart->interval = gs.min_restart_interval;
437 else if ((restart->interval *= 2) > gs.max_restart_interval)
438 restart->interval = gs.max_restart_interval;
439 if (gs.loglevel > LOG_DEBUG + 1)
440 zlog_debug("restart %s interval is now %ld",
441 restart->name, restart->interval);
442 }
443 return restart->pid;
444 }
445
446 #define SET_READ_HANDLER(DMN) \
447 do { \
448 (DMN)->t_read = NULL; \
449 thread_add_read(master, handle_read, (DMN), (DMN)->fd, \
450 &(DMN)->t_read); \
451 } while (0);
452
453 #define SET_WAKEUP_DOWN(DMN) \
454 do { \
455 (DMN)->t_wakeup = NULL; \
456 thread_add_timer_msec(master, wakeup_down, (DMN), \
457 FUZZY(gs.period), &(DMN)->t_wakeup); \
458 } while (0);
459
460 #define SET_WAKEUP_UNRESPONSIVE(DMN) \
461 do { \
462 (DMN)->t_wakeup = NULL; \
463 thread_add_timer_msec(master, wakeup_unresponsive, (DMN), \
464 FUZZY(gs.period), &(DMN)->t_wakeup); \
465 } while (0);
466
467 #define SET_WAKEUP_ECHO(DMN) \
468 do { \
469 (DMN)->t_wakeup = NULL; \
470 thread_add_timer_msec(master, wakeup_send_echo, (DMN), \
471 FUZZY(gs.period), &(DMN)->t_wakeup); \
472 } while (0);
473
474 static int wakeup_down(struct thread *t_wakeup)
475 {
476 struct daemon *dmn = THREAD_ARG(t_wakeup);
477
478 dmn->t_wakeup = NULL;
479 if (try_connect(dmn) < 0)
480 SET_WAKEUP_DOWN(dmn);
481 if ((dmn->connect_tries > 1) && (dmn->state != DAEMON_UP))
482 try_restart(dmn);
483 return 0;
484 }
485
486 static int wakeup_init(struct thread *t_wakeup)
487 {
488 struct daemon *dmn = THREAD_ARG(t_wakeup);
489
490 dmn->t_wakeup = NULL;
491 if (try_connect(dmn) < 0) {
492 SET_WAKEUP_DOWN(dmn);
493 flog_err(WATCHFRR_ERR_CONNECTION,
494 "%s state -> down : initial connection attempt failed",
495 dmn->name);
496 dmn->state = DAEMON_DOWN;
497 }
498 return 0;
499 }
500
501 static void daemon_down(struct daemon *dmn, const char *why)
502 {
503 if (IS_UP(dmn) || (dmn->state == DAEMON_INIT))
504 flog_err(WATCHFRR_ERR_CONNECTION,
505 "%s state -> down : %s", dmn->name, why);
506 else if (gs.loglevel > LOG_DEBUG)
507 zlog_debug("%s still down : %s", dmn->name, why);
508 if (IS_UP(dmn))
509 gs.numdown++;
510 dmn->state = DAEMON_DOWN;
511 if (dmn->fd >= 0) {
512 close(dmn->fd);
513 dmn->fd = -1;
514 }
515 THREAD_OFF(dmn->t_read);
516 THREAD_OFF(dmn->t_write);
517 THREAD_OFF(dmn->t_wakeup);
518 if (try_connect(dmn) < 0)
519 SET_WAKEUP_DOWN(dmn);
520 phase_check();
521 }
522
523 static int handle_read(struct thread *t_read)
524 {
525 struct daemon *dmn = THREAD_ARG(t_read);
526 static const char resp[sizeof(PING_TOKEN) + 4] = PING_TOKEN "\n";
527 char buf[sizeof(resp) + 100];
528 ssize_t rc;
529 struct timeval delay;
530
531 dmn->t_read = NULL;
532 if ((rc = read(dmn->fd, buf, sizeof(buf))) < 0) {
533 char why[100];
534
535 if (ERRNO_IO_RETRY(errno)) {
536 /* Pretend it never happened. */
537 SET_READ_HANDLER(dmn);
538 return 0;
539 }
540 snprintf(why, sizeof(why), "unexpected read error: %s",
541 safe_strerror(errno));
542 daemon_down(dmn, why);
543 return 0;
544 }
545 if (rc == 0) {
546 daemon_down(dmn, "read returned EOF");
547 return 0;
548 }
549 if (!dmn->echo_sent.tv_sec) {
550 char why[sizeof(buf) + 100];
551 snprintf(why, sizeof(why),
552 "unexpected read returns %d bytes: %.*s", (int)rc,
553 (int)rc, buf);
554 daemon_down(dmn, why);
555 return 0;
556 }
557
558 /* We are expecting an echo response: is there any chance that the
559 response would not be returned entirely in the first read? That
560 seems inconceivable... */
561 if ((rc != sizeof(resp)) || memcmp(buf, resp, sizeof(resp))) {
562 char why[100 + sizeof(buf)];
563 snprintf(why, sizeof(why),
564 "read returned bad echo response of %d bytes "
565 "(expecting %u): %.*s",
566 (int)rc, (unsigned int)sizeof(resp), (int)rc, buf);
567 daemon_down(dmn, why);
568 return 0;
569 }
570
571 time_elapsed(&delay, &dmn->echo_sent);
572 dmn->echo_sent.tv_sec = 0;
573 if (dmn->state == DAEMON_UNRESPONSIVE) {
574 if (delay.tv_sec < gs.timeout) {
575 dmn->state = DAEMON_UP;
576 zlog_warn(
577 "%s state -> up : echo response received after %ld.%06ld "
578 "seconds",
579 dmn->name, (long)delay.tv_sec,
580 (long)delay.tv_usec);
581 } else
582 zlog_warn(
583 "%s: slow echo response finally received after %ld.%06ld "
584 "seconds",
585 dmn->name, (long)delay.tv_sec,
586 (long)delay.tv_usec);
587 } else if (gs.loglevel > LOG_DEBUG + 1)
588 zlog_debug("%s: echo response received after %ld.%06ld seconds",
589 dmn->name, (long)delay.tv_sec, (long)delay.tv_usec);
590
591 SET_READ_HANDLER(dmn);
592 if (dmn->t_wakeup)
593 thread_cancel(dmn->t_wakeup);
594 SET_WAKEUP_ECHO(dmn);
595
596 return 0;
597 }
598
599 /*
600 * Wait till we notice that all daemons are ready before
601 * we send we are ready to systemd
602 */
603 static void daemon_send_ready(void)
604 {
605 static int sent = 0;
606 if (!sent && gs.numdown == 0) {
607 FILE *fp;
608
609 fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w");
610 if (fp)
611 fclose(fp);
612 #if defined HAVE_SYSTEMD
613 zlog_notice(
614 "Watchfrr: Notifying Systemd we are up and running");
615 systemd_send_started(master, 0);
616 #endif
617 sent = 1;
618 }
619 }
620
621 static void daemon_up(struct daemon *dmn, const char *why)
622 {
623 dmn->state = DAEMON_UP;
624 gs.numdown--;
625 dmn->connect_tries = 0;
626 zlog_notice("%s state -> up : %s", dmn->name, why);
627 daemon_send_ready();
628 SET_WAKEUP_ECHO(dmn);
629 phase_check();
630 }
631
632 static int check_connect(struct thread *t_write)
633 {
634 struct daemon *dmn = THREAD_ARG(t_write);
635 int sockerr;
636 socklen_t reslen = sizeof(sockerr);
637
638 dmn->t_write = NULL;
639 if (getsockopt(dmn->fd, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &reslen)
640 < 0) {
641 zlog_warn("%s: check_connect: getsockopt failed: %s", dmn->name,
642 safe_strerror(errno));
643 daemon_down(dmn,
644 "getsockopt failed checking connection success");
645 return 0;
646 }
647 if ((reslen == sizeof(sockerr)) && sockerr) {
648 char why[100];
649 snprintf(
650 why, sizeof(why),
651 "getsockopt reports that connection attempt failed: %s",
652 safe_strerror(sockerr));
653 daemon_down(dmn, why);
654 return 0;
655 }
656
657 daemon_up(dmn, "delayed connect succeeded");
658 return 0;
659 }
660
661 static int wakeup_connect_hanging(struct thread *t_wakeup)
662 {
663 struct daemon *dmn = THREAD_ARG(t_wakeup);
664 char why[100];
665
666 dmn->t_wakeup = NULL;
667 snprintf(why, sizeof(why),
668 "connection attempt timed out after %ld seconds", gs.timeout);
669 daemon_down(dmn, why);
670 return 0;
671 }
672
673 /* Making connection to protocol daemon. */
674 static int try_connect(struct daemon *dmn)
675 {
676 int sock;
677 struct sockaddr_un addr;
678 socklen_t len;
679
680 if (gs.loglevel > LOG_DEBUG + 1)
681 zlog_debug("%s: attempting to connect", dmn->name);
682 dmn->connect_tries++;
683
684 memset(&addr, 0, sizeof(struct sockaddr_un));
685 addr.sun_family = AF_UNIX;
686 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s.vty", gs.vtydir,
687 dmn->name);
688 #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
689 len = addr.sun_len = SUN_LEN(&addr);
690 #else
691 len = sizeof(addr.sun_family) + strlen(addr.sun_path);
692 #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
693
694 /* Quick check to see if we might succeed before we go to the trouble
695 of creating a socket. */
696 if (access(addr.sun_path, W_OK) < 0) {
697 if (errno != ENOENT)
698 flog_err_sys(LIB_ERR_SYSTEM_CALL,
699 "%s: access to socket %s denied: %s",
700 dmn->name, addr.sun_path,
701 safe_strerror(errno));
702 return -1;
703 }
704
705 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
706 flog_err_sys(LIB_ERR_SOCKET, "%s(%s): cannot make socket: %s",
707 __func__, addr.sun_path, safe_strerror(errno));
708 return -1;
709 }
710
711 if (set_nonblocking(sock) < 0 || set_cloexec(sock) < 0) {
712 flog_err_sys(LIB_ERR_SYSTEM_CALL,
713 "%s(%s): set_nonblocking/cloexec(%d) failed",
714 __func__, addr.sun_path, sock);
715 close(sock);
716 return -1;
717 }
718
719 if (connect(sock, (struct sockaddr *)&addr, len) < 0) {
720 if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
721 if (gs.loglevel > LOG_DEBUG)
722 zlog_debug("%s(%s): connect failed: %s",
723 __func__, addr.sun_path,
724 safe_strerror(errno));
725 close(sock);
726 return -1;
727 }
728 if (gs.loglevel > LOG_DEBUG)
729 zlog_debug("%s: connection in progress", dmn->name);
730 dmn->state = DAEMON_CONNECTING;
731 dmn->fd = sock;
732 dmn->t_write = NULL;
733 thread_add_write(master, check_connect, dmn, dmn->fd,
734 &dmn->t_write);
735 dmn->t_wakeup = NULL;
736 thread_add_timer(master, wakeup_connect_hanging, dmn,
737 gs.timeout, &dmn->t_wakeup);
738 SET_READ_HANDLER(dmn);
739 return 0;
740 }
741
742 dmn->fd = sock;
743 SET_READ_HANDLER(dmn);
744 daemon_up(dmn, "connect succeeded");
745 return 1;
746 }
747
748 static int phase_hanging(struct thread *t_hanging)
749 {
750 gs.t_phase_hanging = NULL;
751 flog_err(WATCHFRR_ERR_CONNECTION,
752 "Phase [%s] hanging for %ld seconds, aborting phased restart",
753 phase_str[gs.phase], PHASE_TIMEOUT);
754 gs.phase = PHASE_NONE;
755 return 0;
756 }
757
758 static void set_phase(restart_phase_t new_phase)
759 {
760 gs.phase = new_phase;
761 if (gs.t_phase_hanging)
762 thread_cancel(gs.t_phase_hanging);
763 gs.t_phase_hanging = NULL;
764 thread_add_timer(master, phase_hanging, NULL, PHASE_TIMEOUT,
765 &gs.t_phase_hanging);
766 }
767
768 static void phase_check(void)
769 {
770 switch (gs.phase) {
771 case PHASE_NONE:
772 break;
773 case PHASE_STOPS_PENDING:
774 if (gs.numpids)
775 break;
776 zlog_info(
777 "Phased restart: all routing daemon stop jobs have completed.");
778 set_phase(PHASE_WAITING_DOWN);
779
780 /*FALLTHRU*/
781 case PHASE_WAITING_DOWN:
782 if (gs.numdown + IS_UP(gs.special) < gs.numdaemons)
783 break;
784 zlog_info("Phased restart: all routing daemons now down.");
785 run_job(&gs.special->restart, "restart", gs.restart_command, 1,
786 1);
787 set_phase(PHASE_ZEBRA_RESTART_PENDING);
788
789 /*FALLTHRU*/
790 case PHASE_ZEBRA_RESTART_PENDING:
791 if (gs.special->restart.pid)
792 break;
793 zlog_info("Phased restart: %s restart job completed.",
794 gs.special->name);
795 set_phase(PHASE_WAITING_ZEBRA_UP);
796
797 /*FALLTHRU*/
798 case PHASE_WAITING_ZEBRA_UP:
799 if (!IS_UP(gs.special))
800 break;
801 zlog_info("Phased restart: %s is now up.", gs.special->name);
802 {
803 struct daemon *dmn;
804 for (dmn = gs.daemons; dmn; dmn = dmn->next) {
805 if (dmn != gs.special)
806 run_job(&dmn->restart, "start",
807 gs.start_command, 1, 0);
808 }
809 }
810 gs.phase = PHASE_NONE;
811 THREAD_OFF(gs.t_phase_hanging);
812 zlog_notice("Phased global restart has completed.");
813 break;
814 }
815 }
816
817 static void try_restart(struct daemon *dmn)
818 {
819 if (watch_only)
820 return;
821
822 if (dmn != gs.special) {
823 if ((gs.special->state == DAEMON_UP)
824 && (gs.phase == PHASE_NONE))
825 run_job(&dmn->restart, "restart", gs.restart_command, 0,
826 1);
827 else
828 zlog_debug(
829 "%s: postponing restart attempt because master %s daemon "
830 "not up [%s], or phased restart in progress",
831 dmn->name, gs.special->name,
832 state_str[gs.special->state]);
833 return;
834 }
835
836 if ((gs.phase != PHASE_NONE) || gs.numpids) {
837 if (gs.loglevel > LOG_DEBUG + 1)
838 zlog_debug(
839 "postponing phased global restart: restart already in "
840 "progress [%s], or outstanding child processes [%d]",
841 phase_str[gs.phase], gs.numpids);
842 return;
843 }
844 /* Is it too soon for a restart? */
845 {
846 struct timeval delay;
847 if (time_elapsed(&delay, &gs.special->restart.time)->tv_sec
848 < gs.special->restart.interval) {
849 if (gs.loglevel > LOG_DEBUG + 1)
850 zlog_debug(
851 "postponing phased global restart: "
852 "elapsed time %ld < retry interval %ld",
853 (long)delay.tv_sec,
854 gs.special->restart.interval);
855 return;
856 }
857 }
858 run_job(&gs.restart, "restart", gs.restart_command, 0, 1);
859 }
860
861 static int wakeup_unresponsive(struct thread *t_wakeup)
862 {
863 struct daemon *dmn = THREAD_ARG(t_wakeup);
864
865 dmn->t_wakeup = NULL;
866 if (dmn->state != DAEMON_UNRESPONSIVE)
867 flog_err(WATCHFRR_ERR_CONNECTION,
868 "%s: no longer unresponsive (now %s), "
869 "wakeup should have been cancelled!",
870 dmn->name, state_str[dmn->state]);
871 else {
872 SET_WAKEUP_UNRESPONSIVE(dmn);
873 try_restart(dmn);
874 }
875 return 0;
876 }
877
878 static int wakeup_no_answer(struct thread *t_wakeup)
879 {
880 struct daemon *dmn = THREAD_ARG(t_wakeup);
881
882 dmn->t_wakeup = NULL;
883 dmn->state = DAEMON_UNRESPONSIVE;
884 flog_err(WATCHFRR_ERR_CONNECTION,
885 "%s state -> unresponsive : no response yet to ping "
886 "sent %ld seconds ago",
887 dmn->name, gs.timeout);
888 SET_WAKEUP_UNRESPONSIVE(dmn);
889 try_restart(dmn);
890 return 0;
891 }
892
893 static int wakeup_send_echo(struct thread *t_wakeup)
894 {
895 static const char echocmd[] = "echo " PING_TOKEN;
896 ssize_t rc;
897 struct daemon *dmn = THREAD_ARG(t_wakeup);
898
899 dmn->t_wakeup = NULL;
900 if (((rc = write(dmn->fd, echocmd, sizeof(echocmd))) < 0)
901 || ((size_t)rc != sizeof(echocmd))) {
902 char why[100 + sizeof(echocmd)];
903 snprintf(why, sizeof(why),
904 "write '%s' returned %d instead of %u", echocmd,
905 (int)rc, (unsigned int)sizeof(echocmd));
906 daemon_down(dmn, why);
907 } else {
908 gettimeofday(&dmn->echo_sent, NULL);
909 dmn->t_wakeup = NULL;
910 thread_add_timer(master, wakeup_no_answer, dmn, gs.timeout,
911 &dmn->t_wakeup);
912 }
913 return 0;
914 }
915
916 bool check_all_up(void)
917 {
918 struct daemon *dmn;
919
920 for (dmn = gs.daemons; dmn; dmn = dmn->next)
921 if (dmn->state != DAEMON_UP)
922 return false;
923 return true;
924 }
925
926 static void sigint(void)
927 {
928 zlog_notice("Terminating on signal");
929 systemd_send_stopping();
930 exit(0);
931 }
932
933 static int valid_command(const char *cmd)
934 {
935 char *p;
936
937 return ((p = strchr(cmd, '%')) != NULL) && (*(p + 1) == 's')
938 && !strchr(p + 1, '%');
939 }
940
941 /* This is an ugly hack to circumvent problems with passing command-line
942 arguments that contain spaces. The fix is to use a configuration file. */
943 static char *translate_blanks(const char *cmd, const char *blankstr)
944 {
945 char *res;
946 char *p;
947 size_t bslen = strlen(blankstr);
948
949 if (!(res = strdup(cmd))) {
950 perror("strdup");
951 exit(1);
952 }
953 while ((p = strstr(res, blankstr)) != NULL) {
954 *p = ' ';
955 if (bslen != 1)
956 memmove(p + 1, p + bslen, strlen(p + bslen) + 1);
957 }
958 return res;
959 }
960
961 struct zebra_privs_t watchfrr_privs = {
962 #ifdef VTY_GROUP
963 .vty_group = VTY_GROUP,
964 #endif
965 };
966
967 static struct quagga_signal_t watchfrr_signals[] = {
968 {
969 .signal = SIGINT,
970 .handler = sigint,
971 },
972 {
973 .signal = SIGTERM,
974 .handler = sigint,
975 },
976 {
977 .signal = SIGCHLD,
978 .handler = sigchild,
979 },
980 };
981
982 FRR_DAEMON_INFO(watchfrr, WATCHFRR,
983 .flags = FRR_NO_PRIVSEP | FRR_NO_TCPVTY | FRR_LIMITED_CLI
984 | FRR_NO_CFG_PID_DRY | FRR_NO_ZCLIENT,
985
986 .printhelp = printhelp,
987 .copyright = "Copyright 2004 Andrew J. Schorr",
988
989 .signals = watchfrr_signals,
990 .n_signals = array_size(watchfrr_signals),
991
992 .privs = &watchfrr_privs, )
993
994 #define DEPRECATED_OPTIONS "aAezR:"
995
996 int main(int argc, char **argv)
997 {
998 int opt;
999 const char *pidfile = pidfile_default;
1000 const char *special = "zebra";
1001 const char *blankstr = NULL;
1002
1003 snprintf(pidfile_default, sizeof(pidfile_default), "%s/watchfrr.pid",
1004 frr_vtydir);
1005
1006 frr_preinit(&watchfrr_di, argc, argv);
1007 progname = watchfrr_di.progname;
1008
1009 frr_opt_add("b:dk:l:i:p:r:S:s:t:T:" DEPRECATED_OPTIONS, longopts, "");
1010
1011 gs.restart.name = "all";
1012 while ((opt = frr_getopt(argc, argv, NULL)) != EOF) {
1013 if (opt && opt < 128 && strchr(DEPRECATED_OPTIONS, opt)) {
1014 fprintf(stderr,
1015 "The -%c option no longer exists.\n"
1016 "Please refer to the watchfrr(8) man page.\n",
1017 opt);
1018 exit(1);
1019 }
1020
1021 switch (opt) {
1022 case 0:
1023 break;
1024 case 'b':
1025 blankstr = optarg;
1026 break;
1027 case OPTION_DRY:
1028 watch_only = true;
1029 break;
1030 case 'k':
1031 if (!valid_command(optarg)) {
1032 fprintf(stderr,
1033 "Invalid kill command, must contain '%%s': %s\n",
1034 optarg);
1035 frr_help_exit(1);
1036 }
1037 gs.stop_command = optarg;
1038 break;
1039 case 'l': {
1040 char garbage[3];
1041 if ((sscanf(optarg, "%d%1s", &gs.loglevel, garbage)
1042 != 1)
1043 || (gs.loglevel < LOG_EMERG)) {
1044 fprintf(stderr,
1045 "Invalid loglevel argument: %s\n",
1046 optarg);
1047 frr_help_exit(1);
1048 }
1049 } break;
1050 case OPTION_MINRESTART: {
1051 char garbage[3];
1052 if ((sscanf(optarg, "%ld%1s", &gs.min_restart_interval,
1053 garbage)
1054 != 1)
1055 || (gs.min_restart_interval < 0)) {
1056 fprintf(stderr,
1057 "Invalid min_restart_interval argument: %s\n",
1058 optarg);
1059 frr_help_exit(1);
1060 }
1061 } break;
1062 case OPTION_MAXRESTART: {
1063 char garbage[3];
1064 if ((sscanf(optarg, "%ld%1s", &gs.max_restart_interval,
1065 garbage)
1066 != 1)
1067 || (gs.max_restart_interval < 0)) {
1068 fprintf(stderr,
1069 "Invalid max_restart_interval argument: %s\n",
1070 optarg);
1071 frr_help_exit(1);
1072 }
1073 } break;
1074 case 'i': {
1075 char garbage[3];
1076 int period;
1077 if ((sscanf(optarg, "%d%1s", &period, garbage) != 1)
1078 || (gs.period < 1)) {
1079 fprintf(stderr,
1080 "Invalid interval argument: %s\n",
1081 optarg);
1082 frr_help_exit(1);
1083 }
1084 gs.period = 1000 * period;
1085 } break;
1086 case 'p':
1087 pidfile = optarg;
1088 break;
1089 case 'r':
1090 if (!valid_command(optarg)) {
1091 fprintf(stderr,
1092 "Invalid restart command, must contain '%%s': %s\n",
1093 optarg);
1094 frr_help_exit(1);
1095 }
1096 gs.restart_command = optarg;
1097 break;
1098 case 's':
1099 if (!valid_command(optarg)) {
1100 fprintf(stderr,
1101 "Invalid start command, must contain '%%s': %s\n",
1102 optarg);
1103 frr_help_exit(1);
1104 }
1105 gs.start_command = optarg;
1106 break;
1107 case 'S':
1108 gs.vtydir = optarg;
1109 break;
1110 case 't': {
1111 char garbage[3];
1112 if ((sscanf(optarg, "%ld%1s", &gs.timeout, garbage)
1113 != 1)
1114 || (gs.timeout < 1)) {
1115 fprintf(stderr,
1116 "Invalid timeout argument: %s\n",
1117 optarg);
1118 frr_help_exit(1);
1119 }
1120 } break;
1121 case 'T': {
1122 char garbage[3];
1123 if ((sscanf(optarg, "%ld%1s", &gs.restart_timeout,
1124 garbage)
1125 != 1)
1126 || (gs.restart_timeout < 1)) {
1127 fprintf(stderr,
1128 "Invalid restart timeout argument: %s\n",
1129 optarg);
1130 frr_help_exit(1);
1131 }
1132 } break;
1133 default:
1134 fputs("Invalid option.\n", stderr);
1135 frr_help_exit(1);
1136 }
1137 }
1138
1139 if (watch_only
1140 && (gs.start_command || gs.stop_command || gs.restart_command)) {
1141 fputs("Options -r/-s/-k are not used when --dry is active.\n",
1142 stderr);
1143 }
1144 if (!watch_only
1145 && (!gs.restart_command || !gs.start_command || !gs.stop_command)) {
1146 fprintf(stderr,
1147 "Options -s (start), -k (kill), and -r (restart) are required.\n");
1148 frr_help_exit(1);
1149 }
1150
1151 if (blankstr) {
1152 if (gs.restart_command)
1153 gs.restart_command =
1154 translate_blanks(gs.restart_command, blankstr);
1155 if (gs.start_command)
1156 gs.start_command =
1157 translate_blanks(gs.start_command, blankstr);
1158 if (gs.stop_command)
1159 gs.stop_command =
1160 translate_blanks(gs.stop_command, blankstr);
1161 }
1162
1163 gs.restart.interval = gs.min_restart_interval;
1164
1165 master = frr_init();
1166 watchfrr_error_init();
1167
1168 zlog_set_level(ZLOG_DEST_MONITOR, ZLOG_DISABLED);
1169 if (watchfrr_di.daemon_mode) {
1170 zlog_set_level(ZLOG_DEST_SYSLOG, MIN(gs.loglevel, LOG_DEBUG));
1171 if (daemon(0, 0) < 0) {
1172 fprintf(stderr, "Watchfrr daemon failed: %s",
1173 strerror(errno));
1174 exit(1);
1175 }
1176 } else
1177 zlog_set_level(ZLOG_DEST_STDOUT, MIN(gs.loglevel, LOG_DEBUG));
1178
1179 watchfrr_vty_init();
1180
1181 frr_vty_serv();
1182
1183 {
1184 int i;
1185 struct daemon *tail = NULL;
1186
1187 for (i = optind; i < argc; i++) {
1188 struct daemon *dmn;
1189
1190 if (!(dmn = (struct daemon *)calloc(1, sizeof(*dmn)))) {
1191 fprintf(stderr, "calloc(1,%u) failed: %s\n",
1192 (unsigned int)sizeof(*dmn),
1193 safe_strerror(errno));
1194 return 1;
1195 }
1196 dmn->name = dmn->restart.name = argv[i];
1197 dmn->state = DAEMON_INIT;
1198 gs.numdaemons++;
1199 gs.numdown++;
1200 dmn->fd = -1;
1201 dmn->t_wakeup = NULL;
1202 thread_add_timer_msec(master, wakeup_init, dmn,
1203 100 + (random() % 900),
1204 &dmn->t_wakeup);
1205 dmn->restart.interval = gs.min_restart_interval;
1206 if (tail)
1207 tail->next = dmn;
1208 else
1209 gs.daemons = dmn;
1210 tail = dmn;
1211
1212 if (!strcmp(dmn->name, special))
1213 gs.special = dmn;
1214 }
1215 }
1216 if (!gs.daemons) {
1217 fputs("Must specify one or more daemons to monitor.\n", stderr);
1218 frr_help_exit(1);
1219 }
1220 if (!watch_only && !gs.special) {
1221 fprintf(stderr, "\"%s\" daemon must be in daemon list\n",
1222 special);
1223 frr_help_exit(1);
1224 }
1225
1226 /* Make sure we're not already running. */
1227 pid_output(pidfile);
1228
1229 /* Announce which daemons are being monitored. */
1230 {
1231 struct daemon *dmn;
1232 size_t len = 0;
1233
1234 for (dmn = gs.daemons; dmn; dmn = dmn->next)
1235 len += strlen(dmn->name) + 1;
1236
1237 {
1238 char buf[len + 1];
1239 char *p = buf;
1240
1241 for (dmn = gs.daemons; dmn; dmn = dmn->next) {
1242 if (p != buf)
1243 *p++ = ' ';
1244 strcpy(p, dmn->name);
1245 p += strlen(p);
1246 }
1247 zlog_notice("%s %s watching [%s]%s", progname,
1248 FRR_VERSION, buf,
1249 watch_only ? ", monitor mode" : "");
1250 }
1251 }
1252
1253 {
1254 struct thread thread;
1255
1256 while (thread_fetch(master, &thread))
1257 thread_call(&thread);
1258 }
1259
1260 systemd_send_stopping();
1261 /* Not reached. */
1262 return 0;
1263 }