2 * fateshare.c - skeleton vpp engine plug-in
4 * Copyright (c) 2022 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vppinfra/unix.h>
21 #include <fateshare/fateshare.h>
23 #include <vlibapi/api.h>
24 #include <vlibmemory/api.h>
25 #include <vpp/app/version.h>
28 #include <sys/types.h>
31 #include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
33 #include <sys/procctl.h>
34 #endif /* __linux__ */
37 fateshare_main_t fateshare_main;
39 /* Action function shared between message handler and debug CLI */
42 child_handler (int sig)
46 fateshare_main_t *kmp = &fateshare_main;
48 while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
50 if (pid == kmp->monitor_pid)
52 clib_warning ("Monitor child %d exited with status %d!", pid,
54 kmp->vlib_main->main_loop_exit_now = 1;
58 clib_warning ("child %d exited with status %d!", pid, status);
64 launch_monitor (fateshare_main_t *kmp)
66 clib_error_t *error = 0;
67 pid_t ppid_before_fork = getpid ();
72 error = clib_error_return (0, "can not fork");
75 clib_warning ("fateshare about to launch monitor %v.", kmp->monitor_cmd);
77 open ((char *) kmp->monitor_logfile, O_APPEND | O_RDWR | O_CREAT, 0777);
80 error = clib_error_return (0, "can not open log file");
86 kmp->monitor_pid = cpid;
95 int r = prctl (PR_SET_PDEATHSIG, SIGTERM);
104 r = procctl (P_PID, 0, PROC_PDEATHSIG_CTL, &s);
110 #endif /* __linux__ */
111 pid_t current_ppid = getppid ();
112 if (current_ppid != ppid_before_fork)
114 fprintf (stderr, "parent pid changed while starting (%d => %d)\n",
115 ppid_before_fork, current_ppid);
116 if (current_ppid == 1)
118 fprintf (stderr, "exiting.\n");
123 int r1 = setpgid (getpid (), 0);
126 perror ("setpgid error");
130 u8 *scmd = format (0, "%v\0", kmp->monitor_cmd);
131 u8 *logfile_base = format (0, "%v\0", kmp->monitor_logfile);
139 fd = open ("/dev/null", O_RDONLY);
146 char *ppid_str = (char *) format (0, "%lld\0", current_ppid);
149 vec_validate (argv, vec_len (kmp->commands) + 3 - 1);
150 argv[0] = (void *) scmd;
152 argv[2] = (char *) logfile_base;
154 vec_foreach_index (i, kmp->commands)
156 argv[3 + i] = (char *) kmp->commands[i];
159 int res = execv (argv[0], argv);
160 clib_warning ("ERROR during execve: %d", res);
170 static clib_error_t *
171 fateshare_config (vlib_main_t *vm, unformat_input_t *input)
173 fateshare_main_t *fmp = &fateshare_main;
175 u8 **new_command = 0;
176 clib_error_t *error = 0;
178 /* unix config may make vpp fork, we want to run after that. */
179 if ((error = vlib_call_config_function (vm, unix_config)))
183 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
185 if (unformat (input, "monitor %s", &fmp->monitor_cmd))
187 clib_warning ("setting monitor to %v", fmp->monitor_cmd);
189 else if (unformat (input, "logfile %s", &fmp->monitor_logfile))
191 clib_warning ("setting logfile to %v", fmp->monitor_logfile);
193 else if (unformat (input, "command %s", &command))
195 vec_add2 (fmp->commands, new_command, 1);
196 *new_command = command;
199 return clib_error_return (0, "unknown input `%U'",
200 format_unformat_error, input);
203 vec_add2 (fmp->commands, new_command, 1);
206 /* Establish handler. */
208 sigemptyset (&sa.sa_mask);
210 sa.sa_handler = child_handler;
212 sigaction (SIGCHLD, &sa, NULL);
214 if (fmp->monitor_cmd == 0)
219 /* find executable path */
220 path = os_get_exec_path ();
223 return clib_error_return (
224 0, "could not get exec path - set monitor manually");
226 /* add null termination */
230 if ((p = strrchr ((char *) path, '/')) == 0)
233 return clib_error_return (
234 0, "could not determine vpp directory - set monitor manually");
238 fmp->monitor_cmd = format (0, "%s/vpp_fateshare_monitor\0", path);
241 if (fmp->monitor_logfile == 0)
243 fmp->monitor_logfile =
244 format (0, "/tmp/vpp-fateshare-monitor-log.txt\0");
246 error = launch_monitor (fmp);
252 fateshare_init (vlib_main_t *vm)
254 fateshare_main_t *kmp = &fateshare_main;
255 clib_error_t *error = 0;
262 static clib_error_t *
263 fateshare_send_hup_fn (vlib_main_t *vm, unformat_input_t *input,
264 vlib_cli_command_t *cmd)
266 clib_error_t *error = 0;
267 fateshare_main_t *kmp = &fateshare_main;
269 if (kmp->monitor_pid)
271 int rc = kill (kmp->monitor_pid, SIGHUP);
274 error = clib_error_return (
275 0, "can not send signal to monitor process: %s", strerror (errno));
280 error = clib_error_return (0, "can not find monitor process");
286 VLIB_EARLY_CONFIG_FUNCTION (fateshare_config, "fateshare");
288 VLIB_INIT_FUNCTION (fateshare_init);
290 VLIB_CLI_COMMAND (fateshare_restart_process_command, static) = {
291 .path = "fateshare restart-processes",
292 .short_help = "restart dependent processes",
293 .function = fateshare_send_hup_fn,
296 VLIB_PLUGIN_REGISTER () = {
297 .version = VPP_BUILD_VER,
298 .description = "Run child processes which will share fate with VPP, restart "
300 .default_disabled = 1,
304 * fd.io coding-style-patch-verification: ON
307 * eval: (c-set-style "gnu")