]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
confile: Add lxc.sysctl config 2009/head
authorLiFeng <lifeng68@huawei.com>
Thu, 7 Dec 2017 16:40:35 +0000 (11:40 -0500)
committerLiFeng <lifeng68@huawei.com>
Mon, 11 Dec 2017 14:24:11 +0000 (09:24 -0500)
Signed-off-by: LiFeng <lifeng68@huawei.com>
doc/lxc.container.conf.sgml.in
src/lxc/conf.c
src/lxc/conf.h
src/lxc/confile.c
src/tests/get_item.c
src/tests/parse_config_file.c

index 21d9cfcc10de2996abfa2c204d71e53bd792e825..8c14d1507e147361f03f83467f29679aef9f9a8e 100644 (file)
@@ -1389,6 +1389,34 @@ 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/.
+              Note that not all sysctls are namespaced.Changing Non-namespaced
+              sysctls will cause the system-wide setting to be modified.
+              <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>
index 2aa057b1e36d57e1b5d420406d892b9678dba46f..fbaa35d811fd9b1c4733e1dc03a6a0709033fb5a 100644 (file)
@@ -2366,6 +2366,38 @@ 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[MAXPATHLEN] = {0};
+       int ret = 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;
+               }
+
+               ret = snprintf(filename, sizeof(filename), "/proc/sys/%s", tmp);
+               free(tmp);
+               if (ret < 0 || (size_t)ret >= sizeof(filename)) {
+                       ERROR("Error setting up sysctl parameters path");
+                       return -1;
+               }
+
+               ret = lxc_write_to_file(filename, elem->value, strlen(elem->value), false);
+               if (ret < 0) {
+                       ERROR("Failed to setup sysctl parameters %s to %s", elem->key, elem->value);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
 static char *default_rootfs_mount = LXCROOTFSMOUNT;
 
 struct lxc_conf *lxc_conf_init(void)
@@ -2416,6 +2448,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);
@@ -3164,6 +3197,15 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
+       /* 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(&lxc_conf->sysctls)) {
+               ret = setup_sysctl_parameters(&lxc_conf->sysctls);
+               if (ret < 0)
+                       return -1;
+       }
+
        if (!lxc_list_empty(&lxc_conf->keepcaps)) {
                if (!lxc_list_empty(&lxc_conf->caps)) {
                        ERROR("Container requests lxc.cap.drop and lxc.cap.keep: either use lxc.cap.drop or lxc.cap.keep, not both.");
@@ -3293,8 +3335,7 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
        bool all = false;
        const char *k = NULL;
 
-       if (strcmp(key, "lxc.limit") == 0
-           || strcmp(key, "lxc.prlimit"))
+       if (strcmp(key, "lxc.limit") == 0 || strcmp(key, "lxc.prlimit") == 0)
                all = true;
        else if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.")-1) == 0)
                k = key + sizeof("lxc.limit.")-1;
@@ -3315,6 +3356,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;
@@ -3454,6 +3521,7 @@ void lxc_conf_free(struct lxc_conf *conf)
        lxc_clear_aliens(conf);
        lxc_clear_environment(conf);
        lxc_clear_limits(conf, "lxc.prlimit");
+       lxc_clear_sysctls(conf, "lxc.sysctl");
        free(conf->cgroup_meta.dir);
        free(conf->cgroup_meta.controllers);
        free(conf);
index ce259c42b034b18eb7bc997a1ac400ff249e4f37..252fab9df93ea4194a07dcadeb00253c32ffae8a 100644 (file)
@@ -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 */
index 35f4326ba0bf9c40c6ac43f958ad7022991dccb2..a7d95f72727df5ce2092444e456d31fc3872c86b 100644 (file)
@@ -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,                   },
@@ -1456,8 +1458,7 @@ static int set_config_prlimit(const char *key, const char *value,
        }
 
        /* find existing list element */
-       lxc_list_for_each(iter, &lxc_conf->limits)
-       {
+       lxc_list_for_each(iter, &lxc_conf->limits) {
                limelem = iter->elem;
                if (!strcmp(key, limelem->resource)) {
                        limelem->limit = limit;
@@ -1468,25 +1469,25 @@ static int set_config_prlimit(const char *key, const char *value,
        /* allocate list element */
        limlist = malloc(sizeof(*limlist));
        if (!limlist)
-               goto out;
+               goto on_error;
 
        limelem = malloc(sizeof(*limelem));
        if (!limelem)
-               goto out;
+               goto on_error;
        memset(limelem, 0, sizeof(*limelem));
 
        limelem->resource = strdup(key);
        if (!limelem->resource)
-               goto out;
+               goto on_error;
        limelem->limit = limit;
 
-       limlist->elem = limelem;
+       lxc_list_add_elem(limlist, limelem);;
 
        lxc_list_add_tail(&lxc_conf->limits, limlist);
 
        return 0;
 
-out:
+on_error:
        free(limlist);
        if (limelem) {
                free(limelem->resource);
@@ -1495,6 +1496,71 @@ out:
        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.", sizeof("lxc.sysctl.") - 1) != 0)
+               return -1;
+
+       key += sizeof("lxc.sysctl.") - 1;
+
+       /* find existing list element */
+       lxc_list_for_each(iter, &lxc_conf->sysctls) {
+               sysctl_elem = iter->elem;
+               if (strcmp(key, sysctl_elem->key) == 0) {
+                       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 on_error;
+
+       sysctl_elem = malloc(sizeof(*sysctl_elem));
+       if (!sysctl_elem)
+               goto on_error;
+       memset(sysctl_elem, 0, sizeof(*sysctl_elem));
+
+       sysctl_elem->key = strdup(key);
+       if (!sysctl_elem->key)
+               goto on_error;
+
+       sysctl_elem->value = strdup(value);
+       if (!sysctl_elem->value)
+               goto on_error;
+
+       lxc_list_add_elem(sysctl_list, sysctl_elem);
+
+       lxc_list_add_tail(&lxc_conf->sysctls, sysctl_list);
+
+       return 0;
+
+on_error:
+       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 +3342,43 @@ 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 len;
+       struct lxc_list *it;
+       int fulllen = 0;
+       bool get_all = false;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (strcmp(key, "lxc.sysctl") == 0)
+               get_all = true;
+       else if (strncmp(key, "lxc.sysctl.", sizeof("lxc.sysctl.") - 1) == 0)
+               key += sizeof("lxc.sysctl.") - 1;
+       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) == 0) {
+                       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 +3756,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)
 {
index e0fd7b603789bc52af5329de0c160e19a4914355..7a15c1c891cfa8ce0399d38b6c8879bf4d9658ce 100644 (file)
@@ -34,8 +34,9 @@
 
 int main(int argc, char *argv[])
 {
-       int ret = EXIT_FAILURE;
+       int ret;
        struct lxc_container *c;
+       int fret = EXIT_FAILURE;
        char v1[2], v2[256], v3[2048];
 
        if ((c = lxc_container_new("testxyz", NULL)) == NULL) {
@@ -243,6 +244,71 @@ int main(int argc, char *argv[])
        }
        printf("lxc.limit returned %d %s\n", ret, v3);
 
+#define SYSCTL_SOMAXCONN "lxc.sysctl.net.core.somaxconn = 256\n"
+#define ALL_SYSCTLS "lxc.sysctl.net.ipv4.ip_forward = 1\n" SYSCTL_SOMAXCONN
+
+       ret = c->get_config_item(c, "lxc.sysctl", v3, 2047);
+       if (ret != 0) {
+               fprintf(stderr, "%d: get_config_item(sysctl) returned %d\n", __LINE__, ret);
+               goto out;
+       }
+
+       if (!c->set_config_item(c, "lxc.sysctl.net.ipv4.ip_forward", "1")) {
+               fprintf(stderr, "%d: failed to set lxc.sysctl.net.ipv4.ip_forward\n", __LINE__);
+               goto out;
+       }
+       ret = c->get_config_item(c, "lxc.sysctl.net.ipv4.ip_forward", v2, 255);
+       if (ret < 0) {
+               fprintf(stderr, "%d: get_config_item(lxc.sysctl.net.ipv4.ip_forward) returned %d\n", __LINE__, ret);
+               goto out;
+       }
+       if (strcmp(v2, "1")) {
+               fprintf(stderr, "%d: lxc.sysctl.net.ipv4.ip_forward returned wrong value: %d %s not 1\n", __LINE__, ret, v2);
+               goto out;
+       }
+       printf("lxc.sysctl.net.ipv4.ip_forward returned %d %s\n", ret, v2);
+
+       if (!c->set_config_item(c, "lxc.sysctl.net.core.somaxconn", "256")) {
+               fprintf(stderr, "%d: failed to set lxc.sysctl.net.core.somaxconn\n", __LINE__);
+               goto out;
+       }
+       ret = c->get_config_item(c, "lxc.sysctl.net.core.somaxconn", v2, 255);
+       if (ret < 0) {
+               fprintf(stderr, "%d: get_config_item(lxc.sysctl.net.core.somaxconn) returned %d\n", __LINE__, ret);
+               goto out;
+       }
+       if (strcmp(v2, "256")) {
+               fprintf(stderr, "%d: lxc.sysctl.net.core.somaxconn returned wrong value: %d %s not 256\n", __LINE__, ret, v2);
+               goto out;
+       }
+       printf("lxc.sysctl.net.core.somaxconn returned %d %s\n", ret, v2);
+
+       ret = c->get_config_item(c, "lxc.sysctl", v3, 2047);
+       if (ret != sizeof(ALL_SYSCTLS)-1) {
+               fprintf(stderr, "%d: get_config_item(sysctl) returned %d\n", __LINE__, ret);
+               goto out;
+       }
+       if (strcmp(v3, ALL_SYSCTLS)) {
+               fprintf(stderr, "%d: lxc.sysctl returned wrong value: %d %s not %d %s\n", __LINE__, ret, v3, (int)sizeof(ALL_SYSCTLS) - 1, ALL_SYSCTLS);
+               goto out;
+       }
+       printf("lxc.sysctl returned %d %s\n", ret, v3);
+
+       if (!c->clear_config_item(c, "lxc.sysctl.net.ipv4.ip_forward")) {
+               fprintf(stderr, "%d: failed clearing lxc.sysctl.net.ipv4.ip_forward\n", __LINE__);
+               goto out;
+       }
+       ret = c->get_config_item(c, "lxc.sysctl", v3, 2047);
+       if (ret != sizeof(SYSCTL_SOMAXCONN) - 1) {
+               fprintf(stderr, "%d: get_config_item(sysctl) returned %d\n", __LINE__, ret);
+               goto out;
+       }
+       if (strcmp(v3, SYSCTL_SOMAXCONN)) {
+               fprintf(stderr, "%d: lxc.sysctl returned wrong value: %d %s not %d %s\n", __LINE__, ret, v3, (int)sizeof(SYSCTL_SOMAXCONN) - 1, SYSCTL_SOMAXCONN);
+               goto out;
+       }
+       printf("lxc.sysctl returned %d %s\n", ret, v3);
+
        if (!c->set_config_item(c, "lxc.aa_profile", "unconfined")) {
                fprintf(stderr, "%d: failed to set aa_profile\n", __LINE__);
                goto out;
@@ -424,9 +490,9 @@ int main(int argc, char *argv[])
        }
 
        printf("All get_item tests passed\n");
-       ret = EXIT_SUCCESS;
+       fret = EXIT_SUCCESS;
 out:
        c->destroy(c);
        lxc_container_put(c);
-       exit(ret);
+       exit(fret);
 }
index c679acc28ed8bf81589459b77b75351d2be6b4f8..556d6d034a75e200c70ba8253a2b8e77452a3523 100644 (file)
@@ -922,6 +922,13 @@ int main(int argc, char *argv[])
                goto non_test_error;
        }
 
+       /* lxc.sysctl */
+       if (set_get_compare_clear_save_load(c, "lxc.sysctl.net.core.somaxconn", "256", tmpf,
+                                           true) < 0) {
+               lxc_error("%s\n", "lxc.sysctl.net.core.somaxconn");
+               goto non_test_error;
+       }
+
        /* REMOVE IN LXC 3.0
           legacy lxc.limit.* key
         */