[lxc-devel] [lxc/master] Confile: Add lxc.sysctl config

lifeng68 on Github lxc-bot at linuxcontainers.org
Thu Dec 7 09:00:06 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 542 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171207/80be91f9/attachment.bin>
-------------- next part --------------
From a6b2eb93efbd6e285e88a66eef30c4ecfde9289c Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68 at huawei.com>
Date: Thu, 7 Dec 2017 11:40:35 -0500
Subject: [PATCH 1/2] Confile: Add lxc.sysctl config

Signed-off-by: LiFeng <lifeng68 at huawei.com>
---
 src/lxc/conf.c    |  55 +++++++++++++++++++++++++++
 src/lxc/conf.h    |  15 ++++++++
 src/lxc/confile.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/start.c   |   6 +++
 4 files changed, 186 insertions(+)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 2aa057b1e..4ce034190 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2366,6 +2366,34 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
 	return 0;
 }
 
+int setup_sysctl_parameters(struct lxc_list *sysctls)
+{
+	struct lxc_list *it;
+	struct lxc_sysctl *elem;
+	char *tmp = NULL;
+	char filename[PATH_MAX] = {0};
+	int r = 0;
+
+	lxc_list_for_each(it, sysctls) {
+		elem = it->elem;
+		tmp = lxc_string_replace(".", "/", elem->key);
+		if (!tmp) {
+			ERROR("Failed to replace key %s", elem->key);
+			return -1;
+		}
+
+		snprintf(filename, sizeof(filename), "/proc/sys/%s", tmp);
+		r = lxc_write_to_file(filename, elem->value, strlen(elem->value), false);
+		if (r < 0) {
+			free(tmp);
+			ERROR("Failed to setup sysctl parameters %s to %s", elem->key, elem->value);
+			return -1;
+		}
+		free(tmp);
+	}
+	return 0;
+}
+
 static char *default_rootfs_mount = LXCROOTFSMOUNT;
 
 struct lxc_conf *lxc_conf_init(void)
@@ -2416,6 +2444,7 @@ struct lxc_conf *lxc_conf_init(void)
 	lxc_list_init(&new->aliens);
 	lxc_list_init(&new->environment);
 	lxc_list_init(&new->limits);
+	lxc_list_init(&new->sysctls);
 	for (i = 0; i < NUM_LXC_HOOKS; i++)
 		lxc_list_init(&new->hooks[i]);
 	lxc_list_init(&new->groups);
@@ -3315,6 +3344,32 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
 	return 0;
 }
 
+int lxc_clear_sysctls(struct lxc_conf *c, const char *key)
+{
+	struct lxc_list *it, *next;
+	bool all = false;
+	const char *k = NULL;
+
+	if (strcmp(key, "lxc.sysctl") == 0)
+		all = true;
+	else if (strncmp(key, "lxc.sysctl.", sizeof("lxc.sysctl.")-1) == 0)
+		k = key + sizeof("lxc.sysctl.")-1;
+	else
+		return -1;
+
+	lxc_list_for_each_safe(it, &c->sysctls, next) {
+		struct lxc_sysctl *elem = it->elem;
+		if (!all && strcmp(elem->key, k) != 0)
+			continue;
+		lxc_list_del(it);
+		free(elem->key);
+		free(elem->value);
+		free(elem);
+		free(it);
+	}
+	return 0;
+}
+
 int lxc_clear_groups(struct lxc_conf *c)
 {
 	struct lxc_list *it,*next;
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index ce259c42b..252fab9df 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -95,6 +95,16 @@ enum idtype {
 	ID_TYPE_GID
 };
 
+/*
+ * Defines a structure to configure kernel parameters at runtime.
+ * @key      : the kernel parameters will be configured without the "lxc.sysctl" prefix
+ * @value    : the value to set
+ */
+struct lxc_sysctl {
+	char *key;
+	char *value;
+};
+
 /*
  * id_map is an id map entry.  Form in confile is:
  * lxc.idmap = u 0    9800 100
@@ -370,6 +380,9 @@ struct lxc_conf {
 
 	/* A list of clients registered to be informed about a container state. */
 	struct lxc_list state_clients;
+
+	/* sysctls */
+	struct lxc_list sysctls;
 };
 
 int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
@@ -428,5 +441,7 @@ extern unsigned long add_required_remount_flags(const char *s, const char *d,
 extern int run_script(const char *name, const char *section, const char *script,
 		      ...);
 extern int in_caplist(int cap, struct lxc_list *caps);
+extern int setup_sysctl_parameters(struct lxc_list *sysctls);
+extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key);
 
 #endif /* __LXC_CONF_H */
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 35f4326ba..7188e0eb7 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -141,6 +141,7 @@ lxc_config_define(start);
 lxc_config_define(tty_max);
 lxc_config_define(tty_dir);
 lxc_config_define(uts_name);
+lxc_config_define(sysctl);
 
 static struct lxc_config_t config[] = {
                                            /* REMOVE in LXC 3.0 */
@@ -241,6 +242,7 @@ static struct lxc_config_t config[] = {
 	{ "lxc.tty.dir",                   false,                  set_config_tty_dir,                     get_config_tty_dir,                     clr_config_tty_dir,                   },
 	{ "lxc.tty.max",                   false,                  set_config_tty_max,                     get_config_tty_max,                     clr_config_tty_max,                   },
 	{ "lxc.uts.name",                  false,                  set_config_uts_name,                    get_config_uts_name,                    clr_config_uts_name,                  },
+	{ "lxc.sysctl",                    false,                  set_config_sysctl,                      get_config_sysctl,                      clr_config_sysctl,                    },
 
 	/* [START]: REMOVE IN LXC 3.0 */
 	{ "lxc.pts",                       true,                   set_config_pty_max,                     get_config_pty_max,                     clr_config_pty_max,                   },
@@ -1495,6 +1497,72 @@ static int set_config_prlimit(const char *key, const char *value,
 	return -1;
 }
 
+static int set_config_sysctl(const char *key, const char *value,
+			    struct lxc_conf *lxc_conf, void *data)
+{
+	struct lxc_list *iter;
+	struct lxc_list *sysctl_list = NULL;
+	struct lxc_sysctl *sysctl_elem = NULL;
+	char *replace_value = NULL;
+
+	if (lxc_config_value_empty(value))
+		return lxc_clear_sysctls(lxc_conf, key);
+
+	if (strncmp(key, "lxc.sysctl.", strlen("lxc.sysctl.")) != 0)
+		return -1;
+
+	key += strlen("lxc.sysctl.");
+
+	/* find existing list element */
+	lxc_list_for_each(iter, &lxc_conf->sysctls)
+	{
+		sysctl_elem = iter->elem;
+		if (!strcmp(key, sysctl_elem->key)) {
+			replace_value = strdup(value);
+			if (!replace_value)
+				return -1;
+			free(sysctl_elem->value);
+			sysctl_elem->value = replace_value;
+			return 0;
+		}
+	}
+
+	/* allocate list element */
+	sysctl_list = malloc(sizeof(*sysctl_list));
+	if (!sysctl_list)
+		goto out;
+
+	sysctl_elem = malloc(sizeof(*sysctl_elem));
+	if (!sysctl_elem)
+		goto out;
+	memset(sysctl_elem, 0, sizeof(*sysctl_elem));
+
+	sysctl_elem->key = strdup(key);
+	if (!sysctl_elem->key)
+		goto out;
+
+	sysctl_elem->value = strdup(value);
+	if (!sysctl_elem->value)
+		goto out;
+
+	sysctl_list->elem = sysctl_elem;
+
+	lxc_list_add_tail(&lxc_conf->sysctls, sysctl_list);
+
+	return 0;
+
+out:
+	free(sysctl_list);
+	if (sysctl_elem) {
+		free(sysctl_elem->key);
+		free(sysctl_elem->value);
+		free(sysctl_elem);
+	}
+	return -1;
+
+
+}
+
 static int set_config_idmaps(const char *key, const char *value,
 			     struct lxc_conf *lxc_conf, void *data)
 {
@@ -3276,6 +3344,42 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
 	return fulllen;
 }
 
+/* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then just the value
+ * will be printed. If you ask for 'lxc.sysctl', then all sysctl entries will be
+ * printed, in 'lxc.sysctl.key = value' format.
+ */
+static int get_config_sysctl(const char *key, char *retv, int inlen,
+			    struct lxc_conf *c, void *data)
+{
+	int fulllen = 0, len;
+	bool get_all = false;
+	struct lxc_list *it;
+
+	if (!retv)
+		inlen = 0;
+	else
+		memset(retv, 0, inlen);
+
+	if (!strcmp(key, "lxc.sysctl"))
+		get_all = true;
+	else if (strncmp(key, "lxc.sysctl.", strlen("lxc.sysctl.")) == 0)
+		key += strlen("lxc.sysctl.");
+	else
+		return -1;
+
+	lxc_list_for_each(it, &c->sysctls) {
+		struct lxc_sysctl *elem = it->elem;
+		if (get_all) {
+			strprint(retv, inlen, "lxc.sysctl.%s = %s\n",
+				 elem->key, elem->value);
+		} else if (!strcmp(elem->key, key)) {
+			strprint(retv, inlen, "%s", elem->value);
+		}
+	}
+
+	return fulllen;
+}
+
 static int get_config_noop(const char *key, char *retv, int inlen,
 			   struct lxc_conf *c, void *data)
 {
@@ -3653,6 +3757,12 @@ static inline int clr_config_prlimit(const char *key, struct lxc_conf *c,
 	return lxc_clear_limits(c, key);
 }
 
+static inline int clr_config_sysctl(const char *key, struct lxc_conf *c,
+				   void *data)
+{
+	return lxc_clear_sysctls(c, key);
+}
+
 static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
 					  void *data)
 {
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 72e3f0146..067734723 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -944,6 +944,12 @@ static int do_start(void *data)
 	if (lsm_process_label_set(NULL, handler->conf, 1, 1) < 0)
 		goto out_warn_father;
 
+	/* set sysctl value to a path under /proc/sys as determined from the key.
+	 * For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward.
+	 */
+	if (!lxc_list_empty(&handler->conf->sysctls) && setup_sysctl_parameters(&handler->conf->sysctls))
+		goto out_warn_father;
+
 	/* Set PR_SET_NO_NEW_PRIVS after we changed the lsm label. If we do it
 	 * before we aren't allowed anymore.
 	 */

From d3469be6cb24fe96d55f7dc55fce4c053b93ae51 Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68 at huawei.com>
Date: Thu, 7 Dec 2017 12:24:15 -0500
Subject: [PATCH 2/2] doc: add lxc.sysctl to lxc.container.conf

Signed-off-by: LiFeng <lifeng68 at huawei.com>
---
 doc/lxc.container.conf.sgml.in | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 21d9cfcc1..a178a6308 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -1389,6 +1389,32 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </variablelist>
     </refsect2>
 
+    <refsect2>
+      <title>Sysctl</title>
+      <para>
+        Configure kernel parameters for the container.
+      </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.sysctl.[kernel parameters name]</option>
+          </term>
+          <listitem>
+            <para>
+              Specify the kernel parameters to be set. The parameters available 
+              are those listed under /proc/sys/.
+              <citerefentry>
+                <refentrytitle><command>sysctl</command></refentrytitle>
+                <manvolnum>8</manvolnum>
+              </citerefentry>.
+              If used with no value, lxc will clear the parameters specified up 
+              to this point.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
     <refsect2>
       <title>Apparmor profile</title>
       <para>


More information about the lxc-devel mailing list