mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-29 13:28:27 +00:00
join-ns: add join-ns option to criu CLI and RPC
this patch add join-ns option to criu CLI and RPC. This opt can be used in this fomat: --join-ns NS:PID|NS_FILE for example --join-ns net:12345 or --join-ns net:/foo/bar. pid namespaces is not supported yet. As fork() is needed to make new pid-namespace work. That makes it hard for criu to track the child-process through pid because another child process has been created after fork(). Signed-off-by: Deng Guangxing <dengguangxing@huawei.com> Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
parent
7206e329b5
commit
2cf17cd83b
@ -37,6 +37,7 @@
|
|||||||
#include "setproctitle.h"
|
#include "setproctitle.h"
|
||||||
|
|
||||||
#include "cr-errno.h"
|
#include "cr-errno.h"
|
||||||
|
#include "namespaces.h"
|
||||||
|
|
||||||
unsigned int service_sk_ino = -1;
|
unsigned int service_sk_ino = -1;
|
||||||
|
|
||||||
@ -373,6 +374,11 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < req->n_join_ns; i++) {
|
||||||
|
if (join_ns_add(req->join_ns[i]->ns, req->join_ns[i]->ns_file, req->join_ns[i]->extra_opt))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->n_inherit_fd && !opts.swrk_restore) {
|
if (req->n_inherit_fd && !opts.swrk_restore) {
|
||||||
pr_err("inherit_fd is not allowed in standalone service\n");
|
pr_err("inherit_fd is not allowed in standalone service\n");
|
||||||
goto err;
|
goto err;
|
||||||
@ -472,6 +478,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_namespace_opts())
|
||||||
|
goto err;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "cr-service.h"
|
#include "cr-service.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
|
#include "namespaces.h"
|
||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "action-scripts.h"
|
#include "action-scripts.h"
|
||||||
@ -58,6 +59,7 @@ void init_opts(void)
|
|||||||
INIT_LIST_HEAD(&opts.ext_unixsk_ids);
|
INIT_LIST_HEAD(&opts.ext_unixsk_ids);
|
||||||
INIT_LIST_HEAD(&opts.veth_pairs);
|
INIT_LIST_HEAD(&opts.veth_pairs);
|
||||||
INIT_LIST_HEAD(&opts.ext_mounts);
|
INIT_LIST_HEAD(&opts.ext_mounts);
|
||||||
|
INIT_LIST_HEAD(&opts.join_ns);
|
||||||
INIT_LIST_HEAD(&opts.inherit_fds);
|
INIT_LIST_HEAD(&opts.inherit_fds);
|
||||||
INIT_LIST_HEAD(&opts.external);
|
INIT_LIST_HEAD(&opts.external);
|
||||||
INIT_LIST_HEAD(&opts.new_cgroup_roots);
|
INIT_LIST_HEAD(&opts.new_cgroup_roots);
|
||||||
@ -71,6 +73,29 @@ void init_opts(void)
|
|||||||
opts.empty_ns = 0;
|
opts.empty_ns = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_join_ns(const char *ptr)
|
||||||
|
{
|
||||||
|
char *aux, *ns_file, *extra_opts = NULL;
|
||||||
|
|
||||||
|
aux = strchr(ptr, ':');
|
||||||
|
if (aux == NULL)
|
||||||
|
return -1;
|
||||||
|
*aux = '\0';
|
||||||
|
|
||||||
|
ns_file = aux + 1;
|
||||||
|
aux = strchr(ns_file, ',');
|
||||||
|
if (aux != NULL) {
|
||||||
|
*aux = '\0';
|
||||||
|
extra_opts = aux + 1;
|
||||||
|
} else {
|
||||||
|
extra_opts = NULL;
|
||||||
|
}
|
||||||
|
if (join_ns_add(ptr, ns_file, extra_opts))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_cpu_cap(struct cr_options *opts, const char *optarg)
|
static int parse_cpu_cap(struct cr_options *opts, const char *optarg)
|
||||||
{
|
{
|
||||||
bool inverse = false;
|
bool inverse = false;
|
||||||
@ -190,7 +215,7 @@ int main(int argc, char *argv[], char *envp[])
|
|||||||
int log_level = LOG_UNSET;
|
int log_level = LOG_UNSET;
|
||||||
char *imgs_dir = ".";
|
char *imgs_dir = ".";
|
||||||
char *work_dir = NULL;
|
char *work_dir = NULL;
|
||||||
static const char short_opts[] = "dSsRf:F:t:p:hcD:o:v::x::Vr:jlW:L:M:";
|
static const char short_opts[] = "dSsRf:F:t:p:hcD:o:v::x::Vr:jJ:lW:L:M:";
|
||||||
static struct option long_opts[] = {
|
static struct option long_opts[] = {
|
||||||
{ "tree", required_argument, 0, 't' },
|
{ "tree", required_argument, 0, 't' },
|
||||||
{ "pid", required_argument, 0, 'p' },
|
{ "pid", required_argument, 0, 'p' },
|
||||||
@ -205,6 +230,7 @@ int main(int argc, char *argv[], char *envp[])
|
|||||||
{ "images-dir", required_argument, 0, 'D' },
|
{ "images-dir", required_argument, 0, 'D' },
|
||||||
{ "work-dir", required_argument, 0, 'W' },
|
{ "work-dir", required_argument, 0, 'W' },
|
||||||
{ "log-file", required_argument, 0, 'o' },
|
{ "log-file", required_argument, 0, 'o' },
|
||||||
|
{ "join-ns", required_argument, 0, 'J' },
|
||||||
{ "root", required_argument, 0, 'r' },
|
{ "root", required_argument, 0, 'r' },
|
||||||
{ USK_EXT_PARAM, optional_argument, 0, 'x' },
|
{ USK_EXT_PARAM, optional_argument, 0, 'x' },
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
@ -338,6 +364,10 @@ int main(int argc, char *argv[], char *envp[])
|
|||||||
case 'o':
|
case 'o':
|
||||||
opts.output = optarg;
|
opts.output = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'J':
|
||||||
|
if (parse_join_ns(optarg))
|
||||||
|
goto bad_arg;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
if (log_level == LOG_UNSET)
|
if (log_level == LOG_UNSET)
|
||||||
log_level = 0;
|
log_level = 0;
|
||||||
@ -552,6 +582,11 @@ int main(int argc, char *argv[], char *envp[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_namespace_opts()) {
|
||||||
|
pr_msg("Error: namespace flags confict\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!opts.restore_detach && opts.restore_sibling) {
|
if (!opts.restore_detach && opts.restore_sibling) {
|
||||||
pr_msg("--restore-sibling only makes sense with --restore-detach\n");
|
pr_msg("--restore-sibling only makes sense with --restore-detach\n");
|
||||||
return 1;
|
return 1;
|
||||||
@ -793,6 +828,12 @@ usage:
|
|||||||
" --empty-ns {net}\n"
|
" --empty-ns {net}\n"
|
||||||
" Create a namespace, but don't restore its properies.\n"
|
" Create a namespace, but don't restore its properies.\n"
|
||||||
" An user will retore them from action scripts.\n"
|
" An user will retore them from action scripts.\n"
|
||||||
|
" -J|--join-ns NS:PID|NS_FILE[,EXTRA_OPTS]\n"
|
||||||
|
" Join exist namespace and restore process in it.\n"
|
||||||
|
" Namespace can be specified in pid or file path format.\n"
|
||||||
|
" --join-ns net:12345 or --join-ns net:/foo/bar.\n"
|
||||||
|
" Extra_opts is optional, for now only user namespace support:\n"
|
||||||
|
" --join-ns user:PID,UID,GID to specify uid and gid.\n"
|
||||||
"Check options:\n"
|
"Check options:\n"
|
||||||
" without any arguments, \"criu check\" checks availability of absolutely required\n"
|
" without any arguments, \"criu check\" checks availability of absolutely required\n"
|
||||||
" kernel features; if any of these features is missing dump and restore will fail\n"
|
" kernel features; if any of these features is missing dump and restore will fail\n"
|
||||||
|
@ -81,6 +81,7 @@ struct cr_options {
|
|||||||
struct list_head ext_mounts;
|
struct list_head ext_mounts;
|
||||||
struct list_head inherit_fds;
|
struct list_head inherit_fds;
|
||||||
struct list_head external;
|
struct list_head external;
|
||||||
|
struct list_head join_ns;
|
||||||
char *libdir;
|
char *libdir;
|
||||||
bool use_page_server;
|
bool use_page_server;
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
#ifndef CLONE_NEWNS
|
#ifndef CLONE_NEWNS
|
||||||
#define CLONE_NEWNS 0x00020000
|
#define CLONE_NEWNS 0x00020000
|
||||||
@ -36,6 +37,7 @@
|
|||||||
|
|
||||||
/* Nested namespaces are supported only for these types */
|
/* Nested namespaces are supported only for these types */
|
||||||
#define CLONE_SUBNS (CLONE_NEWNS)
|
#define CLONE_SUBNS (CLONE_NEWNS)
|
||||||
|
#define EXTRA_SIZE 20
|
||||||
|
|
||||||
struct ns_desc {
|
struct ns_desc {
|
||||||
unsigned int cflag;
|
unsigned int cflag;
|
||||||
@ -43,6 +45,24 @@ struct ns_desc {
|
|||||||
size_t len;
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct user_ns_extra {
|
||||||
|
char *uid;
|
||||||
|
char *gid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* struct join_ns is used for storing parameters specified by --join-ns */
|
||||||
|
struct join_ns {
|
||||||
|
struct list_head list;
|
||||||
|
char *ns_file;
|
||||||
|
struct ns_desc *nd; /* namespace descriptor */
|
||||||
|
int ns_fd;
|
||||||
|
/* extra options of --join-ns, like uid&gid in user namespace */
|
||||||
|
union {
|
||||||
|
struct user_ns_extra user_extra;
|
||||||
|
char *common_extra;
|
||||||
|
} extra_opts;
|
||||||
|
};
|
||||||
|
|
||||||
enum ns_type {
|
enum ns_type {
|
||||||
NS_UNKNOWN = 0,
|
NS_UNKNOWN = 0,
|
||||||
NS_CRIU,
|
NS_CRIU,
|
||||||
@ -124,6 +144,8 @@ extern gid_t userns_gid(gid_t gid);
|
|||||||
|
|
||||||
extern int dump_user_ns(pid_t pid, int ns_id);
|
extern int dump_user_ns(pid_t pid, int ns_id);
|
||||||
extern void free_userns_maps(void);
|
extern void free_userns_maps(void);
|
||||||
|
extern int join_ns_add(const char *type, char *ns_file, char *extra_opts);
|
||||||
|
extern int check_namespace_opts(void);
|
||||||
|
|
||||||
typedef int (*uns_call_t)(void *arg, int fd, pid_t pid);
|
typedef int (*uns_call_t)(void *arg, int fd, pid_t pid);
|
||||||
/*
|
/*
|
||||||
|
@ -10,8 +10,12 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <sys/capability.h>
|
#include <sys/capability.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "rst-malloc.h"
|
#include "rst-malloc.h"
|
||||||
|
#include "cr_options.h"
|
||||||
#include "imgset.h"
|
#include "imgset.h"
|
||||||
#include "uts_ns.h"
|
#include "uts_ns.h"
|
||||||
#include "ipc_ns.h"
|
#include "ipc_ns.h"
|
||||||
@ -35,6 +39,147 @@ static struct ns_desc *ns_desc_array[] = {
|
|||||||
&cgroup_ns_desc,
|
&cgroup_ns_desc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static unsigned int join_ns_flags;
|
||||||
|
|
||||||
|
int check_namespace_opts(void)
|
||||||
|
{
|
||||||
|
errno = 22;
|
||||||
|
if (join_ns_flags & opts.rst_namespaces_flags) {
|
||||||
|
pr_perror("Conflict flags: -join-ns and -namespace");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (join_ns_flags & opts.empty_ns) {
|
||||||
|
pr_perror("Conflict flags: -join-ns and -empty-ns");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_int_str(char *str)
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
long val;
|
||||||
|
|
||||||
|
if (str == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (*str == '\0') {
|
||||||
|
str = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 22;
|
||||||
|
val = strtol(str, &endptr, 10);
|
||||||
|
if ((errno == ERANGE) || (endptr == str)
|
||||||
|
|| (*endptr != '\0')
|
||||||
|
|| (val < 0) || (val > 65535)) {
|
||||||
|
str = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_ns_file(char *ns_file)
|
||||||
|
{
|
||||||
|
int pid, ret, proc_dir;
|
||||||
|
|
||||||
|
if (!check_int_str(ns_file)) {
|
||||||
|
pid = atoi(ns_file);
|
||||||
|
if (pid <= 0) {
|
||||||
|
pr_perror("Invalid join_ns pid %s", ns_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
proc_dir = open_pid_proc(pid);
|
||||||
|
if (proc_dir < 0) {
|
||||||
|
pr_perror("Invalid join_ns pid: /proc/%s not found", ns_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = access(ns_file, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_perror("Can't access join-ns file: %s", ns_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_user_extra_opts(struct join_ns *jn, char *extra_opts)
|
||||||
|
{
|
||||||
|
char *uid, *gid, *aux;
|
||||||
|
|
||||||
|
if (extra_opts == NULL) {
|
||||||
|
jn->extra_opts.user_extra.uid = NULL;
|
||||||
|
jn->extra_opts.user_extra.gid = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid = extra_opts;
|
||||||
|
aux = strchr(extra_opts, ',');
|
||||||
|
if (aux == NULL) {
|
||||||
|
gid = NULL;
|
||||||
|
} else {
|
||||||
|
*aux = '\0';
|
||||||
|
gid = aux + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_int_str(uid) || check_int_str(gid))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
jn->extra_opts.user_extra.uid = uid;
|
||||||
|
jn->extra_opts.user_extra.gid = gid;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int join_ns_add(const char *type, char *ns_file, char *extra_opts)
|
||||||
|
{
|
||||||
|
struct join_ns *jn;
|
||||||
|
|
||||||
|
jn = xmalloc(sizeof(*jn));
|
||||||
|
if (!jn)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (check_ns_file(ns_file))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
jn->ns_file = ns_file;
|
||||||
|
if (!strncmp(type, "net", 4)) {
|
||||||
|
jn->nd = &net_ns_desc;
|
||||||
|
join_ns_flags |= CLONE_NEWNET;
|
||||||
|
} else if (!strncmp(type, "uts", 4)) {
|
||||||
|
jn->nd = &uts_ns_desc;
|
||||||
|
join_ns_flags |= CLONE_NEWUTS;
|
||||||
|
} else if (!strncmp(type, "ipc", 4)) {
|
||||||
|
jn->nd = &ipc_ns_desc;
|
||||||
|
join_ns_flags |= CLONE_NEWIPC;
|
||||||
|
} else if (!strncmp(type, "pid", 4)) {
|
||||||
|
pr_perror("join-ns pid namespace not supported\n");
|
||||||
|
return -1;
|
||||||
|
} else if (!strncmp(type, "user", 5)) {
|
||||||
|
jn->nd = &user_ns_desc;
|
||||||
|
if (set_user_extra_opts(jn, extra_opts)) {
|
||||||
|
pr_perror("invalid user namespace extra_opts %s\n", extra_opts);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
join_ns_flags |= CLONE_NEWUSER;
|
||||||
|
} else if (!strncmp(type, "mnt", 4)) {
|
||||||
|
jn->nd = &mnt_ns_desc;
|
||||||
|
join_ns_flags |= CLONE_NEWNS;
|
||||||
|
} else {
|
||||||
|
pr_perror("invalid namespace type %s\n", type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&jn->list, &opts.join_ns);
|
||||||
|
pr_info("Added %s:%s join namespace\n", type, ns_file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int parse_ns_link(char *link, size_t len, struct ns_desc *d)
|
static unsigned int parse_ns_link(char *link, size_t len, struct ns_desc *d)
|
||||||
{
|
{
|
||||||
unsigned long kid = 0;
|
unsigned long kid = 0;
|
||||||
|
@ -15,6 +15,12 @@ message ext_mount_map {
|
|||||||
required string val = 2;
|
required string val = 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
message join_namespace {
|
||||||
|
required string ns = 1;
|
||||||
|
required string ns_file = 2;
|
||||||
|
optional string extra_opt = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message inherit_fd {
|
message inherit_fd {
|
||||||
required string key = 1;
|
required string key = 1;
|
||||||
required int32 fd = 2;
|
required int32 fd = 2;
|
||||||
@ -90,6 +96,7 @@ message criu_opts {
|
|||||||
repeated string irmap_scan_paths = 36;
|
repeated string irmap_scan_paths = 36;
|
||||||
repeated string external = 37;
|
repeated string external = 37;
|
||||||
optional uint32 empty_ns = 38;
|
optional uint32 empty_ns = 38;
|
||||||
|
repeated join_namespace join_ns = 39;
|
||||||
}
|
}
|
||||||
|
|
||||||
message criu_dump_resp {
|
message criu_dump_resp {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user