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>
30 #include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
33 fateshare_main_t fateshare_main;
35 /* Action function shared between message handler and debug CLI */
38 child_handler (int sig)
42 fateshare_main_t *kmp = &fateshare_main;
44 while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
46 if (pid == kmp->monitor_pid)
48 clib_warning ("Monitor child %d exited with status %d!", pid,
50 kmp->vlib_main->main_loop_exit_now = 1;
54 clib_warning ("child %d exited with status %d!", pid, status);
60 launch_monitor (fateshare_main_t *kmp)
62 clib_error_t *error = 0;
63 pid_t ppid_before_fork = getpid ();
68 error = clib_error_return (0, "can not fork");
71 clib_warning ("fateshare about to launch monitor %v.", kmp->monitor_cmd);
73 open ((char *) kmp->monitor_logfile, O_APPEND | O_RDWR | O_CREAT, 0777);
76 error = clib_error_return (0, "can not open log file");
82 kmp->monitor_pid = cpid;
90 int r = prctl (PR_SET_PDEATHSIG, SIGTERM);
96 pid_t current_ppid = getppid ();
97 if (current_ppid != ppid_before_fork)
99 fprintf (stderr, "parent pid changed while starting (%d => %d)\n",
100 ppid_before_fork, current_ppid);
101 if (current_ppid == 1)
103 fprintf (stderr, "exiting.\n");
108 int r1 = setpgid (getpid (), 0);
111 perror ("setpgid error");
115 u8 *scmd = format (0, "%v\0", kmp->monitor_cmd);
116 u8 *logfile_base = format (0, "%v\0", kmp->monitor_logfile);
124 fd = open ("/dev/null", O_RDONLY);
131 char *ppid_str = (char *) format (0, "%lld\0", current_ppid);
134 vec_validate (argv, vec_len (kmp->commands) + 3 - 1);
135 argv[0] = (void *) scmd;
137 argv[2] = (char *) logfile_base;
139 vec_foreach_index (i, kmp->commands)
141 argv[3 + i] = (char *) kmp->commands[i];
144 int res = execv (argv[0], argv);
145 clib_warning ("ERROR during execve: %d", res);
155 static clib_error_t *
156 fateshare_config (vlib_main_t *vm, unformat_input_t *input)
158 fateshare_main_t *fmp = &fateshare_main;
160 u8 **new_command = 0;
161 clib_error_t *error = 0;
163 /* unix config may make vpp fork, we want to run after that. */
164 if ((error = vlib_call_config_function (vm, unix_config)))
168 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
170 if (unformat (input, "monitor %s", &fmp->monitor_cmd))
172 clib_warning ("setting monitor to %v", fmp->monitor_cmd);
174 else if (unformat (input, "logfile %s", &fmp->monitor_logfile))
176 clib_warning ("setting logfile to %v", fmp->monitor_logfile);
178 else if (unformat (input, "command %s", &command))
180 vec_add2 (fmp->commands, new_command, 1);
181 *new_command = command;
184 return clib_error_return (0, "unknown input `%U'",
185 format_unformat_error, input);
188 vec_add2 (fmp->commands, new_command, 1);
191 /* Establish handler. */
193 sigemptyset (&sa.sa_mask);
195 sa.sa_handler = child_handler;
197 sigaction (SIGCHLD, &sa, NULL);
199 if (fmp->monitor_cmd == 0)
204 /* find executable path */
205 path = os_get_exec_path ();
208 return clib_error_return (
209 0, "could not get exec path - set monitor manually");
211 /* add null termination */
215 if ((p = strrchr ((char *) path, '/')) == 0)
218 return clib_error_return (
219 0, "could not determine vpp directory - set monitor manually");
223 fmp->monitor_cmd = format (0, "%s/vpp_fateshare_monitor\0", path);
226 if (fmp->monitor_logfile == 0)
228 fmp->monitor_logfile =
229 format (0, "/tmp/vpp-fateshare-monitor-log.txt\0");
231 error = launch_monitor (fmp);
237 fateshare_init (vlib_main_t *vm)
239 fateshare_main_t *kmp = &fateshare_main;
240 clib_error_t *error = 0;
247 static clib_error_t *
248 fateshare_send_hup_fn (vlib_main_t *vm, unformat_input_t *input,
249 vlib_cli_command_t *cmd)
251 clib_error_t *error = 0;
252 fateshare_main_t *kmp = &fateshare_main;
254 if (kmp->monitor_pid)
256 int rc = kill (kmp->monitor_pid, SIGHUP);
259 error = clib_error_return (
260 0, "can not send signal to monitor process: %s", strerror (errno));
265 error = clib_error_return (0, "can not find monitor process");
271 VLIB_EARLY_CONFIG_FUNCTION (fateshare_config, "fateshare");
273 VLIB_INIT_FUNCTION (fateshare_init);
275 VLIB_CLI_COMMAND (fateshare_restart_process_command, static) = {
276 .path = "fateshare restart-processes",
277 .short_help = "restart dependent processes",
278 .function = fateshare_send_hup_fn,
281 VLIB_PLUGIN_REGISTER () = {
282 .version = VPP_BUILD_VER,
283 .description = "Run child processes which will share fate with VPP, restart "
285 .default_disabled = 1,
289 * fd.io coding-style-patch-verification: ON
292 * eval: (c-set-style "gnu")