[CRIU] [PATCH 1/4] join-ns: add join-ns option to criu CLI and RPC
Dengguangxing
dengguangxing at huawei.com
Mon Apr 4 20:03:44 PDT 2016
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 at huawei.com>
---
criu/cr-service.c | 9 +++
criu/crtools.c | 43 ++++++++++++-
criu/include/cr_options.h | 1 +
criu/include/namespaces.h | 23 +++++++
criu/namespaces.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++
images/rpc.proto | 7 +++
6 files changed, 231 insertions(+), 1 deletion(-)
diff --git a/criu/cr-service.c b/criu/cr-service.c
index 05455d4..ae4f0b5 100644
--- a/criu/cr-service.c
+++ b/criu/cr-service.c
@@ -37,6 +37,7 @@
#include "setproctitle.h"
#include "cr-errno.h"
+#include "namespaces.h"
unsigned int service_sk_ino = -1;
@@ -374,6 +375,11 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
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) {
pr_err("inherit_fd is not allowed in standalone service\n");
goto err;
@@ -473,6 +479,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
}
}
+ if (check_namespace_opts())
+ goto err;
+
return 0;
err:
diff --git a/criu/crtools.c b/criu/crtools.c
index 537bcc9..7dfb03b 100644
--- a/criu/crtools.c
+++ b/criu/crtools.c
@@ -36,6 +36,7 @@
#include "cr-service.h"
#include "plugin.h"
#include "mount.h"
+#include "namespaces.h"
#include "cgroup.h"
#include "cpu.h"
#include "action-scripts.h"
@@ -58,6 +59,7 @@ void init_opts(void)
INIT_LIST_HEAD(&opts.veth_pairs);
INIT_LIST_HEAD(&opts.scripts);
INIT_LIST_HEAD(&opts.ext_mounts);
+ INIT_LIST_HEAD(&opts.join_ns);
INIT_LIST_HEAD(&opts.inherit_fds);
INIT_LIST_HEAD(&opts.external);
INIT_LIST_HEAD(&opts.new_cgroup_roots);
@@ -99,6 +101,29 @@ bad_ns:
return -1;
}
+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)
{
bool inverse = false;
@@ -218,7 +243,7 @@ int main(int argc, char *argv[], char *envp[])
int log_level = LOG_UNSET;
char *imgs_dir = ".";
char *work_dir = NULL;
- static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jlW:L:M:";
+ static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jJ:lW:L:M:";
static struct option long_opts[] = {
{ "tree", required_argument, 0, 't' },
{ "pid", required_argument, 0, 'p' },
@@ -234,6 +259,7 @@ int main(int argc, char *argv[], char *envp[])
{ "work-dir", required_argument, 0, 'W' },
{ "log-file", required_argument, 0, 'o' },
{ "namespaces", required_argument, 0, 'n' },
+ { "join-ns", required_argument, 0, 'J' },
{ "root", required_argument, 0, 'r' },
{ USK_EXT_PARAM, optional_argument, 0, 'x' },
{ "help", no_argument, 0, 'h' },
@@ -369,6 +395,10 @@ int main(int argc, char *argv[], char *envp[])
if (parse_ns_string(optarg))
goto bad_arg;
break;
+ case 'J':
+ if (parse_join_ns(optarg))
+ goto bad_arg;
+ break;
case 'v':
if (log_level == LOG_UNSET)
log_level = 0;
@@ -583,6 +613,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) {
pr_msg("--restore-sibling only makes sense with --restore-detach\n");
return 1;
@@ -826,6 +861,12 @@ usage:
" --empty-ns {net}\n"
" Create a namespace, but don't restore its properies.\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"
" 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"
diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
index 5e1cc21..1224f4a 100644
--- a/criu/include/cr_options.h
+++ b/criu/include/cr_options.h
@@ -83,6 +83,7 @@ struct cr_options {
struct list_head ext_mounts;
struct list_head inherit_fds;
struct list_head external;
+ struct list_head join_ns;
char *libdir;
bool use_page_server;
unsigned short port;
diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index 303c9e6..344e0f6 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -3,6 +3,7 @@
#include "compiler.h"
#include "files.h"
+#include "list.h"
/* including syscall-types.h gives another weird error; do we really need to
* define this twice? */
@@ -12,6 +13,7 @@
/* Nested namespaces are supported only for these types */
#define CLONE_SUBNS (CLONE_NEWNS)
+#define EXTRA_SIZE 20
struct ns_desc {
unsigned int cflag;
@@ -19,6 +21,24 @@ struct ns_desc {
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 {
NS_UNKNOWN = 0,
NS_CRIU,
@@ -70,6 +90,7 @@ extern bool check_ns_proc(struct fd_link *link);
extern struct ns_desc pid_ns_desc;
extern struct ns_desc user_ns_desc;
extern unsigned long root_ns_mask;
+extern unsigned int join_ns_flags;
extern const struct fdtype_ops nsfile_dump_ops;
extern struct collect_image_info nsfile_cinfo;
@@ -100,6 +121,8 @@ extern gid_t userns_gid(gid_t gid);
extern int dump_user_ns(pid_t pid, int ns_id);
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);
/*
diff --git a/criu/namespaces.c b/criu/namespaces.c
index 724203e..6094e99 100644
--- a/criu/namespaces.c
+++ b/criu/namespaces.c
@@ -10,7 +10,11 @@
#include <signal.h>
#include <sched.h>
#include <sys/capability.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <errno.h>
+#include "cr_options.h"
#include "util.h"
#include "imgset.h"
#include "uts_ns.h"
@@ -35,6 +39,151 @@ static struct ns_desc *ns_desc_array[] = {
&cgroup_ns_desc,
};
+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;
+ }
+ if (opts.empty_ns & opts.rst_namespaces_flags) {
+ pr_perror("Conflict flags: -empty-ns and -namespace");
+ 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)
{
unsigned long kid = 0;
diff --git a/images/rpc.proto b/images/rpc.proto
index fac4b9f..9ece4da 100644
--- a/images/rpc.proto
+++ b/images/rpc.proto
@@ -15,6 +15,12 @@ message ext_mount_map {
required string val = 2;
};
+message join_namespace {
+ required string ns = 1;
+ required string ns_file = 2;
+ optional string extra_opt = 3;
+}
+
message inherit_fd {
required string key = 1;
required int32 fd = 2;
@@ -90,6 +96,7 @@ message criu_opts {
repeated string irmap_scan_paths = 36;
repeated string external = 37;
optional uint32 empty_ns = 38;
+ repeated join_namespace join_ns = 39;
}
message criu_dump_resp {
--
2.5.0
More information about the CRIU
mailing list