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 <fateshare/fateshare.h>
22 #include <vlibapi/api.h>
23 #include <vlibmemory/api.h>
24 #include <vpp/app/version.h>
27 #include <sys/types.h>
29 #include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
32 fateshare_main_t fateshare_main;
34 /* Action function shared between message handler and debug CLI */
37 child_handler (int sig)
41 fateshare_main_t *kmp = &fateshare_main;
43 while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
45 if (pid == kmp->monitor_pid)
47 clib_warning ("Monitor child %d exited with status %d!", pid,
49 kmp->vlib_main->main_loop_exit_now = 1;
53 clib_warning ("child %d exited with status %d!", pid, status);
59 launch_monitor (fateshare_main_t *kmp)
61 clib_error_t *error = 0;
62 pid_t ppid_before_fork = getpid ();
67 error = clib_error_return (0, "can not fork");
70 clib_warning ("fateshare about to launch monitor %v.", kmp->monitor_cmd);
72 open ((char *) kmp->monitor_logfile, O_APPEND | O_RDWR | O_CREAT, 0777);
75 error = clib_error_return (0, "can not open log file");
81 kmp->monitor_pid = cpid;
89 int r = prctl (PR_SET_PDEATHSIG, SIGTERM);
95 pid_t current_ppid = getppid ();
96 if (current_ppid != ppid_before_fork)
98 fprintf (stderr, "parent pid changed while starting (%d => %d)\n",
99 ppid_before_fork, current_ppid);
100 if (current_ppid == 1)
102 fprintf (stderr, "exiting.\n");
107 int r1 = setpgid (getpid (), 0);
110 perror ("setpgid error");
114 u8 *scmd = format (0, "%v\0", kmp->monitor_cmd);
115 u8 *logfile_base = format (0, "%v\0", kmp->monitor_logfile);
123 fd = open ("/dev/null", O_RDONLY);
130 char *ppid_str = (char *) format (0, "%lld\0", current_ppid);
133 vec_validate (argv, vec_len (kmp->commands) + 3 - 1);
134 argv[0] = (void *) scmd;
136 argv[2] = (char *) logfile_base;
138 vec_foreach_index (i, kmp->commands)
140 argv[3 + i] = (char *) kmp->commands[i];
143 int res = execv (argv[0], argv);
144 clib_warning ("ERROR during execve: %d", res);
154 static clib_error_t *
155 fateshare_config (vlib_main_t *vm, unformat_input_t *input)
157 fateshare_main_t *fmp = &fateshare_main;
159 u8 **new_command = 0;
160 clib_error_t *error = 0;
162 /* unix config may make vpp fork, we want to run after that. */
163 if ((error = vlib_call_config_function (vm, unix_config)))
167 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
169 if (unformat (input, "monitor %s", &fmp->monitor_cmd))
171 clib_warning ("setting monitor to %v", fmp->monitor_cmd);
173 else if (unformat (input, "logfile %s", &fmp->monitor_logfile))
175 clib_warning ("setting logfile to %v", fmp->monitor_logfile);
177 else if (unformat (input, "command %s", &command))
179 vec_add2 (fmp->commands, new_command, 1);
180 *new_command = command;
183 return clib_error_return (0, "unknown input `%U'",
184 format_unformat_error, input);
187 vec_add2 (fmp->commands, new_command, 1);
190 /* Establish handler. */
192 sigemptyset (&sa.sa_mask);
194 sa.sa_handler = child_handler;
196 sigaction (SIGCHLD, &sa, NULL);
198 if (fmp->monitor_cmd == 0)
200 char *p, path[PATH_MAX];
203 /* find executable path */
204 if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
205 return clib_error_return (
206 0, "could not stat /proc/self/exe - set monitor manually");
208 /* readlink doesn't provide null termination */
212 if ((p = strrchr (path, '/')) == 0)
213 return clib_error_return (
214 0, "could not determine vpp directory - set monitor manually");
217 fmp->monitor_cmd = format (0, "%s/vpp_fateshare_monitor\0", path);
219 if (fmp->monitor_logfile == 0)
221 fmp->monitor_logfile =
222 format (0, "/tmp/vpp-fateshare-monitor-log.txt\0");
224 error = launch_monitor (fmp);
230 fateshare_init (vlib_main_t *vm)
232 fateshare_main_t *kmp = &fateshare_main;
233 clib_error_t *error = 0;
240 static clib_error_t *
241 fateshare_send_hup_fn (vlib_main_t *vm, unformat_input_t *input,
242 vlib_cli_command_t *cmd)
244 clib_error_t *error = 0;
245 fateshare_main_t *kmp = &fateshare_main;
247 if (kmp->monitor_pid)
249 int rc = kill (kmp->monitor_pid, SIGHUP);
252 error = clib_error_return (
253 0, "can not send signal to monitor process: %s", strerror (errno));
258 error = clib_error_return (0, "can not find monitor process");
264 VLIB_EARLY_CONFIG_FUNCTION (fateshare_config, "fateshare");
266 VLIB_INIT_FUNCTION (fateshare_init);
268 VLIB_CLI_COMMAND (fateshare_restart_process_command, static) = {
269 .path = "fateshare restart-processes",
270 .short_help = "restart dependent processes",
271 .function = fateshare_send_hup_fn,
274 VLIB_PLUGIN_REGISTER () = {
275 .version = VPP_BUILD_VER,
276 .description = "Run child processes which will share fate with VPP, restart "
278 .default_disabled = 1,
282 * fd.io coding-style-patch-verification: ON
285 * eval: (c-set-style "gnu")