154e19c09a
Type: improvement Change-Id: I7ea8b5505a2663d6751208f0001e4b9ba2deb150 Signed-off-by: Tom Jones <thj@freebsd.org>
310 lines
6.9 KiB
C
310 lines
6.9 KiB
C
/*
|
|
* fateshare.c - skeleton vpp engine plug-in
|
|
*
|
|
* Copyright (c) 2022 Cisco and/or its affiliates.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <vnet/vnet.h>
|
|
#include <vnet/plugin/plugin.h>
|
|
#include <vppinfra/unix.h>
|
|
#include <fateshare/fateshare.h>
|
|
|
|
#include <vlibapi/api.h>
|
|
#include <vlibmemory/api.h>
|
|
#include <vpp/app/version.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#ifdef __linux__
|
|
#include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
|
|
#else
|
|
#include <sys/procctl.h>
|
|
#endif /* __linux__ */
|
|
#include <limits.h>
|
|
|
|
fateshare_main_t fateshare_main;
|
|
|
|
/* Action function shared between message handler and debug CLI */
|
|
|
|
static void
|
|
child_handler (int sig)
|
|
{
|
|
pid_t pid;
|
|
int status;
|
|
fateshare_main_t *kmp = &fateshare_main;
|
|
|
|
while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
|
|
{
|
|
if (pid == kmp->monitor_pid)
|
|
{
|
|
clib_warning ("Monitor child %d exited with status %d!", pid,
|
|
status);
|
|
kmp->vlib_main->main_loop_exit_now = 1;
|
|
}
|
|
else
|
|
{
|
|
clib_warning ("child %d exited with status %d!", pid, status);
|
|
}
|
|
}
|
|
}
|
|
|
|
clib_error_t *
|
|
launch_monitor (fateshare_main_t *kmp)
|
|
{
|
|
clib_error_t *error = 0;
|
|
pid_t ppid_before_fork = getpid ();
|
|
pid_t cpid = fork ();
|
|
if (cpid == -1)
|
|
{
|
|
perror (0);
|
|
error = clib_error_return (0, "can not fork");
|
|
goto done;
|
|
}
|
|
clib_warning ("fateshare about to launch monitor %v.", kmp->monitor_cmd);
|
|
int logfd =
|
|
open ((char *) kmp->monitor_logfile, O_APPEND | O_RDWR | O_CREAT, 0777);
|
|
if (logfd < 0)
|
|
{
|
|
error = clib_error_return (0, "can not open log file");
|
|
goto done;
|
|
}
|
|
if (cpid)
|
|
{
|
|
/* parent */
|
|
kmp->monitor_pid = cpid;
|
|
close (logfd);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
dup2 (logfd, 1);
|
|
dup2 (logfd, 2);
|
|
#ifdef __linux__
|
|
int r = prctl (PR_SET_PDEATHSIG, SIGTERM);
|
|
if (r == -1)
|
|
{
|
|
perror (0);
|
|
exit (1);
|
|
}
|
|
#else
|
|
int r, s = SIGTERM;
|
|
|
|
r = procctl (P_PID, 0, PROC_PDEATHSIG_CTL, &s);
|
|
if (r == -1)
|
|
{
|
|
perror (0);
|
|
exit (1);
|
|
}
|
|
#endif /* __linux__ */
|
|
pid_t current_ppid = getppid ();
|
|
if (current_ppid != ppid_before_fork)
|
|
{
|
|
fprintf (stderr, "parent pid changed while starting (%d => %d)\n",
|
|
ppid_before_fork, current_ppid);
|
|
if (current_ppid == 1)
|
|
{
|
|
fprintf (stderr, "exiting.\n");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
int r1 = setpgid (getpid (), 0);
|
|
if (r1 != 0)
|
|
{
|
|
perror ("setpgid error");
|
|
exit (1);
|
|
}
|
|
|
|
u8 *scmd = format (0, "%v\0", kmp->monitor_cmd);
|
|
u8 *logfile_base = format (0, "%v\0", kmp->monitor_logfile);
|
|
int fd = logfd - 1;
|
|
while (fd > 2)
|
|
{
|
|
close (fd);
|
|
fd--;
|
|
}
|
|
|
|
fd = open ("/dev/null", O_RDONLY);
|
|
if (fd < 0)
|
|
{
|
|
exit (1);
|
|
}
|
|
dup2 (fd, 0);
|
|
|
|
char *ppid_str = (char *) format (0, "%lld\0", current_ppid);
|
|
|
|
char **argv = 0;
|
|
vec_validate (argv, vec_len (kmp->commands) + 3 - 1);
|
|
argv[0] = (void *) scmd;
|
|
argv[1] = ppid_str;
|
|
argv[2] = (char *) logfile_base;
|
|
int i;
|
|
vec_foreach_index (i, kmp->commands)
|
|
{
|
|
argv[3 + i] = (char *) kmp->commands[i];
|
|
}
|
|
|
|
int res = execv (argv[0], argv);
|
|
clib_warning ("ERROR during execve: %d", res);
|
|
perror ("execve");
|
|
|
|
exit (0);
|
|
}
|
|
done:
|
|
|
|
return error;
|
|
}
|
|
|
|
static clib_error_t *
|
|
fateshare_config (vlib_main_t *vm, unformat_input_t *input)
|
|
{
|
|
fateshare_main_t *fmp = &fateshare_main;
|
|
u8 *command = 0;
|
|
u8 **new_command = 0;
|
|
clib_error_t *error = 0;
|
|
|
|
/* unix config may make vpp fork, we want to run after that. */
|
|
if ((error = vlib_call_config_function (vm, unix_config)))
|
|
return error;
|
|
|
|
/* Defaults */
|
|
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
|
|
{
|
|
if (unformat (input, "monitor %s", &fmp->monitor_cmd))
|
|
{
|
|
clib_warning ("setting monitor to %v", fmp->monitor_cmd);
|
|
}
|
|
else if (unformat (input, "logfile %s", &fmp->monitor_logfile))
|
|
{
|
|
clib_warning ("setting logfile to %v", fmp->monitor_logfile);
|
|
}
|
|
else if (unformat (input, "command %s", &command))
|
|
{
|
|
vec_add2 (fmp->commands, new_command, 1);
|
|
*new_command = command;
|
|
}
|
|
else
|
|
return clib_error_return (0, "unknown input `%U'",
|
|
format_unformat_error, input);
|
|
}
|
|
|
|
vec_add2 (fmp->commands, new_command, 1);
|
|
*new_command = 0;
|
|
|
|
/* Establish handler. */
|
|
struct sigaction sa;
|
|
sigemptyset (&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = child_handler;
|
|
|
|
sigaction (SIGCHLD, &sa, NULL);
|
|
|
|
if (fmp->monitor_cmd == 0)
|
|
{
|
|
char *p;
|
|
u8 *path;
|
|
|
|
/* find executable path */
|
|
path = os_get_exec_path ();
|
|
|
|
if (path == 0)
|
|
return clib_error_return (
|
|
0, "could not get exec path - set monitor manually");
|
|
|
|
/* add null termination */
|
|
vec_add1 (path, 0);
|
|
|
|
/* strip filename */
|
|
if ((p = strrchr ((char *) path, '/')) == 0)
|
|
{
|
|
vec_free (path);
|
|
return clib_error_return (
|
|
0, "could not determine vpp directory - set monitor manually");
|
|
}
|
|
*p = 0;
|
|
|
|
fmp->monitor_cmd = format (0, "%s/vpp_fateshare_monitor\0", path);
|
|
vec_free (path);
|
|
}
|
|
if (fmp->monitor_logfile == 0)
|
|
{
|
|
fmp->monitor_logfile =
|
|
format (0, "/tmp/vpp-fateshare-monitor-log.txt\0");
|
|
}
|
|
error = launch_monitor (fmp);
|
|
|
|
return error;
|
|
}
|
|
|
|
clib_error_t *
|
|
fateshare_init (vlib_main_t *vm)
|
|
{
|
|
fateshare_main_t *kmp = &fateshare_main;
|
|
clib_error_t *error = 0;
|
|
|
|
kmp->vlib_main = vm;
|
|
|
|
return error;
|
|
}
|
|
|
|
static clib_error_t *
|
|
fateshare_send_hup_fn (vlib_main_t *vm, unformat_input_t *input,
|
|
vlib_cli_command_t *cmd)
|
|
{
|
|
clib_error_t *error = 0;
|
|
fateshare_main_t *kmp = &fateshare_main;
|
|
|
|
if (kmp->monitor_pid)
|
|
{
|
|
int rc = kill (kmp->monitor_pid, SIGHUP);
|
|
if (rc)
|
|
{
|
|
error = clib_error_return (
|
|
0, "can not send signal to monitor process: %s", strerror (errno));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error = clib_error_return (0, "can not find monitor process");
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
VLIB_EARLY_CONFIG_FUNCTION (fateshare_config, "fateshare");
|
|
|
|
VLIB_INIT_FUNCTION (fateshare_init);
|
|
|
|
VLIB_CLI_COMMAND (fateshare_restart_process_command, static) = {
|
|
.path = "fateshare restart-processes",
|
|
.short_help = "restart dependent processes",
|
|
.function = fateshare_send_hup_fn,
|
|
};
|
|
|
|
VLIB_PLUGIN_REGISTER () = {
|
|
.version = VPP_BUILD_VER,
|
|
.description = "Run child processes which will share fate with VPP, restart "
|
|
"them if they quit",
|
|
.default_disabled = 1,
|
|
};
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|