]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/confile.c
conf: add lxc.seccomp.notify.cookie
[mirror_lxc.git] / src / lxc / confile.c
index 456cd4c2ed02fc3710c966e6d5ed5d74c5ae7749..b08aa0174fda2feeb76dc5feb3e402edfded4fba 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
 #define __STDC_FORMAT_MACROS
+#include <arpa/inet.h>
 #include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <net/if.h>
+#include <netinet/in.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/in.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
 
+#include "af_unix.h"
 #include "conf.h"
 #include "config.h"
 #include "confile.h"
 #include "confile_utils.h"
+#include "../include/netns_ifaddrs.h"
 #include "log.h"
 #include "lxcseccomp.h"
+#include "memory_utils.h"
 #include "network.h"
 #include "parse.h"
 #include "storage.h"
 #include "utils.h"
 
-#if HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#else
-#include <../include/ifaddrs.h>
-#endif
-
 #if HAVE_SYS_PERSONALITY_H
 #include <sys/personality.h>
 #endif
 
 lxc_log_define(confile, lxc);
 
-#define lxc_config_define(name)                                                \
-       static int set_config_##name(const char *, const char *,               \
-                                    struct lxc_conf *, void *);               \
-       static int get_config_##name(const char *, char *, int,                \
-                                    struct lxc_conf *, void *);               \
-       static int clr_config_##name(const char *, struct lxc_conf *, void *);
+#define lxc_config_define(name)                                             \
+       __hot static int set_config_##name(const char *, const char *,      \
+                                          struct lxc_conf *, void *);      \
+       __hot static int get_config_##name(const char *, char *, int,       \
+                                          struct lxc_conf *, void *);      \
+       __hot static int clr_config_##name(const char *, struct lxc_conf *, \
+                                          void *);
 
 lxc_config_define(autodev);
 lxc_config_define(apparmor_allow_incomplete);
@@ -92,6 +92,7 @@ lxc_config_define(cap_keep);
 lxc_config_define(cgroup_controller);
 lxc_config_define(cgroup2_controller);
 lxc_config_define(cgroup_dir);
+lxc_config_define(cgroup_relative);
 lxc_config_define(console_buffer_size);
 lxc_config_define(console_logfile);
 lxc_config_define(console_path);
@@ -128,7 +129,10 @@ lxc_config_define(net_ipv4_gateway);
 lxc_config_define(net_ipv6_address);
 lxc_config_define(net_ipv6_gateway);
 lxc_config_define(net_link);
+lxc_config_define(net_l2proxy);
 lxc_config_define(net_macvlan_mode);
+lxc_config_define(net_ipvlan_mode);
+lxc_config_define(net_ipvlan_isolation);
 lxc_config_define(net_mtu);
 lxc_config_define(net_name);
 lxc_config_define(net_nic);
@@ -136,15 +140,21 @@ lxc_config_define(net_script_down);
 lxc_config_define(net_script_up);
 lxc_config_define(net_type);
 lxc_config_define(net_veth_pair);
+lxc_config_define(net_veth_ipv4_route);
+lxc_config_define(net_veth_ipv6_route);
 lxc_config_define(net_vlan_id);
 lxc_config_define(no_new_privs);
 lxc_config_define(personality);
 lxc_config_define(prlimit);
 lxc_config_define(pty_max);
+lxc_config_define(rootfs_managed);
 lxc_config_define(rootfs_mount);
 lxc_config_define(rootfs_options);
 lxc_config_define(rootfs_path);
 lxc_config_define(seccomp_profile);
+lxc_config_define(seccomp_allow_nesting);
+lxc_config_define(seccomp_notify_cookie);
+lxc_config_define(seccomp_notify_proxy);
 lxc_config_define(selinux_context);
 lxc_config_define(signal_halt);
 lxc_config_define(signal_reboot);
@@ -156,7 +166,7 @@ lxc_config_define(uts_name);
 lxc_config_define(sysctl);
 lxc_config_define(proc);
 
-static struct lxc_config_t config[] = {
+static struct lxc_config_t config_jump_table[] = {
        { "lxc.arch",                      set_config_personality,                 get_config_personality,                 clr_config_personality,               },
        { "lxc.apparmor.profile",          set_config_apparmor_profile,            get_config_apparmor_profile,            clr_config_apparmor_profile,          },
        { "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete,   get_config_apparmor_allow_incomplete,   clr_config_apparmor_allow_incomplete, },
@@ -167,6 +177,7 @@ static struct lxc_config_t config[] = {
        { "lxc.cap.keep",                  set_config_cap_keep,                    get_config_cap_keep,                    clr_config_cap_keep,                  },
        { "lxc.cgroup2",                   set_config_cgroup2_controller,          get_config_cgroup2_controller,          clr_config_cgroup2_controller,        },
        { "lxc.cgroup.dir",                set_config_cgroup_dir,                  get_config_cgroup_dir,                  clr_config_cgroup_dir,                },
+       { "lxc.cgroup.relative",           set_config_cgroup_relative,             get_config_cgroup_relative,             clr_config_cgroup_relative,           },
        { "lxc.cgroup",                    set_config_cgroup_controller,           get_config_cgroup_controller,           clr_config_cgroup_controller,         },
        { "lxc.console.buffer.size",       set_config_console_buffer_size,         get_config_console_buffer_size,         clr_config_console_buffer_size,       },
        { "lxc.console.logfile",           set_config_console_logfile,             get_config_console_logfile,             clr_config_console_logfile,           },
@@ -213,7 +224,10 @@ static struct lxc_config_t config[] = {
        { "lxc.net.ipv6.address",          set_config_net_ipv6_address,            get_config_net_ipv6_address,            clr_config_net_ipv6_address,          },
        { "lxc.net.ipv6.gateway",          set_config_net_ipv6_gateway,            get_config_net_ipv6_gateway,            clr_config_net_ipv6_gateway,          },
        { "lxc.net.link",                  set_config_net_link,                    get_config_net_link,                    clr_config_net_link,                  },
+       { "lxc.net.l2proxy",               set_config_net_l2proxy,                 get_config_net_l2proxy,                 clr_config_net_l2proxy,               },
        { "lxc.net.macvlan.mode",          set_config_net_macvlan_mode,            get_config_net_macvlan_mode,            clr_config_net_macvlan_mode,          },
+       { "lxc.net.ipvlan.mode",           set_config_net_ipvlan_mode,             get_config_net_ipvlan_mode,             clr_config_net_ipvlan_mode,           },
+       { "lxc.net.ipvlan.isolation",      set_config_net_ipvlan_isolation,        get_config_net_ipvlan_isolation,        clr_config_net_ipvlan_isolation,      },
        { "lxc.net.mtu",                   set_config_net_mtu,                     get_config_net_mtu,                     clr_config_net_mtu,                   },
        { "lxc.net.name",                  set_config_net_name,                    get_config_net_name,                    clr_config_net_name,                  },
        { "lxc.net.script.down",           set_config_net_script_down,             get_config_net_script_down,             clr_config_net_script_down,           },
@@ -221,14 +235,20 @@ static struct lxc_config_t config[] = {
        { "lxc.net.type",                  set_config_net_type,                    get_config_net_type,                    clr_config_net_type,                  },
        { "lxc.net.vlan.id",               set_config_net_vlan_id,                 get_config_net_vlan_id,                 clr_config_net_vlan_id,               },
        { "lxc.net.veth.pair",             set_config_net_veth_pair,               get_config_net_veth_pair,               clr_config_net_veth_pair,             },
+       { "lxc.net.veth.ipv4.route",       set_config_net_veth_ipv4_route,         get_config_net_veth_ipv4_route,         clr_config_net_veth_ipv4_route,       },
+       { "lxc.net.veth.ipv6.route",       set_config_net_veth_ipv6_route,         get_config_net_veth_ipv6_route,         clr_config_net_veth_ipv6_route,       },
        { "lxc.net.",                      set_config_net_nic,                     get_config_net_nic,                     clr_config_net_nic,                   },
        { "lxc.net",                       set_config_net,                         get_config_net,                         clr_config_net,                       },
        { "lxc.no_new_privs",              set_config_no_new_privs,                get_config_no_new_privs,                clr_config_no_new_privs,              },
        { "lxc.prlimit",                   set_config_prlimit,                     get_config_prlimit,                     clr_config_prlimit,                   },
        { "lxc.pty.max",                   set_config_pty_max,                     get_config_pty_max,                     clr_config_pty_max,                   },
+       { "lxc.rootfs.managed",            set_config_rootfs_managed,              get_config_rootfs_managed,              clr_config_rootfs_managed,            },
        { "lxc.rootfs.mount",              set_config_rootfs_mount,                get_config_rootfs_mount,                clr_config_rootfs_mount,              },
        { "lxc.rootfs.options",            set_config_rootfs_options,              get_config_rootfs_options,              clr_config_rootfs_options,            },
        { "lxc.rootfs.path",               set_config_rootfs_path,                 get_config_rootfs_path,                 clr_config_rootfs_path,               },
+       { "lxc.seccomp.allow_nesting",     set_config_seccomp_allow_nesting,       get_config_seccomp_allow_nesting,       clr_config_seccomp_allow_nesting,     },
+       { "lxc.seccomp.notify.cookie",     set_config_seccomp_notify_cookie,       get_config_seccomp_notify_cookie,       clr_config_seccomp_notify_cookie,     },
+       { "lxc.seccomp.notify.proxy",      set_config_seccomp_notify_proxy,        get_config_seccomp_notify_proxy,        clr_config_seccomp_notify_proxy,      },
        { "lxc.seccomp.profile",           set_config_seccomp_profile,             get_config_seccomp_profile,             clr_config_seccomp_profile,           },
        { "lxc.selinux.context",           set_config_selinux_context,             get_config_selinux_context,             clr_config_selinux_context,           },
        { "lxc.signal.halt",               set_config_signal_halt,                 get_config_signal_halt,                 clr_config_signal_halt,               },
@@ -244,15 +264,15 @@ static struct lxc_config_t config[] = {
        { "lxc.proc",                      set_config_proc,                        get_config_proc,                        clr_config_proc,                      },
 };
 
-static const size_t config_size = sizeof(config) / sizeof(struct lxc_config_t);
+static const size_t config_jump_table_size = sizeof(config_jump_table) / sizeof(struct lxc_config_t);
 
 struct lxc_config_t *lxc_get_config(const char *key)
 {
        size_t i;
 
-       for (i = 0; i < config_size; i++)
-               if (!strncmp(config[i].name, key, strlen(config[i].name)))
-                       return &config[i];
+       for (i = 0; i < config_jump_table_size; i++)
+               if (!strncmp(config_jump_table[i].name, key, strlen(config_jump_table[i].name)))
+                       return &config_jump_table[i];
 
        return NULL;
 }
@@ -279,22 +299,27 @@ static int set_config_net_type(const char *key, const char *value,
        if (!netdev)
                return -1;
 
-       if (!strcmp(value, "veth")) {
+       if (strcmp(value, "veth") == 0) {
                netdev->type = LXC_NET_VETH;
-       } else if (!strcmp(value, "macvlan")) {
+               lxc_list_init(&netdev->priv.veth_attr.ipv4_routes);
+               lxc_list_init(&netdev->priv.veth_attr.ipv6_routes);
+       } else if (strcmp(value, "macvlan") == 0) {
                netdev->type = LXC_NET_MACVLAN;
-               lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode,
-                                        "private");
-       } else if (!strcmp(value, "vlan")) {
+               lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private");
+       } else if (strcmp(value, "ipvlan") == 0) {
+               netdev->type = LXC_NET_IPVLAN;
+               lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, "l3");
+               lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, "bridge");
+       } else if (strcmp(value, "vlan") == 0) {
                netdev->type = LXC_NET_VLAN;
-       } else if (!strcmp(value, "phys")) {
+       } else if (strcmp(value, "phys") == 0) {
                netdev->type = LXC_NET_PHYS;
-       } else if (!strcmp(value, "empty")) {
+       } else if (strcmp(value, "empty") == 0) {
                netdev->type = LXC_NET_EMPTY;
-       } else if (!strcmp(value, "none")) {
+       } else if (strcmp(value, "none") == 0) {
                netdev->type = LXC_NET_NONE;
        } else {
-               ERROR("invalid network type %s", value);
+               ERROR("Invalid network type %s", value);
                return -1;
        }
 
@@ -320,21 +345,22 @@ static int set_config_net_flags(const char *key, const char *value,
 static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
                                  struct lxc_netdev *netdev)
 {
-       struct ifaddrs *ifaddr, *ifa;
+       struct netns_ifaddrs *ifaddr, *ifa;
        int n;
        int ret = 0;
        const char *type_key = "lxc.net.type";
        const char *link_key = "lxc.net.link";
        const char *tmpvalue = "phys";
 
-       if (getifaddrs(&ifaddr) == -1) {
-               SYSERROR("Get network interfaces failed");
+       if (netns_getifaddrs(&ifaddr, -1, &(bool){false}) < 0) {
+               SYSERROR("Failed to get network interfaces");
                return -1;
        }
 
        for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
                if (!ifa->ifa_addr)
                        continue;
+
                if (ifa->ifa_addr->sa_family != AF_PACKET)
                        continue;
 
@@ -345,17 +371,17 @@ static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
                                ret = set_config_net_link(
                                    link_key, ifa->ifa_name, lxc_conf, netdev);
                                if (ret) {
-                                       ERROR("failed to create matched ifnames");
+                                       ERROR("Failed to create matched ifnames");
                                        break;
                                }
                        } else {
-                               ERROR("failed to create matched ifnames");
+                               ERROR("Failed to create matched ifnames");
                                break;
                        }
                }
        }
 
-       freeifaddrs(ifaddr);
+       netns_freeifaddrs(ifaddr);
        ifaddr = NULL;
 
        return ret;
@@ -381,6 +407,35 @@ static int set_config_net_link(const char *key, const char *value,
        return ret;
 }
 
+static int set_config_net_l2proxy(const char *key, const char *value,
+                                    struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+       unsigned int val = 0;
+       int ret;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_net_l2proxy(key, lxc_conf, data);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       ret = lxc_safe_uint(value, &val);
+       if (ret < 0)
+               return minus_one_set_errno(-ret);
+
+       switch (val) {
+       case 0:
+               netdev->l2proxy = false;
+               return 0;
+       case 1:
+               netdev->l2proxy = true;
+               return 0;
+       }
+
+       return minus_one_set_errno(EINVAL);
+}
+
 static int set_config_net_name(const char *key, const char *value,
                               struct lxc_conf *lxc_conf, void *data)
 {
@@ -423,6 +478,44 @@ static int set_config_net_macvlan_mode(const char *key, const char *value,
        return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
 }
 
+static int set_config_net_ipvlan_mode(const char *key, const char *value,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_net_ipvlan_mode(key, lxc_conf, data);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_IPVLAN) {
+               SYSERROR("Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value);
+               return minus_one_set_errno(EINVAL);
+       }
+
+       return lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, value);
+}
+
+static int set_config_net_ipvlan_isolation(const char *key, const char *value,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_net_ipvlan_isolation(key, lxc_conf, data);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_IPVLAN) {
+               SYSERROR("Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value);
+               return minus_one_set_errno(EINVAL);
+       }
+
+       return lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, value);
+}
+
 static int set_config_net_hwaddr(const char *key, const char *value,
                                 struct lxc_conf *lxc_conf, void *data)
 {
@@ -448,6 +541,7 @@ static int set_config_net_hwaddr(const char *key, const char *value,
        }
 
        netdev->hwaddr = new_value;
+
        return 0;
 }
 
@@ -503,7 +597,6 @@ static int set_config_net_ipv4_address(const char *key, const char *value,
        inetdev = malloc(sizeof(*inetdev));
        if (!inetdev)
                return -1;
-
        memset(inetdev, 0, sizeof(*inetdev));
 
        list = malloc(sizeof(*list));
@@ -577,8 +670,8 @@ static int set_config_net_ipv4_address(const char *key, const char *value,
        }
 
        lxc_list_add_tail(&netdev->ipv4, list);
-
        free(addr);
+
        return 0;
 }
 
@@ -595,9 +688,13 @@ static int set_config_net_ipv4_gateway(const char *key, const char *value,
 
        free(netdev->ipv4_gateway);
 
-       if (!strcmp(value, "auto")) {
+       if (strcmp(value, "auto") == 0) {
                netdev->ipv4_gateway = NULL;
                netdev->ipv4_gateway_auto = true;
+       } else if (strcmp(value, "dev") == 0) {
+               netdev->ipv4_gateway = NULL;
+               netdev->ipv4_gateway_auto = false;
+               netdev->ipv4_gateway_dev = true;
        } else {
                int ret;
                struct in_addr *gw;
@@ -620,6 +717,69 @@ static int set_config_net_ipv4_gateway(const char *key, const char *value,
        return 0;
 }
 
+static int set_config_net_veth_ipv4_route(const char *key, const char *value,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       __do_free char *valdup = NULL;
+       __do_free struct lxc_inetdev *inetdev = NULL;
+       __do_free struct lxc_list *list = NULL;
+       int ret;
+       char *netmask, *slash;
+       struct lxc_netdev *netdev = data;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_net_veth_ipv4_route(key, lxc_conf, data);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH) {
+               SYSERROR("Invalid ipv4 route \"%s\", can only be used with veth network", value);
+               return minus_one_set_errno(EINVAL);
+       }
+
+       inetdev = malloc(sizeof(*inetdev));
+       if (!inetdev)
+               return -1;
+       memset(inetdev, 0, sizeof(*inetdev));
+
+       list = malloc(sizeof(*list));
+       if (!list)
+               return -1;
+
+       lxc_list_init(list);
+       list->elem = inetdev;
+
+       valdup = strdup(value);
+       if (!valdup)
+               return -1;
+
+       slash = strchr(valdup, '/');
+       if (!slash)
+               return minus_one_set_errno(EINVAL);
+
+       *slash = '\0';
+       slash++;
+       if (*slash == '\0')
+               return minus_one_set_errno(EINVAL);
+
+       netmask = slash;
+
+       ret = lxc_safe_uint(netmask, &inetdev->prefix);
+       if (ret < 0 || inetdev->prefix > 32)
+               return minus_one_set_errno(EINVAL);
+
+       ret = inet_pton(AF_INET, valdup, &inetdev->addr);
+       if (!ret || ret < 0)
+               return minus_one_set_errno(EINVAL);
+
+       lxc_list_add_tail(&netdev->priv.veth_attr.ipv4_routes, list);
+       move_ptr(inetdev);
+       move_ptr(list);
+
+       return 0;
+}
+
 static int set_config_net_ipv6_address(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf, void *data)
 {
@@ -638,7 +798,6 @@ static int set_config_net_ipv6_address(const char *key, const char *value,
        inet6dev = malloc(sizeof(*inet6dev));
        if (!inet6dev)
                return -1;
-
        memset(inet6dev, 0, sizeof(*inet6dev));
 
        list = malloc(sizeof(*list));
@@ -662,6 +821,7 @@ static int set_config_net_ipv6_address(const char *key, const char *value,
        if (slash) {
                *slash = '\0';
                netmask = slash + 1;
+
                ret = lxc_safe_uint(netmask, &inet6dev->prefix);
                if (ret < 0) {
                        free(list);
@@ -681,8 +841,8 @@ static int set_config_net_ipv6_address(const char *key, const char *value,
        }
 
        lxc_list_add_tail(&netdev->ipv6, list);
-
        free(valdup);
+
        return 0;
 }
 
@@ -699,9 +859,13 @@ static int set_config_net_ipv6_gateway(const char *key, const char *value,
 
        free(netdev->ipv6_gateway);
 
-       if (!strcmp(value, "auto")) {
+       if (strcmp(value, "auto") == 0) {
                netdev->ipv6_gateway = NULL;
                netdev->ipv6_gateway_auto = true;
+       } else if (strcmp(value, "dev") == 0) {
+               netdev->ipv6_gateway = NULL;
+               netdev->ipv6_gateway_auto = false;
+               netdev->ipv6_gateway_dev = true;
        } else {
                int ret;
                struct in6_addr *gw;
@@ -724,6 +888,69 @@ static int set_config_net_ipv6_gateway(const char *key, const char *value,
        return 0;
 }
 
+static int set_config_net_veth_ipv6_route(const char *key, const char *value,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       __do_free char *valdup;
+       __do_free struct lxc_inet6dev *inet6dev;
+       __do_free struct lxc_list *list;
+       int ret;
+       char *netmask, *slash;
+       struct lxc_netdev *netdev = data;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_net_veth_ipv6_route(key, lxc_conf, data);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH) {
+               SYSERROR("Invalid ipv6 route \"%s\", can only be used with veth network", value);
+               return minus_one_set_errno(EINVAL);
+       }
+
+       inet6dev = malloc(sizeof(*inet6dev));
+       if (!inet6dev)
+               return -1;
+       memset(inet6dev, 0, sizeof(*inet6dev));
+
+       list = malloc(sizeof(*list));
+       if (!list)
+               return -1;
+
+       lxc_list_init(list);
+       list->elem = inet6dev;
+
+       valdup = strdup(value);
+       if (!valdup)
+               return -1;
+
+       slash = strchr(valdup, '/');
+       if (!slash)
+               return minus_one_set_errno(EINVAL);
+
+       *slash = '\0';
+       slash++;
+       if (*slash == '\0')
+               return minus_one_set_errno(EINVAL);
+
+       netmask = slash;
+
+       ret = lxc_safe_uint(netmask, &inet6dev->prefix);
+       if (ret < 0 || inet6dev->prefix > 128)
+               return minus_one_set_errno(EINVAL);
+
+       ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
+       if (!ret || ret < 0)
+               return minus_one_set_errno(EINVAL);
+
+       lxc_list_add_tail(&netdev->priv.veth_attr.ipv6_routes, list);
+       move_ptr(inet6dev);
+       move_ptr(list);
+
+       return 0;
+}
+
 static int set_config_net_script_up(const char *key, const char *value,
                                    struct lxc_conf *lxc_conf, void *data)
 {
@@ -764,13 +991,66 @@ static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
 
        hooklist->elem = hook;
        lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
+
        return 0;
 }
 
+static int set_config_seccomp_allow_nesting(const char *key, const char *value,
+                                           struct lxc_conf *lxc_conf, void *data)
+{
+#ifdef HAVE_SECCOMP
+       if (lxc_config_value_empty(value))
+               return clr_config_seccomp_allow_nesting(key, lxc_conf, NULL);
+
+       if (lxc_safe_uint(value, &lxc_conf->seccomp.allow_nesting) < 0)
+               return -1;
+
+       if (lxc_conf->seccomp.allow_nesting > 1)
+               return minus_one_set_errno(EINVAL);
+
+       return 0;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+static int set_config_seccomp_notify_cookie(const char *key, const char *value,
+                                           struct lxc_conf *lxc_conf, void *data)
+{
+#ifdef HAVE_SECCOMP_NOTIFY
+       return set_config_string_item(&lxc_conf->seccomp.notifier.cookie, value);
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
+
+static int set_config_seccomp_notify_proxy(const char *key, const char *value,
+                                          struct lxc_conf *lxc_conf, void *data)
+{
+#ifdef HAVE_SECCOMP_NOTIFY
+       const char *offset;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_seccomp_notify_proxy(key, lxc_conf, NULL);
+
+       if (strncmp(value, "unix:", 5) != 0)
+               return minus_one_set_errno(EINVAL);
+
+       offset = value + 5;
+       if (lxc_unix_sockaddr(&lxc_conf->seccomp.notifier.proxy_addr, offset) < 0)
+               return -1;
+
+       return 0;
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
+
 static int set_config_seccomp_profile(const char *key, const char *value,
                                      struct lxc_conf *lxc_conf, void *data)
 {
-       return set_config_path_item(&lxc_conf->seccomp, value);
+       return set_config_path_item(&lxc_conf->seccomp.seccomp, value);
 }
 
 static int set_config_execute_cmd(const char *key, const char *value,
@@ -866,6 +1146,7 @@ static int set_config_hooks(const char *key, const char *value,
                return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
 
        free(copy);
+
        return -1;
 }
 
@@ -889,6 +1170,7 @@ static int set_config_hooks_version(const char *key, const char *value,
        }
 
        lxc_conf->hooks_version = tmp;
+
        return 0;
 }
 
@@ -921,6 +1203,7 @@ static int set_config_pty_max(const char *key, const char *value,
                return -1;
 
        lxc_conf->pty_max = max;
+
        return 0;
 }
 
@@ -1007,9 +1290,9 @@ static int set_config_monitor_signal_pdeath(const char *key, const char *value,
 static int set_config_group(const char *key, const char *value,
                            struct lxc_conf *lxc_conf, void *data)
 {
-       char *groups, *groupptr, *sptr, *token;
+       char *groups, *token;
        struct lxc_list *grouplist;
-       int ret = -1;
+       int ret = 0;
 
        if (lxc_config_value_empty(value))
                return lxc_clear_groups(lxc_conf);
@@ -1021,20 +1304,17 @@ static int set_config_group(const char *key, const char *value,
        /* In case several groups are specified in a single line split these
         * groups in a single element for the list.
         */
-       for (groupptr = groups;; groupptr = NULL) {
-               token = strtok_r(groupptr, " \t", &sptr);
-               if (!token) {
-                       ret = 0;
-                       break;
-               }
-
+       lxc_iterate_parts(token, groups, " \t") {
                grouplist = malloc(sizeof(*grouplist));
-               if (!grouplist)
+               if (!grouplist) {
+                       ret = -1;
                        break;
+               }
 
                grouplist->elem = strdup(token);
                if (!grouplist->elem) {
                        free(grouplist);
+                       ret = -1;
                        break;
                }
 
@@ -1042,6 +1322,7 @@ static int set_config_group(const char *key, const char *value,
        }
 
        free(groups);
+
        return ret;
 }
 
@@ -1082,6 +1363,7 @@ static int set_config_environment(const char *key, const char *value,
 
 on_error:
        free(list_item);
+
        return -1;
 }
 
@@ -1101,6 +1383,7 @@ static int set_config_tty_max(const char *key, const char *value,
                return -1;
 
        lxc_conf->ttys.max = nbtty;
+
        return 0;
 }
 
@@ -1230,6 +1513,7 @@ static int set_config_log_level(const char *key, const char *value,
         * current logging.
         */
        lxc_conf->loglevel = newlevel;
+
        return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
 }
 
@@ -1398,6 +1682,52 @@ static int set_config_cgroup_dir(const char *key, const char *value,
        return set_config_string_item(&lxc_conf->cgroup_meta.dir, value);
 }
 
+static int set_config_cgroup_relative(const char *key, const char *value,
+                                     struct lxc_conf *lxc_conf, void *data)
+{
+       unsigned int converted;
+       int ret;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_cgroup_relative(key, lxc_conf, NULL);
+
+       ret = lxc_safe_uint(value, &converted);
+       if (ret < 0)
+               return -ret;
+
+       if (converted == 1) {
+               lxc_conf->cgroup_meta.relative = true;
+               return 0;
+       }
+
+       if (converted == 0) {
+               lxc_conf->cgroup_meta.relative = false;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static bool parse_limit_value(const char **value, rlim_t *res)
+{
+       char *endptr = NULL;
+
+       if (strncmp(*value, "unlimited", STRLITERALLEN("unlimited")) == 0) {
+               *res = RLIM_INFINITY;
+               *value += STRLITERALLEN("unlimited");
+               return true;
+       }
+
+       errno = 0;
+       *res = strtoull(*value, &endptr, 10);
+       if (errno || !endptr)
+               return false;
+
+       *value = endptr;
+
+       return true;
+}
+
 static int set_config_prlimit(const char *key, const char *value,
                            struct lxc_conf *lxc_conf, void *data)
 {
@@ -1410,14 +1740,15 @@ static int set_config_prlimit(const char *key, const char *value,
        if (lxc_config_value_empty(value))
                return lxc_clear_limits(lxc_conf, key);
 
-       if (strncmp(key, "lxc.prlimit.", sizeof("lxc.prlimit.") - 1) != 0)
+       if (strncmp(key, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")) != 0)
                return -1;
 
-       key += sizeof("lxc.prlimit.") - 1;
+       key += STRLITERALLEN("lxc.prlimit.");
 
        /* soft limit comes first in the value */
        if (!parse_limit_value(&value, &limit_value))
                return -1;
+
        limit.rlim_cur = limit_value;
 
        /* skip spaces and a colon */
@@ -1436,6 +1767,7 @@ static int set_config_prlimit(const char *key, const char *value,
        if (*value) {
                if (!parse_limit_value(&value, &limit_value))
                        return -1;
+
                limit.rlim_max = limit_value;
 
                /* check for trailing garbage */
@@ -1471,20 +1803,21 @@ static int set_config_prlimit(const char *key, const char *value,
        limelem->resource = strdup(key);
        if (!limelem->resource)
                goto on_error;
-       limelem->limit = limit;
 
+       limelem->limit = limit;
        lxc_list_add_elem(limlist, limelem);;
-
        lxc_list_add_tail(&lxc_conf->limits, limlist);
 
        return 0;
 
 on_error:
        free(limlist);
+
        if (limelem) {
                free(limelem->resource);
                free(limelem);
        }
+
        return -1;
 }
 
@@ -1499,10 +1832,10 @@ static int set_config_sysctl(const char *key, const char *value,
        if (lxc_config_value_empty(value))
                return clr_config_sysctl(key, lxc_conf, NULL);
 
-       if (strncmp(key, "lxc.sysctl.", sizeof("lxc.sysctl.") - 1) != 0)
+       if (strncmp(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")) != 0)
                return -1;
 
-       key += sizeof("lxc.sysctl.") - 1;
+       key += STRLITERALLEN("lxc.sysctl.");
 
        /* find existing list element */
        lxc_list_for_each(iter, &lxc_conf->sysctls) {
@@ -1517,6 +1850,7 @@ static int set_config_sysctl(const char *key, const char *value,
 
                free(sysctl_elem->value);
                sysctl_elem->value = replace_value;
+
                return 0;
        }
 
@@ -1539,18 +1873,19 @@ static int set_config_sysctl(const char *key, const char *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;
 }
 
@@ -1564,10 +1899,10 @@ static int set_config_proc(const char *key, const char *value,
        if (lxc_config_value_empty(value))
                return clr_config_proc(key, lxc_conf, NULL);
 
-       if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") -1) != 0)
+       if (strncmp(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")) != 0)
                return -1;
 
-       subkey = key + sizeof("lxc.proc.") - 1;
+       subkey = key + STRLITERALLEN("lxc.proc.");
        if (*subkey == '\0')
                return -EINVAL;
 
@@ -1594,6 +1929,7 @@ static int set_config_proc(const char *key, const char *value,
 
 on_error:
        free(proclist);
+
        if (procelem) {
                free(procelem->filename);
                free(procelem->value);
@@ -1648,7 +1984,6 @@ static int set_config_idmaps(const char *key, const char *value,
                if (idmap->nsid == 0)
                        lxc_conf->root_nsuid_map = idmap;
 
-
        if (!lxc_conf->root_nsgid_map && idmap->idtype == ID_TYPE_GID)
                if (idmap->nsid == 0)
                        lxc_conf->root_nsgid_map = idmap;
@@ -1678,7 +2013,7 @@ static int set_config_mount_fstab(const char *key, const char *value,
 static int set_config_mount_auto(const char *key, const char *value,
                                 struct lxc_conf *lxc_conf, void *data)
 {
-       char *autos, *autoptr, *sptr, *token;
+       char *autos, *token;
        int i;
        int ret = -1;
        static struct {
@@ -1726,21 +2061,15 @@ static int set_config_mount_auto(const char *key, const char *value,
        if (!autos)
                return -1;
 
-       for (autoptr = autos;; autoptr = NULL) {
+       lxc_iterate_parts(token, autos, " \t") {
                bool is_shmounts = false;
 
-               token = strtok_r(autoptr, " \t", &sptr);
-               if (!token) {
-                       ret = 0;
-                       break;
-               }
-
                for (i = 0; allowed_auto_mounts[i].token; i++) {
                        if (!strcmp(allowed_auto_mounts[i].token, token))
                                break;
 
                        if (strcmp("shmounts:", allowed_auto_mounts[i].token) == 0 &&
-                           strncmp("shmounts:", token, sizeof("shmounts:") - 1) == 0) {
+                           strncmp("shmounts:", token, STRLITERALLEN("shmounts:")) == 0) {
                                is_shmounts = true;
                                break;
                        }
@@ -1748,32 +2077,47 @@ static int set_config_mount_auto(const char *key, const char *value,
 
                if (!allowed_auto_mounts[i].token) {
                        ERROR("Invalid filesystem to automount \"%s\"", token);
-                       break;
+                       goto on_error;
                }
 
                lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
                lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
+
                if (is_shmounts) {
-                       lxc_conf->shmount.path_host = strdup(token + (sizeof("shmounts:") - 1));
-                       if (!lxc_conf->shmount.path_host) {
+                       char *container_path;
+                       char *host_path;
+
+                       host_path = token + STRLITERALLEN("shmounts:");
+                       if (*host_path == '\0') {
                                SYSERROR("Failed to copy shmounts host path");
-                               break;
+                               goto on_error;
                        }
 
-                       if (strcmp(lxc_conf->shmount.path_host, "") == 0) {
-                               ERROR("Invalid shmounts path: empty");
-                               break;
+                       container_path = strchr(host_path, ':');
+                       if (!container_path || *(container_path + 1) == '\0')
+                               container_path = "/dev/.lxc-mounts";
+                       else
+                               *container_path++ = '\0';
+
+                       lxc_conf->shmount.path_host = strdup(host_path);
+                       if (!lxc_conf->shmount.path_host) {
+                               SYSERROR("Failed to copy shmounts host path");
+                               goto on_error;
                        }
 
-                       lxc_conf->shmount.path_cont = strdup("/dev/.lxc-mounts");
+                       lxc_conf->shmount.path_cont = strdup(container_path);
                        if(!lxc_conf->shmount.path_cont) {
                                SYSERROR("Failed to copy shmounts container path");
-                               break;
+                               goto on_error;
                        }
                }
        }
 
+       ret = 0;
+
+on_error:
        free(autos);
+
        return ret;
 }
 
@@ -1809,7 +2153,7 @@ int add_elem_to_mount_list(const char *value, struct lxc_conf *lxc_conf) {
 static int set_config_cap_keep(const char *key, const char *value,
                               struct lxc_conf *lxc_conf, void *data)
 {
-       char *keepcaps, *keepptr, *sptr, *token;
+       char *keepcaps, *token;
        struct lxc_list *keeplist;
        int ret = -1;
 
@@ -1823,29 +2167,26 @@ static int set_config_cap_keep(const char *key, const char *value,
        /* In case several capability keep is specified in a single line
         * split these caps in a single element for the list.
         */
-       for (keepptr = keepcaps;; keepptr = NULL) {
-               token = strtok_r(keepptr, " \t", &sptr);
-               if (!token) {
-                       ret = 0;
-                       break;
-               }
-
+       lxc_iterate_parts(token, keepcaps, " \t") {
                if (!strcmp(token, "none"))
                        lxc_clear_config_keepcaps(lxc_conf);
 
                keeplist = malloc(sizeof(*keeplist));
                if (!keeplist)
-                       break;
+                       goto on_error;
 
                keeplist->elem = strdup(token);
                if (!keeplist->elem) {
                        free(keeplist);
-                       break;
+                       goto on_error;
                }
 
                lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
        }
 
+       ret = 0;
+
+on_error:
        free(keepcaps);
 
        return ret;
@@ -1854,7 +2195,7 @@ static int set_config_cap_keep(const char *key, const char *value,
 static int set_config_cap_drop(const char *key, const char *value,
                               struct lxc_conf *lxc_conf, void *data)
 {
-       char *dropcaps, *dropptr, *sptr, *token;
+       char *dropcaps, *token;
        struct lxc_list *droplist;
        int ret = -1;
 
@@ -1868,26 +2209,23 @@ static int set_config_cap_drop(const char *key, const char *value,
        /* In case several capability drop is specified in a single line
         * split these caps in a single element for the list.
         */
-       for (dropptr = dropcaps;; dropptr = NULL) {
-               token = strtok_r(dropptr, " \t", &sptr);
-               if (!token) {
-                       ret = 0;
-                       break;
-               }
-
+       lxc_iterate_parts(token, dropcaps, " \t") {
                droplist = malloc(sizeof(*droplist));
                if (!droplist)
-                       break;
+                       goto on_error;
 
                droplist->elem = strdup(token);
                if (!droplist->elem) {
                        free(droplist);
-                       break;
+                       goto on_error;
                }
 
                lxc_list_add_tail(&lxc_conf->caps, droplist);
        }
 
+        ret = 0;
+
+on_error:
        free(dropcaps);
 
        return ret;
@@ -1969,6 +2307,7 @@ static int set_config_console_buffer_size(const char *key, const char *value,
                       "next power of two: %" PRIu64 " bytes", buffer_size);
 
        lxc_conf->console.buffer_size = buffer_size;
+
        return 0;
 }
 
@@ -2016,15 +2355,52 @@ static int set_config_console_size(const char *key, const char *value,
                       "next power of two: %" PRIu64 " bytes", log_size);
 
        lxc_conf->console.log_size = log_size;
+
        return 0;
 }
 
+/*
+ * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
+ * file, we expand it in the unexpanded_config, so that after a save_config we
+ * store the hwaddr for re-use.
+ * This is only called when reading the config file, not when executing a
+ * lxc.include.
+ * 'x' and 'X' are substituted in-place.
+ */
+static void update_hwaddr(const char *line)
+{
+       char *p;
+
+       line += lxc_char_left_gc(line, strlen(line));
+       if (line[0] == '#')
+               return;
+
+       if (!lxc_config_net_is_hwaddr(line))
+               return;
+
+       /* Let config_net_hwaddr raise the error. */
+       p = strchr(line, '=');
+       if (!p)
+               return;
+       p++;
+
+       while (isblank(*p))
+               p++;
+
+       if (!*p)
+               return;
+
+       rand_complete_hwaddr(p);
+}
+
 int append_unexp_config_line(const char *line, struct lxc_conf *conf)
 {
-       size_t len = conf->unexpanded_len, linelen = strlen(line);
+       size_t linelen;
+       size_t len = conf->unexpanded_len;
 
        update_hwaddr(line);
 
+       linelen = strlen(line);
        while (conf->unexpanded_alloced <= len + linelen + 2) {
                char *tmp = realloc(conf->unexpanded_config,
                                    conf->unexpanded_alloced + 1024);
@@ -2033,16 +2409,16 @@ int append_unexp_config_line(const char *line, struct lxc_conf *conf)
 
                if (!conf->unexpanded_config)
                        *tmp = '\0';
+
                conf->unexpanded_config = tmp;
                conf->unexpanded_alloced += 1024;
        }
 
-       (void)strlcat(conf->unexpanded_config, line, conf->unexpanded_alloced);
+       memcpy(conf->unexpanded_config + conf->unexpanded_len, line, linelen);
        conf->unexpanded_len += linelen;
-       if (line[linelen - 1] != '\n') {
-               (void)strlcat(conf->unexpanded_config, "\n", conf->unexpanded_alloced);
-               conf->unexpanded_len++;
-       }
+       if (line[linelen - 1] != '\n')
+               conf->unexpanded_config[conf->unexpanded_len++] = '\n';
+       conf->unexpanded_config[conf->unexpanded_len] = '\0';
 
        return 0;
 }
@@ -2051,7 +2427,7 @@ static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
 {
        struct dirent *direntp;
        DIR *dir;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        int len;
        int ret = -1;
 
@@ -2073,8 +2449,8 @@ static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
                if (len < 6 || strncmp(fnam + len - 5, ".conf", 5) != 0)
                        continue;
 
-               len = snprintf(path, MAXPATHLEN, "%s/%s", dirp, fnam);
-               if (len < 0 || len >= MAXPATHLEN) {
+               len = snprintf(path, PATH_MAX, "%s/%s", dirp, fnam);
+               if (len < 0 || len >= PATH_MAX) {
                        ret = -1;
                        goto out;
                }
@@ -2129,11 +2505,13 @@ static int set_config_rootfs_path(const char *key, const char *value,
        tmp = strchr(dup, ':');
        if (tmp) {
                *tmp = '\0';
+
                ret = set_config_path_item(&lxc_conf->rootfs.bdev_type, dup);
                if (ret < 0) {
                        free(dup);
                        return -1;
                }
+
                tmp++;
                container_path = tmp;
        } else {
@@ -2142,9 +2520,35 @@ static int set_config_rootfs_path(const char *key, const char *value,
 
        ret = set_config_path_item(&lxc_conf->rootfs.path, container_path);
        free(dup);
+
        return ret;
 }
 
+static int set_config_rootfs_managed(const char *key, const char *value,
+                                    struct lxc_conf *lxc_conf, void *data)
+{
+       unsigned int val = 0;
+
+       if (lxc_config_value_empty(value)) {
+               lxc_conf->rootfs.managed = true;
+               return 0;
+       }
+
+       if (lxc_safe_uint(value, &val) < 0)
+               return -EINVAL;
+
+       switch (val) {
+       case 0:
+               lxc_conf->rootfs.managed = false;
+               return 0;
+       case 1:
+               lxc_conf->rootfs.managed = true;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 static int set_config_rootfs_mount(const char *key, const char *value,
                                   struct lxc_conf *lxc_conf, void *data)
 {
@@ -2154,7 +2558,32 @@ static int set_config_rootfs_mount(const char *key, const char *value,
 static int set_config_rootfs_options(const char *key, const char *value,
                                     struct lxc_conf *lxc_conf, void *data)
 {
-       return set_config_string_item(&lxc_conf->rootfs.options, value);
+       int ret;
+       unsigned long mflags = 0, pflags = 0;
+       char *mdata = NULL, *opts = NULL;
+       struct lxc_rootfs *rootfs = &lxc_conf->rootfs;
+
+       ret = parse_mntopts(value, &mflags, &mdata);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = parse_propagationopts(value, &pflags);
+       if (ret < 0) {
+               free(mdata);
+               return -EINVAL;
+       }
+
+       ret = set_config_string_item(&opts, value);
+       if (ret < 0) {
+               free(mdata);
+               return -ENOMEM;
+       }
+
+       rootfs->mountflags = mflags | pflags;
+       rootfs->options = opts;
+       rootfs->data = mdata;
+
+       return 0;
 }
 
 static int set_config_uts_name(const char *key, const char *value,
@@ -2186,9 +2615,8 @@ static int set_config_uts_name(const char *key, const char *value,
 static int set_config_namespace_clone(const char *key, const char *value,
                                      struct lxc_conf *lxc_conf, void *data)
 {
-       char *ns, *nsptr, *token;
+       char *ns, *token;
        int cloneflag = 0;
-       char *saveptr = NULL;
 
        if (lxc_config_value_empty(value))
                return clr_config_namespace_clone(key, lxc_conf, data);
@@ -2203,9 +2631,8 @@ static int set_config_namespace_clone(const char *key, const char *value,
        ns = strdup(value);
        if (!ns)
                return -1;
-       nsptr = ns;
 
-       for (; (token = strtok_r(nsptr, " \t", &saveptr)); nsptr = NULL) {
+       lxc_iterate_parts(token, ns, " \t") {
                token += lxc_char_left_gc(token, strlen(token));
                token[lxc_char_right_gc(token, strlen(token))] = '\0';
                cloneflag = lxc_namespace_2_cloneflag(token);
@@ -2223,9 +2650,8 @@ static int set_config_namespace_clone(const char *key, const char *value,
 static int set_config_namespace_keep(const char *key, const char *value,
                                     struct lxc_conf *lxc_conf, void *data)
 {
-       char *ns, *nsptr, *token;
+       char *ns, *token;
        int cloneflag = 0;
-       char *saveptr = NULL;
 
        if (lxc_config_value_empty(value))
                return clr_config_namespace_keep(key, lxc_conf, data);
@@ -2240,9 +2666,8 @@ static int set_config_namespace_keep(const char *key, const char *value,
        ns = strdup(value);
        if (!ns)
                return -1;
-       nsptr = ns;
 
-       for (; (token = strtok_r(nsptr, " \t", &saveptr)); nsptr = NULL) {
+       lxc_iterate_parts(token, ns, " \t") {
                token += lxc_char_left_gc(token, strlen(token));
                token[lxc_char_right_gc(token, strlen(token))] = '\0';
                cloneflag = lxc_namespace_2_cloneflag(token);
@@ -2266,7 +2691,7 @@ static int set_config_namespace_share(const char *key, const char *value,
        if (lxc_config_value_empty(value))
                return clr_config_namespace_share(key, lxc_conf, data);
 
-       namespace = key + sizeof("lxc.namespace.share.") - 1;
+       namespace = key + STRLITERALLEN("lxc.namespace.share.");
        ns_idx = lxc_namespace_2_ns_idx(namespace);
        if (ns_idx < 0)
                return ns_idx;
@@ -2357,6 +2782,7 @@ static int parse_line(char *buffer, void *data)
 
 on_error:
        free(linep);
+
        return ret;
 }
 
@@ -2430,16 +2856,11 @@ on_error:
 
 int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
 {
-       int ret;
        struct parse_line_conf c;
 
        c.conf = conf;
        c.from_include = from_include;
 
-       ret = access(file, R_OK);
-       if (ret < 0)
-               return -1;
-
        /* Catch only the top level config file name in the structure. */
        if (!conf->rcfile)
                conf->rcfile = strdup(file);
@@ -2462,6 +2883,7 @@ int lxc_config_define_add(struct lxc_list *defines, char *arg)
        }
 
        lxc_list_add_tail(defines, dent);
+
        return 0;
 }
 
@@ -2478,6 +2900,7 @@ bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c)
        }
 
        lxc_config_define_free(defines);
+
        return bret;
 }
 
@@ -2541,7 +2964,7 @@ signed long lxc_config_parse_arch(const char *arch)
 
 int lxc_fill_elevated_privileges(char *flaglist, int *flags)
 {
-       char *token, *saveptr = NULL;
+       char *token;
        int i, aflag;
        struct {
                const char *token;
@@ -2563,8 +2986,7 @@ int lxc_fill_elevated_privileges(char *flaglist, int *flags)
                return 0;
        }
 
-       token = strtok_r(flaglist, "|", &saveptr);
-       while (token) {
+       lxc_iterate_parts(token, flaglist, "|") {
                aflag = -1;
 
                for (i = 0; all_privs[i].token; i++)
@@ -2575,8 +2997,6 @@ int lxc_fill_elevated_privileges(char *flaglist, int *flags)
                        return -1;
 
                *flags |= aflag;
-
-               token = strtok_r(NULL, "|", &saveptr);
        }
 
        return 0;
@@ -2603,12 +3023,12 @@ int write_config(int fd, const struct lxc_conf *conf)
 bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
                                 const char *v)
 {
+       __do_free char *tmp = NULL;
        int ret;
        size_t len;
-       char *tmp;
 
        len = strlen(key) + strlen(v) + 4;
-       tmp = alloca(len);
+       tmp = must_realloc(NULL, len);
 
        if (lxc_config_value_empty(v))
                ret = snprintf(tmp, len, "%s =", key);
@@ -2636,14 +3056,17 @@ void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
        while (*lstart) {
                lend = strchr(lstart, '\n');
                char v;
+
                if (!lend)
                        lend = lstart + strlen(lstart);
                else
                        lend++;
+
                if (strncmp(lstart, key, strlen(key)) != 0) {
                        lstart = lend;
                        continue;
                }
+
                if (!rm_subkeys) {
                        v = lstart[strlen(key)];
                        if (!isspace(v) && v != '=') {
@@ -2651,11 +3074,14 @@ void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
                                continue;
                        }
                }
+
                conf->unexpanded_len -= (lend - lstart);
+
                if (*lend == '\0') {
                        *lstart = '\0';
                        return;
                }
+
                memmove(lstart, lend, strlen(lend) + 1);
        }
 }
@@ -2664,21 +3090,23 @@ bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
                                  const char *newpath, const char *oldname,
                                  const char *newname, const char *ovldir)
 {
+       __do_free char *newdir = NULL,
+                                                        *olddir = NULL;
        int ret;
-       char *lend, *newdir, *olddir, *p, *q;
+       char *lend, *p, *q;
        size_t newdirlen, olddirlen;
        char *lstart = conf->unexpanded_config;
        const char *key = "lxc.mount.entry";
 
        olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
-       olddir = alloca(olddirlen + 1);
+       olddir = must_realloc(NULL, olddirlen + 1);
        ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath,
                       oldname);
        if (ret < 0 || ret >= olddirlen + 1)
                return false;
 
        newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
-       newdir = alloca(newdirlen + 1);
+       newdir = must_realloc(NULL, newdirlen + 1);
        ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath,
                       newname);
        if (ret < 0 || ret >= newdirlen + 1)
@@ -2727,9 +3155,10 @@ bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
                if (olddirlen >= newdirlen) {
                        size_t diff = olddirlen - newdirlen;
                        memcpy(q, newdir, newdirlen);
+
                        if (olddirlen != newdirlen) {
                                memmove(q + newdirlen, q + newdirlen + diff,
-                                       strlen(q) - newdirlen - diff + 1);
+                                       strlen(q) - newdirlen - diff + 1);
                                lend -= diff;
                                conf->unexpanded_len -= diff;
                        }
@@ -2748,15 +3177,18 @@ bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
                        conf->unexpanded_alloced = newlen + 1;
                        new[newlen - 1] = '\0';
                        lend = new + (lend - conf->unexpanded_config);
+
                        /* Move over the remainder to make room for the newdir.
                         */
                        memmove(new + poffset + newdirlen,
-                               new + poffset + olddirlen,
-                               oldlen - poffset - olddirlen + 1);
+                               new + poffset + olddirlen,
+                               oldlen - poffset - olddirlen + 1);
                        conf->unexpanded_config = new;
+
                        memcpy(new + poffset, newdir, newdirlen);
                        lend += diff;
                }
+
        next:
                lstart = lend;
        }
@@ -2768,20 +3200,22 @@ bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
                              const char *newpath, const char *oldname,
                              const char *newname)
 {
+       __do_free char *newdir = NULL,
+                                                        *olddir = NULL;
        int ret;
-       char *lend, *newdir, *olddir, *p;
+       char *lend, *p;
        char *lstart = conf->unexpanded_config;
        size_t newdirlen, olddirlen;
        const char *key = "lxc.hook";
 
        olddirlen = strlen(oldpath) + strlen(oldname) + 1;
-       olddir = alloca(olddirlen + 1);
+       olddir = must_realloc(NULL, olddirlen + 1);
        ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
        if (ret < 0 || ret >= olddirlen + 1)
                return false;
 
        newdirlen = strlen(newpath) + strlen(newname) + 1;
-       newdir = alloca(newdirlen + 1);
+       newdir = must_realloc(NULL, newdirlen + 1);
        ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
        if (ret < 0 || ret >= newdirlen + 1)
                return false;
@@ -2817,9 +3251,10 @@ bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
                if (olddirlen >= newdirlen) {
                        size_t diff = olddirlen - newdirlen;
                        memcpy(p, newdir, newdirlen);
+
                        if (olddirlen != newdirlen) {
                                memmove(p + newdirlen, p + newdirlen + diff,
-                                       strlen(p) - newdirlen - diff + 1);
+                                       strlen(p) - newdirlen - diff + 1);
                                lend -= diff;
                                conf->unexpanded_len -= diff;
                        }
@@ -2838,15 +3273,18 @@ bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
                        conf->unexpanded_alloced = newlen + 1;
                        new[newlen - 1] = '\0';
                        lend = new + (lend - conf->unexpanded_config);
+
                        /* Move over the remainder to make room for the newdir.
                         */
                        memmove(new + poffset + newdirlen,
-                               new + poffset + olddirlen,
-                               oldlen - poffset - olddirlen + 1);
+                               new + poffset + olddirlen,
+                               oldlen - poffset - olddirlen + 1);
                        conf->unexpanded_config = new;
+
                        memcpy(new + poffset, newdir, newdirlen);
                        lend += diff;
                }
+
        next:
                lstart = lend;
        }
@@ -2888,7 +3326,7 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
                else
                        lend++;
 
-               if (!lxc_config_net_hwaddr(lstart)) {
+               if (!lxc_config_net_is_hwaddr(lstart)) {
                        lstart = lend;
                        continue;
                }
@@ -2969,6 +3407,7 @@ static int set_config_log_syslog(const char *key, const char *value,
                return -1;
 
        lxc_log_syslog(facility);
+
        return set_config_string_item(&lxc_conf->syslog, value);
 }
 
@@ -3091,7 +3530,7 @@ static int get_config_selinux_context(const char *key, char *retv, int inlen,
 /* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
  * just the value(s) will be printed. Since there still could be more than one,
  * it is newline-separated.
- * (Maybe that's ambigous, since some values, i.e. devices.list, will already
+ * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
  * have newlines?)
  * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
  * 'lxc.cgroup.subsystem.key = value' format.
@@ -3115,11 +3554,11 @@ static int __get_config_cgroup_controller(const char *key, char *retv,
        if (version == CGROUP2_SUPER_MAGIC) {
                global_token = "lxc.cgroup2";
                namespaced_token = "lxc.cgroup2.";
-               namespaced_token_len = sizeof("lxc.cgroup2.") - 1;;
+               namespaced_token_len = STRLITERALLEN("lxc.cgroup2.");
        } else if (version == CGROUP_SUPER_MAGIC) {
                global_token = "lxc.cgroup";
                namespaced_token = "lxc.cgroup.";
-               namespaced_token_len = sizeof("lxc.cgroup.") - 1;;
+               namespaced_token_len = STRLITERALLEN("lxc.cgroup.");
        } else {
                return -1;
        }
@@ -3138,9 +3577,9 @@ static int __get_config_cgroup_controller(const char *key, char *retv,
                        if (version != cg->version)
                                continue;
 
-                       strprint(retv, inlen, "%s.%s = %s\n",
-                                global_token, cg->subsystem, cg->value);
-               } else if (!strcmp(cg->subsystem, key)) {
+                       strprint(retv, inlen, "%s.%s = %s\n", global_token,
+                                cg->subsystem, cg->value);
+               } else if (strcmp(cg->subsystem, key) == 0) {
                        strprint(retv, inlen, "%s\n", cg->value);
                }
        }
@@ -3178,6 +3617,14 @@ static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static inline int get_config_cgroup_relative(const char *key, char *retv,
+                                            int inlen, struct lxc_conf *lxc_conf,
+                                            void *data)
+{
+       return lxc_get_conf_int(lxc_conf, retv, inlen,
+                               lxc_conf->cgroup_meta.relative);
+}
+
 static int get_config_idmaps(const char *key, char *retv, int inlen,
                             struct lxc_conf *c, void *data)
 {
@@ -3192,19 +3639,19 @@ static int get_config_idmaps(const char *key, char *retv, int inlen,
  * +
  * sizeof(" ")
  * +
- * sizeof(uint64_t)
+ * sizeof(uint32_t)
  * +
  * sizeof(" ")
  * +
- * sizeof(uint64_t)
+ * sizeof(uint32_t)
  * +
  * sizeof(" ")
  * +
- * sizeof(uint64_t)
+ * sizeof(uint32_t)
  * +
  * \0
  */
-#define __LXC_IDMAP_STR_BUF (3 * LXC_NUMSTRLEN64 + 3 + 1 + 1)
+#define __LXC_IDMAP_STR_BUF (3 * INTTYPE_TO_STRLEN(uint32_t) + 3 + 1 + 1)
        char buf[__LXC_IDMAP_STR_BUF];
 
        if (!retv)
@@ -3213,8 +3660,7 @@ static int get_config_idmaps(const char *key, char *retv, int inlen,
                memset(retv, 0, inlen);
 
        listlen = lxc_list_len(&c->id_map);
-       lxc_list_for_each(it, &c->id_map)
-       {
+       lxc_list_for_each(it, &c->id_map) {
                struct id_map *map = it->elem;
                ret = snprintf(buf, __LXC_IDMAP_STR_BUF, "%c %lu %lu %lu",
                               (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
@@ -3224,6 +3670,7 @@ static int get_config_idmaps(const char *key, char *retv, int inlen,
 
                strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
        }
+
        return fulllen;
 }
 
@@ -3347,6 +3794,12 @@ static int get_config_rootfs_path(const char *key, char *retv, int inlen,
        return lxc_get_conf_str(retv, inlen, c->rootfs.path);
 }
 
+static int get_config_rootfs_managed(const char *key, char *retv, int inlen,
+                                    struct lxc_conf *c, void *data)
+{
+       return lxc_get_conf_bool(c, retv, inlen, c->rootfs.managed);
+}
+
 static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
                                   struct lxc_conf *c, void *data)
 {
@@ -3376,19 +3829,23 @@ static int get_config_hooks(const char *key, char *retv, int inlen,
        int i;
 
        subkey = strchr(key, '.');
-       if (subkey)
-               subkey = strchr(subkey + 1, '.');
+       if (!subkey)
+               return -1;
+
+       subkey = strchr(subkey + 1, '.');
        if (!subkey)
                return -1;
        subkey++;
-       if (!*subkey)
+       if (*subkey == '\0')
                return -1;
+
        for (i = 0; i < NUM_LXC_HOOKS; i++) {
                if (strcmp(lxchook_names[i], subkey) == 0) {
                        found = i;
                        break;
                }
        }
+
        if (found == -1)
                return -1;
 
@@ -3400,6 +3857,7 @@ static int get_config_hooks(const char *key, char *retv, int inlen,
        lxc_list_for_each(it, &c->hooks[found]) {
                strprint(retv, inlen, "%s\n", (char *)it->elem);
        }
+
        return fulllen;
 }
 
@@ -3497,11 +3955,45 @@ static int get_config_console_size(const char *key, char *retv, int inlen,
        return lxc_get_conf_uint64(c, retv, inlen, c->console.log_size);
 }
 
+static int get_config_seccomp_allow_nesting(const char *key, char *retv,
+                                           int inlen, struct lxc_conf *c,
+                                           void *data)
+{
+#ifdef HAVE_SECCOMP
+       return lxc_get_conf_int(c, retv, inlen, c->seccomp.allow_nesting);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+static int get_config_seccomp_notify_cookie(const char *key, char *retv, int inlen,
+                                           struct lxc_conf *c, void *data)
+{
+#ifdef HAVE_SECCOMP_NOTIFY
+       return lxc_get_conf_str(retv, inlen, c->seccomp.notifier.cookie);
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
+
+static int get_config_seccomp_notify_proxy(const char *key, char *retv, int inlen,
+                                          struct lxc_conf *c, void *data)
+{
+#ifdef HAVE_SECCOMP_NOTIFY
+       return lxc_get_conf_str(retv, inlen,
+                               (c->seccomp.notifier.proxy_addr.sun_path[0]) == '/'
+                                   ? &c->seccomp.notifier.proxy_addr.sun_path[0]
+                                   : &c->seccomp.notifier.proxy_addr.sun_path[1]);
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
 
 static int get_config_seccomp_profile(const char *key, char *retv, int inlen,
                                      struct lxc_conf *c, void *data)
 {
-       return lxc_get_conf_str(retv, inlen, c->seccomp);
+       return lxc_get_conf_str(retv, inlen, c->seccomp.seccomp);
 }
 
 static int get_config_autodev(const char *key, char *retv, int inlen,
@@ -3643,7 +4135,7 @@ static int get_config_no_new_privs(const char *key, char *retv, int inlen,
  * printed, in 'lxc.prlimit.resource = value' format.
  */
 static int get_config_prlimit(const char *key, char *retv, int inlen,
-                           struct lxc_conf *c, void *data)
+                             struct lxc_conf *c, void *data)
 {
        int fulllen = 0, len;
        bool get_all = false;
@@ -3662,23 +4154,23 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
                return -1;
 
        lxc_list_for_each(it, &c->limits) {
-               char buf[LXC_NUMSTRLEN64 * 2 + 2]; /* 2 colon separated 64 bit
-                                                     integers or the word
-                                                     'unlimited' */
+               /* 2 colon separated 64 bit integers or the word 'unlimited' */
+               char buf[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
                int partlen;
                struct lxc_limit *lim = it->elem;
 
                if (lim->limit.rlim_cur == RLIM_INFINITY) {
-                       memcpy(buf, "unlimited", sizeof("unlimited"));
-                       partlen = sizeof("unlimited") - 1;
+                       memcpy(buf, "unlimited", STRLITERALLEN("unlimited") + 1);
+                       partlen = STRLITERALLEN("unlimited");
                } else {
                        partlen = sprintf(buf, "%" PRIu64,
                                          (uint64_t)lim->limit.rlim_cur);
                }
+
                if (lim->limit.rlim_cur != lim->limit.rlim_max) {
                        if (lim->limit.rlim_max == RLIM_INFINITY)
                                memcpy(buf + partlen, ":unlimited",
-                                      sizeof(":unlimited"));
+                                      STRLITERALLEN(":unlimited") + 1);
                        else
                                sprintf(buf + partlen, ":%" PRIu64,
                                        (uint64_t)lim->limit.rlim_max);
@@ -3687,7 +4179,7 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
                if (get_all) {
                        strprint(retv, inlen, "lxc.prlimit.%s = %s\n",
                                 lim->resource, buf);
-               } else if (!strcmp(lim->resource, key)) {
+               } else if (strcmp(lim->resource, key) == 0) {
                        strprint(retv, inlen, "%s", buf);
                }
        }
@@ -3700,7 +4192,7 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
  * 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)
+                            struct lxc_conf *c, void *data)
 {
        int len;
        struct lxc_list *it;
@@ -3714,16 +4206,16 @@ static int get_config_sysctl(const char *key, char *retv, int 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 if (strncmp(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")) == 0)
+               key += STRLITERALLEN("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);
+                       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);
                }
@@ -3733,7 +4225,7 @@ static int get_config_sysctl(const char *key, char *retv, int inlen,
 }
 
 static int get_config_proc(const char *key, char *retv, int inlen,
-                           struct lxc_conf *c, void *data)
+                          struct lxc_conf *c, void *data)
 {
        struct lxc_list *it;
        int len;
@@ -3747,8 +4239,8 @@ static int get_config_proc(const char *key, char *retv, int inlen,
 
        if (strcmp(key, "lxc.proc") == 0)
                get_all = true;
-       else if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") - 1) == 0)
-               key += sizeof("lxc.proc.") - 1;
+       else if (strncmp(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")) == 0)
+               key += STRLITERALLEN("lxc.proc.");
        else
                return -1;
 
@@ -3757,7 +4249,7 @@ static int get_config_proc(const char *key, char *retv, int inlen,
 
                if (get_all) {
                        strprint(retv, inlen, "lxc.proc.%s = %s\n",
-                                proc->filename, proc->value);
+                                proc->filename, proc->value);
                } else if (strcmp(proc->filename, key) == 0) {
                        strprint(retv, inlen, "%s", proc->value);
                }
@@ -3816,7 +4308,7 @@ static int get_config_namespace_share(const char *key, char *retv, int inlen,
        else
                memset(retv, 0, inlen);
 
-       namespace = key + sizeof("lxc.namespace.share.") - 1;
+       namespace = key + STRLITERALLEN("lxc.namespace.share.");
        ns_idx = lxc_namespace_2_ns_idx(namespace);
        if (ns_idx < 0)
                return ns_idx;
@@ -3918,6 +4410,14 @@ static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
        return 0;
 }
 
+static inline int clr_config_cgroup_relative(const char *key,
+                                            struct lxc_conf *lxc_conf,
+                                            void *data)
+{
+       lxc_conf->cgroup_meta.relative = false;
+       return 0;
+}
+
 static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
                                    void *data)
 {
@@ -3967,6 +4467,13 @@ static inline int clr_config_rootfs_path(const char *key, struct lxc_conf *c,
        return 0;
 }
 
+static inline int clr_config_rootfs_managed(const char *key, struct lxc_conf *c,
+                                           void *data)
+{
+       c->rootfs.managed = true;
+       return 0;
+}
+
 static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c,
                                          void *data)
 {
@@ -3980,6 +4487,10 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
 {
        free(c->rootfs.options);
        c->rootfs.options = NULL;
+
+       free(c->rootfs.data);
+       c->rootfs.data = NULL;
+
        return 0;
 }
 
@@ -4062,11 +4573,47 @@ static inline int clr_config_console_size(const char *key, struct lxc_conf *c,
        return 0;
 }
 
+static inline int clr_config_seccomp_allow_nesting(const char *key,
+                                                  struct lxc_conf *c, void *data)
+{
+#ifdef HAVE_SECCOMP
+       c->seccomp.allow_nesting = 0;
+       return 0;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+static inline int clr_config_seccomp_notify_cookie(const char *key,
+                                                  struct lxc_conf *c, void *data)
+{
+#ifdef HAVE_SECCOMP_NOTIFY
+       free(c->seccomp.notifier.cookie);
+       c->seccomp.notifier.cookie = NULL;
+       return 0;
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
+
+static inline int clr_config_seccomp_notify_proxy(const char *key,
+                                                  struct lxc_conf *c, void *data)
+{
+#ifdef HAVE_SECCOMP_NOTIFY
+       memset(&c->seccomp.notifier.proxy_addr, 0,
+              sizeof(c->seccomp.notifier.proxy_addr));
+       return 0;
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
+
 static inline int clr_config_seccomp_profile(const char *key,
                                             struct lxc_conf *c, void *data)
 {
-       free(c->seccomp);
-       c->seccomp = NULL;
+       free(c->seccomp.seccomp);
+       c->seccomp.seccomp = NULL;
        return 0;
 }
 
@@ -4242,7 +4789,7 @@ static int clr_config_namespace_share(const char *key,
        int ns_idx;
        const char *namespace;
 
-       namespace = key + sizeof("lxc.namespace.share.") - 1;
+       namespace = key + STRLITERALLEN("lxc.namespace.share.");
        ns_idx = lxc_namespace_2_ns_idx(namespace);
        if (ns_idx < 0)
                return ns_idx;
@@ -4301,7 +4848,7 @@ static struct lxc_config_t *get_network_config_ops(const char *key,
        ret = lxc_safe_uint((idx_start + 1), &tmpidx);
        if (ret < 0) {
                errno = -ret;
-               SYSERROR("Failed to parse usigned integer from string \"%s\"",
+               SYSERROR("Failed to parse unsigned integer from string \"%s\"",
                         idx_start + 1);
                *idx = ret;
                goto on_error;
@@ -4313,7 +4860,7 @@ static struct lxc_config_t *get_network_config_ops(const char *key,
         */
        if (tmpidx == INT_MAX) {
                SYSERROR("Number of configured networks would overflow the "
-                        "counter");
+                        "counter");
                goto on_error;
        }
        *idx = tmpidx;
@@ -4384,6 +4931,7 @@ static int set_config_net_nic(const char *key, const char *value,
 
        ret = config->set(deindexed_key, value, lxc_conf, netdev);
        free(deindexed_key);
+
        return ret;
 }
 
@@ -4429,6 +4977,7 @@ static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
 
        ret = config->clr(deindexed_key, lxc_conf, netdev);
        free(deindexed_key);
+
        return ret;
 }
 
@@ -4484,6 +5033,19 @@ static int clr_config_net_link(const char *key, struct lxc_conf *lxc_conf,
        return 0;
 }
 
+static int clr_config_net_l2proxy(const char *key, struct lxc_conf *lxc_conf,
+                              void *data)
+{
+       struct lxc_netdev *netdev = data;
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       netdev->l2proxy = false;
+
+       return 0;
+}
+
 static int clr_config_net_macvlan_mode(const char *key,
                                       struct lxc_conf *lxc_conf, void *data)
 {
@@ -4500,6 +5062,38 @@ static int clr_config_net_macvlan_mode(const char *key,
        return 0;
 }
 
+static int clr_config_net_ipvlan_mode(const char *key,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_IPVLAN)
+               return 0;
+
+       netdev->priv.ipvlan_attr.mode = -1;
+
+       return 0;
+}
+
+static int clr_config_net_ipvlan_isolation(const char *key,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_IPVLAN)
+               return 0;
+
+       netdev->priv.ipvlan_attr.isolation = -1;
+
+       return 0;
+}
+
 static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
                                    void *data)
 {
@@ -4614,6 +5208,24 @@ static int clr_config_net_ipv4_address(const char *key,
        return 0;
 }
 
+static int clr_config_net_veth_ipv4_route(const char *key,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+       struct lxc_list *cur, *next;
+
+       if (!netdev)
+               return -1;
+
+       lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
+               lxc_list_del(cur);
+               free(cur->elem);
+               free(cur);
+       }
+
+       return 0;
+}
+
 static int clr_config_net_ipv6_gateway(const char *key,
                                       struct lxc_conf *lxc_conf, void *data)
 {
@@ -4646,6 +5258,24 @@ static int clr_config_net_ipv6_address(const char *key,
        return 0;
 }
 
+static int clr_config_net_veth_ipv6_route(const char *key,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+       struct lxc_list *cur, *next;
+
+       if (!netdev)
+               return -1;
+
+       lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
+               lxc_list_del(cur);
+               free(cur->elem);
+               free(cur);
+       }
+
+       return 0;
+}
+
 static int get_config_net_nic(const char *key, char *retv, int inlen,
                              struct lxc_conf *c, void *data)
 {
@@ -4672,6 +5302,7 @@ static int get_config_net_nic(const char *key, char *retv, int inlen,
 
        ret = config->get(deindexed_key, retv, inlen, c, netdev);
        free(deindexed_key);
+
        return ret;
 }
 
@@ -4737,6 +5368,13 @@ static int get_config_net_link(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_net_l2proxy(const char *key, char *retv, int inlen,
+                              struct lxc_conf *c, void *data)
+{
+       struct lxc_netdev *netdev = data;
+       return lxc_get_conf_bool(c, retv, inlen, netdev->l2proxy);
+}
+
 static int get_config_net_name(const char *key, char *retv, int inlen,
                               struct lxc_conf *c, void *data)
 {
@@ -4800,6 +5438,84 @@ static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_net_ipvlan_mode(const char *key, char *retv, int inlen,
+                                      struct lxc_conf *c, void *data)
+{
+       int len;
+       int fulllen = 0;
+       const char *mode;
+       struct lxc_netdev *netdev = data;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_IPVLAN)
+               return 0;
+
+       switch (netdev->priv.ipvlan_attr.mode) {
+       case IPVLAN_MODE_L3:
+               mode = "l3";
+               break;
+       case IPVLAN_MODE_L3S:
+               mode = "l3s";
+               break;
+       case IPVLAN_MODE_L2:
+               mode = "l2";
+               break;
+       default:
+               mode = "(invalid)";
+               break;
+       }
+
+       strprint(retv, inlen, "%s", mode);
+
+       return fulllen;
+}
+
+static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inlen,
+                                      struct lxc_conf *c, void *data)
+{
+       int len;
+       int fulllen = 0;
+       const char *mode;
+       struct lxc_netdev *netdev = data;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_IPVLAN)
+               return 0;
+
+       switch (netdev->priv.ipvlan_attr.isolation) {
+       case IPVLAN_ISOLATION_BRIDGE:
+               mode = "bridge";
+               break;
+       case IPVLAN_ISOLATION_PRIVATE:
+               mode = "private";
+               break;
+       case IPVLAN_ISOLATION_VEPA:
+               mode = "vepa";
+               break;
+       default:
+               mode = "(invalid)";
+               break;
+       }
+
+       strprint(retv, inlen, "%s", mode);
+
+       return fulllen;
+}
+
 static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
                                    struct lxc_conf *c, void *data)
 {
@@ -4951,6 +5667,8 @@ static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
 
        if (netdev->ipv4_gateway_auto) {
                strprint(retv, inlen, "auto");
+       } else if (netdev->ipv4_gateway_dev) {
+               strprint(retv, inlen, "dev");
        } else if (netdev->ipv4_gateway) {
                inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
                strprint(retv, inlen, "%s", buf);
@@ -4978,6 +5696,7 @@ static int get_config_net_ipv4_address(const char *key, char *retv, int inlen,
                return -1;
 
        listlen = lxc_list_len(&netdev->ipv4);
+
        lxc_list_for_each(it, &netdev->ipv4) {
                struct lxc_inetdev *i = it->elem;
                inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
@@ -4988,6 +5707,39 @@ static int get_config_net_ipv4_address(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_net_veth_ipv4_route(const char *key, char *retv, int inlen,
+                                      struct lxc_conf *c, void *data)
+{
+       int len;
+       size_t listlen;
+       char buf[INET_ADDRSTRLEN];
+       struct lxc_list *it;
+       int fulllen = 0;
+       struct lxc_netdev *netdev = data;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH)
+               return 0;
+
+       listlen = lxc_list_len(&netdev->priv.veth_attr.ipv4_routes);
+
+       lxc_list_for_each(it, &netdev->priv.veth_attr.ipv4_routes) {
+               struct lxc_inetdev *i = it->elem;
+               inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
+               strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
+                        (listlen-- > 1) ? "\n" : "");
+       }
+
+       return fulllen;
+}
+
 static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
                                       struct lxc_conf *c, void *data)
 {
@@ -5006,6 +5758,8 @@ static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
 
        if (netdev->ipv6_gateway_auto) {
                strprint(retv, inlen, "auto");
+       } else if (netdev->ipv6_gateway_dev) {
+               strprint(retv, inlen, "dev");
        } else if (netdev->ipv6_gateway) {
                inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
                strprint(retv, inlen, "%s", buf);
@@ -5033,6 +5787,7 @@ static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
                return -1;
 
        listlen = lxc_list_len(&netdev->ipv6);
+
        lxc_list_for_each(it, &netdev->ipv6) {
                struct lxc_inet6dev *i = it->elem;
                inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
@@ -5043,6 +5798,39 @@ static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_net_veth_ipv6_route(const char *key, char *retv, int inlen,
+                                      struct lxc_conf *c, void *data)
+{
+       int len;
+       size_t listlen;
+       char buf[INET6_ADDRSTRLEN];
+       struct lxc_list *it;
+       int fulllen = 0;
+       struct lxc_netdev *netdev = data;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH)
+               return 0;
+
+       listlen = lxc_list_len(&netdev->priv.veth_attr.ipv6_routes);
+
+       lxc_list_for_each(it, &netdev->priv.veth_attr.ipv6_routes) {
+               struct lxc_inet6dev *i = it->elem;
+               inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
+               strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
+                        (listlen-- > 1) ? "\n" : "");
+       }
+
+       return fulllen;
+}
+
 int lxc_list_config_items(char *retv, int inlen)
 {
        size_t i;
@@ -5054,8 +5842,8 @@ int lxc_list_config_items(char *retv, int inlen)
        else
                memset(retv, 0, inlen);
 
-       for (i = 0; i < config_size; i++) {
-               char *s = config[i].name;
+       for (i = 0; i < config_jump_table_size; i++) {
+               char *s = config_jump_table[i].name;
 
                if (s[strlen(s) - 1] == '.')
                        continue;
@@ -5160,6 +5948,7 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
        strprint(retv, inlen, "type\n");
        strprint(retv, inlen, "script.up\n");
        strprint(retv, inlen, "script.down\n");
+
        if (netdev->type != LXC_NET_EMPTY) {
                strprint(retv, inlen, "flags\n");
                strprint(retv, inlen, "link\n");
@@ -5175,10 +5964,16 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
        switch (netdev->type) {
        case LXC_NET_VETH:
                strprint(retv, inlen, "veth.pair\n");
+               strprint(retv, inlen, "veth.ipv4.route\n");
+               strprint(retv, inlen, "veth.ipv6.route\n");
                break;
        case LXC_NET_MACVLAN:
                strprint(retv, inlen, "macvlan.mode\n");
                break;
+       case LXC_NET_IPVLAN:
+               strprint(retv, inlen, "ipvlan.mode\n");
+               strprint(retv, inlen, "ipvlan.isolation\n");
+               break;
        case LXC_NET_VLAN:
                strprint(retv, inlen, "vlan.id\n");
                break;