/* Block ("allowlist") all devices by default. */
new->bpf_devices.list_type = LXC_BPF_DEVICE_CGROUP_ALLOWLIST;
lxc_list_init(&(new->bpf_devices).device_item);
- lxc_list_init(&new->network);
lxc_list_init(&new->mount_list);
lxc_list_init(&new->caps);
lxc_list_init(&new->keepcaps);
memset(&new->timens, 0, sizeof(struct timens_offsets));
seccomp_conf_init(new);
+ INIT_LIST_HEAD(&new->netdevs);
+
return new;
}
if (ret < 0)
return log_error(-1, "Failed to receive veth names from parent");
- ret = lxc_setup_network_in_child_namespaces(lxc_conf,
- &lxc_conf->network);
+ ret = lxc_setup_network_in_child_namespaces(lxc_conf);
if (ret < 0)
return log_error(-1, "Failed to setup network");
}
free(conf->init_cwd);
free(conf->unexpanded_config);
free(conf->syslog);
- lxc_free_networks(&conf->network);
+ lxc_free_networks(conf);
free(conf->lsm_aa_profile);
free(conf->lsm_aa_profile_computed);
free(conf->lsm_se_context);
#include "caps.h"
#include "compiler.h"
#include "config.h"
+#include "hlist.h"
#include "list.h"
#include "lxcseccomp.h"
#include "memory_utils.h"
const struct id_map *root_nsgid_map;
};
- struct lxc_list network;
+ struct list_head netdevs;
struct {
char *fstab;
bool network_new_hwaddrs(struct lxc_conf *conf)
{
char *lend, *p, *p2;
- struct lxc_list *it;
char *lstart = conf->unexpanded_config;
if (!conf->unexpanded_config)
while (*lstart) {
char newhwaddr[18], oldhwaddr[17];
+ struct lxc_netdev *netdev;
lend = strchr(lstart, '\n');
if (!lend)
return false;
memcpy(p, newhwaddr, 17);
- lxc_list_for_each(it, &conf->network) {
- struct lxc_netdev *n = it->elem;
-
- if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
- memcpy(n->hwaddr, newhwaddr, 17);
+ list_for_each_entry(netdev, &conf->netdevs, head) {
+ if (netdev->hwaddr && memcmp(oldhwaddr, netdev->hwaddr, 17) == 0)
+ memcpy(netdev->hwaddr, newhwaddr, 17);
}
lstart = lend;
struct lxc_conf *c, void *data)
{
int len, fulllen = 0;
- struct lxc_list *it;
+ struct lxc_netdev *netdev;
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);
- lxc_list_for_each(it, &c->network) {
- struct lxc_netdev *n = it->elem;
- const char *t = lxc_net_type_to_str(n->type);
+ list_for_each_entry(netdev, &c->netdevs, head) {
+ const char *t = lxc_net_type_to_str(netdev->type);
strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
}
static inline int clr_config_net(const char *key, struct lxc_conf *c,
void *data)
{
- lxc_free_networks(&c->network);
+ lxc_free_networks(c);
return 0;
}
return true;
}
-struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
+static struct lxc_netdev *lxc_network_add(struct list_head *head, int idx, bool tail)
{
- __do_free struct lxc_list *newlist = NULL;
__do_free struct lxc_netdev *netdev = NULL;
/* network does not exist */
/* give network a unique index */
netdev->idx = idx;
- /* prepare new list */
- newlist = lxc_list_new();
- if (!newlist)
- return ret_set_errno(NULL, ENOMEM);
- newlist->elem = netdev;
-
if (tail)
- lxc_list_add_tail(networks, newlist);
+ list_add_tail(&netdev->head, head);
else
- lxc_list_add(networks, newlist);
- move_ptr(newlist);
+ list_add(&netdev->head, head);
return move_ptr(netdev);
}
struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
unsigned int idx, bool allocate)
{
- struct lxc_list *networks = &conf->network;
- struct lxc_list *insert = networks;
+ struct list_head *netdevs = &conf->netdevs;
+ struct list_head *head = netdevs;
+ struct lxc_netdev *netdev;
/* lookup network */
- if (!lxc_list_empty(networks)) {
- lxc_list_for_each(insert, networks) {
- struct lxc_netdev *netdev = insert->elem;
-
+ if (!list_empty(netdevs)) {
+ list_for_each_entry(netdev, netdevs, head) {
/* found network device */
if (netdev->idx == idx)
return netdev;
- if (netdev->idx > idx)
+ if (netdev->idx > idx) {
+ head = &netdev->head;
break;
+ }
}
}
if (allocate)
- return lxc_network_add(insert, idx, true);
+ return lxc_network_add(head, idx, true);
return NULL;
}
void lxc_log_configured_netdevs(const struct lxc_conf *conf)
{
struct lxc_netdev *netdev;
- struct lxc_list *it = (struct lxc_list *)&conf->network;;
+ const struct list_head *netdevs = &conf->netdevs;
if (!lxc_log_trace())
return;
- if (lxc_list_empty(it)) {
+ if (list_empty(netdevs)) {
TRACE("container has no networks configured");
return;
}
- lxc_list_for_each(it, &conf->network) {
+ list_for_each_entry(netdev, netdevs, head) {
struct lxc_list *cur, *next;
struct lxc_inetdev *inet4dev;
struct lxc_inet6dev *inet6dev;
char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
- netdev = it->elem;
-
TRACE("index: %zd", netdev->idx);
TRACE("ifindex: %d", netdev->ifindex);
void lxc_clear_netdev(struct lxc_netdev *netdev)
{
struct lxc_list *cur, *next;
+ struct list_head head;
ssize_t idx;
if (!netdev)
}
}
+ head = netdev->head;
memset(netdev, 0, sizeof(struct lxc_netdev));
+ netdev->head = head;
lxc_list_init(&netdev->ipv4);
lxc_list_init(&netdev->ipv6);
netdev->type = -1;
bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
{
- struct lxc_list *cur, *next;
+ struct lxc_netdev *netdev;
- if (lxc_list_empty(&conf->network))
+ if (list_empty(&conf->netdevs))
return false;
- lxc_list_for_each_safe(cur, &conf->network, next) {
- struct lxc_netdev *netdev = cur->elem;
-
+ list_for_each_entry(netdev, &conf->netdevs, head) {
if (netdev->idx != idx)
continue;
- lxc_list_del(cur);
+ list_del(&netdev->head);
lxc_free_netdev(netdev);
- free(cur);
return true;
}
return false;
}
-void lxc_free_networks(struct lxc_list *networks)
+void lxc_free_networks(struct lxc_conf *conf)
{
- struct lxc_list *cur, *next;
+ struct lxc_netdev *netdev, *n;
- lxc_list_for_each_safe (cur, networks, next) {
- struct lxc_netdev *netdev = cur->elem;
+ if (list_empty(&conf->netdevs))
+ return;
- lxc_list_del(cur);
+ list_for_each_entry_safe(netdev, n, &conf->netdevs, head) {
+ list_del(&netdev->head);
lxc_free_netdev(netdev);
- free(cur);
}
/* prevent segfaults */
- lxc_list_init(networks);
+ INIT_LIST_HEAD(&conf->netdevs);
}
static struct lxc_veth_mode {
unsigned long *hostid, unsigned long *range);
__hidden extern bool lxc_config_value_empty(const char *value);
-__hidden extern struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail);
__hidden extern struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf, unsigned int idx,
bool allocate);
__hidden extern void lxc_log_configured_netdevs(const struct lxc_conf *conf);
__hidden extern bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx);
-__hidden extern void lxc_free_networks(struct lxc_list *networks);
+__hidden extern void lxc_free_networks(struct lxc_conf *conf);
__hidden extern void lxc_clear_netdev(struct lxc_netdev *netdev);
__hidden extern int lxc_veth_mode_to_flag(int *mode, const char *value);
__hidden extern char *lxc_veth_flag_to_mode(int mode);
char log[PATH_MAX];
int static_args = 23, ret;
int netnr = 0;
- struct lxc_list *it;
struct mntent mntent;
char buf[4096], ttys[32];
if (ttys[0])
static_args += 2;
- static_args += lxc_list_len(&opts->c->lxc_conf->network) * 2;
+ static_args += list_len(&opts->c->lxc_conf->netdevs) * 2;
} else {
return log_error_errno(-EINVAL, EINVAL, "Invalid criu operation specified");
}
DECLARE_ARG("--leave-running");
} else if (strequal(opts->action, "restore")) {
struct lxc_conf *lxc_conf = opts->c->lxc_conf;
+ struct lxc_netdev *netdev;
DECLARE_ARG("--root");
DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
DECLARE_ARG(buf);
}
- lxc_list_for_each(it, &opts->c->lxc_conf->network) {
+ list_for_each_entry(netdev, &opts->c->lxc_conf->netdevs, head) {
size_t retlen;
char eth[128], *veth;
- struct lxc_netdev *n = it->elem;
bool external_not_veth;
if (cmp_version(opts->criu_version, CRIU_EXTERNAL_NOT_VETH) >= 0) {
external_not_veth = false;
}
- if (n->name[0] != '\0') {
- retlen = strlcpy(eth, n->name, sizeof(eth));
+ if (netdev->name[0] != '\0') {
+ retlen = strlcpy(eth, netdev->name, sizeof(eth));
if (retlen >= sizeof(eth))
return log_error_errno(-E2BIG, E2BIG, "Failed to append veth device name");
} else {
return log_error_errno(-E2BIG, E2BIG, "Failed to append veth device name");
}
- switch (n->type) {
+ switch (netdev->type) {
case LXC_NET_VETH:
- veth = n->priv.veth_attr.pair;
+ veth = netdev->priv.veth_attr.pair;
if (veth[0] == '\0')
- veth = n->priv.veth_attr.veth1;
+ veth = netdev->priv.veth_attr.veth1;
- if (n->link[0] != '\0') {
+ if (netdev->link[0] != '\0') {
if (external_not_veth)
- ret = strnprintf(buf, sizeof(buf), "veth[%s]:%s@%s", eth, veth, n->link);
+ ret = strnprintf(buf, sizeof(buf), "veth[%s]:%s@%s", eth, veth, netdev->link);
else
- ret = strnprintf(buf, sizeof(buf), "%s=%s@%s", eth, veth, n->link);
+ ret = strnprintf(buf, sizeof(buf), "%s=%s@%s", eth, veth, netdev->link);
} else {
if (external_not_veth)
ret = strnprintf(buf, sizeof(buf), "veth[%s]:%s", eth, veth);
TRACE("Added veth device entry %s", buf);
break;
case LXC_NET_MACVLAN:
- if (n->link[0] == '\0')
- return log_error_errno(-EINVAL, EINVAL, "Failed to find host interface for macvlan %s", n->name);
+ if (netdev->link[0] == '\0')
+ return log_error_errno(-EINVAL, EINVAL, "Failed to find host interface for macvlan %s", netdev->name);
- ret = strnprintf(buf, sizeof(buf), "macvlan[%s]:%s", eth, n->link);
+ ret = strnprintf(buf, sizeof(buf), "macvlan[%s]:%s", eth, netdev->link);
if (ret < 0)
return log_error_errno(-EIO, EIO, "Failed to add macvlan entry");
break;
default:
/* we have screened for this earlier... */
- return log_error_errno(-EINVAL, EINVAL, "Unsupported network type %d", n->type);
+ return log_error_errno(-EINVAL, EINVAL, "Unsupported network type %d", netdev->type);
}
if (external_not_veth)
* dump. */
static bool criu_ok(struct lxc_container *c, char **criu_version)
{
- struct lxc_list *it;
+ struct lxc_netdev *netdev;
if (geteuid()) {
ERROR("Must be root to checkpoint");
return false;
/* We only know how to restore containers with veth networks. */
- lxc_list_for_each(it, &c->lxc_conf->network) {
- struct lxc_netdev *n = it->elem;
- switch(n->type) {
+ list_for_each_entry(netdev, &c->lxc_conf->netdevs, head) {
+ switch(netdev->type) {
case LXC_NET_VETH:
case LXC_NET_NONE:
case LXC_NET_EMPTY:
case LXC_NET_MACVLAN:
break;
default:
- ERROR("Found un-dumpable network: %s (%s)", lxc_net_type_to_str(n->type), n->name);
+ ERROR("Found un-dumpable network: %s (%s)", lxc_net_type_to_str(netdev->type), netdev->name);
if (criu_version) {
free(*criu_version);
*criu_version = NULL;
static bool restore_net_info(struct lxc_container *c)
{
int ret;
- struct lxc_list *it;
bool has_error = true;
+ struct lxc_netdev *netdev;
if (container_mem_lock(c))
return false;
- lxc_list_for_each(it, &c->lxc_conf->network) {
- struct lxc_netdev *netdev = it->elem;
+ list_for_each_entry(netdev, &c->lxc_conf->netdevs, head) {
char template[IFNAMSIZ];
if (netdev->type != LXC_NET_VETH)
pos && ({ n = pos->member.next; 1; }); \
pos = hlist_entry_safe(n, typeof(*pos), member))
+static inline size_t list_len(struct list_head *list)
+{
+ size_t i = 0;
+
+ list_for_each(list, list) {
+ i++;
+ }
+
+ return i;
+}
+
#endif /* __LXC_HLIST_H */
int lxc_find_gateway_addresses(struct lxc_handler *handler)
{
- struct lxc_list *network = &handler->conf->network;
- struct lxc_list *iterator;
struct lxc_netdev *netdev;
int link_index;
- lxc_list_for_each(iterator, network) {
- netdev = iterator->elem;
-
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
continue;
if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN)
return log_error_errno(-1, EINVAL, "Automatic gateway detection is only supported for veth and macvlan");
- if (is_empty_string(netdev->link)) {
+ if (is_empty_string(netdev->link))
return log_error_errno(-1, errno, "Automatic gateway detection needs a link interface");
- }
link_index = if_nametoindex(netdev->link);
if (!link_index)
static bool lxc_delete_network_unpriv(struct lxc_handler *handler)
{
int ret;
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
+ struct lxc_netdev *netdev;
/* strlen("/proc/") = 6
* +
* INTTYPE_TO_STRLEN(pid_t)
if (ret < 0)
return false;
- lxc_list_for_each(iterator, network) {
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
char *hostveth = NULL;
- struct lxc_netdev *netdev = iterator->elem;
/* We can only delete devices whose ifindex we have. If we don't
* have the index it means that we didn't create it.
static int lxc_create_network_priv(struct lxc_handler *handler)
{
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
-
- lxc_list_for_each(iterator, network) {
- struct lxc_netdev *netdev = iterator->elem;
+ struct lxc_netdev *netdev;
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE)
return log_error_errno(-1, EINVAL, "Invalid network configuration type %d", netdev->type);
int lxc_network_move_created_netdev_priv(struct lxc_handler *handler)
{
pid_t pid = handler->pid;
- struct lxc_list *network = &handler->conf->network;
- struct lxc_list *iterator;
+ struct lxc_netdev *netdev;
if (am_guest_unpriv())
return 0;
- lxc_list_for_each(iterator, network) {
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
__do_free char *physname = NULL;
int ret;
- struct lxc_netdev *netdev = iterator->elem;
if (!netdev_requires_move(netdev))
continue;
int hooks_version = handler->conf->hooks_version;
const char *lxcname = handler->name;
const char *lxcpath = handler->lxcpath;
- struct lxc_list *network = &handler->conf->network;
pid_t pid = handler->pid;
- struct lxc_list *iterator;
-
- lxc_list_for_each(iterator, network) {
- struct lxc_netdev *netdev = iterator->elem;
+ struct lxc_netdev *netdev;
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
if (!network_requires_advanced_setup(netdev->type))
continue;
static bool lxc_delete_network_priv(struct lxc_handler *handler)
{
int ret;
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
+ struct lxc_netdev *netdev;
- lxc_list_for_each(iterator, network) {
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
char *hostveth = NULL;
- struct lxc_netdev *netdev = iterator->elem;
/* We can only delete devices whose ifindex we have. If we don't
* have the index it means that we didn't create it.
int lxc_requests_empty_network(struct lxc_handler *handler)
{
- struct lxc_list *network = &handler->conf->network;
- struct lxc_list *iterator;
+ struct list_head *netdevs = &handler->conf->netdevs;
bool found_none = false, found_nic = false;
+ struct lxc_netdev *netdev;
- if (lxc_list_empty(network))
+ if (list_empty(netdevs))
return 0;
- lxc_list_for_each (iterator, network) {
- struct lxc_netdev *netdev = iterator->elem;
+ list_for_each_entry(netdev, netdevs, head) {
if (netdev->type == LXC_NET_NONE)
found_none = true;
struct lxc_conf *conf = handler->conf;
int ret;
char ifname[IFNAMSIZ];
- struct lxc_list *iterator;
+ struct lxc_netdev *netdev;
/*
* If we weren't asked to clone a new network namespace, there's
if (ret < 0)
return log_error_errno(-1, errno, "Failed to enter network namespace");
- lxc_list_for_each(iterator, &conf->network) {
- struct lxc_netdev *netdev = iterator->elem;
-
+ list_for_each_entry(netdev, &conf->netdevs, head) {
if (netdev->type != LXC_NET_PHYS)
continue;
*
* That'll brutally fail of course but there's nothing we can do about it.
*/
-int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf,
- struct lxc_list *network)
+int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf)
{
- struct lxc_list *iterator;
bool needs_second_pass = false;
+ struct lxc_netdev *netdev;
+ const struct list_head *netdevs = &conf->netdevs;
- if (lxc_list_empty(network))
+ if (list_empty(netdevs))
return 0;
/* Configure all devices that have a specific target name. */
- lxc_list_for_each(iterator, network) {
- struct lxc_netdev *netdev = iterator->elem;
+ list_for_each_entry(netdev, netdevs, head) {
int ret;
if (is_empty_string(netdev->name) || strequal(netdev->name, "eth%d")) {
if (needs_second_pass) {
/* Configure all devices that have a kernel assigned name. */
- lxc_list_for_each(iterator, network) {
- struct lxc_netdev *netdev = iterator->elem;
+ list_for_each_entry(netdev, netdevs, head) {
int ret;
if (!is_empty_string(netdev->name) && !strequal(netdev->name, "eth%d"))
int lxc_network_send_to_child(struct lxc_handler *handler)
{
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
int data_sock = handler->data_sock[0];
+ struct lxc_netdev *netdev;
- lxc_list_for_each(iterator, network) {
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
int ret;
- struct lxc_netdev *netdev = iterator->elem;
if (!network_requires_advanced_setup(netdev->type))
continue;
int lxc_network_recv_from_parent(struct lxc_handler *handler)
{
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
int data_sock = handler->data_sock[1];
+ struct lxc_netdev *netdev;
- lxc_list_for_each(iterator, network) {
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
int ret;
- struct lxc_netdev *netdev = iterator->elem;
if (!network_requires_advanced_setup(netdev->type))
continue;
int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler)
{
- struct lxc_list *iterator, *network;
int data_sock = handler->data_sock[0];
+ struct lxc_netdev *netdev;
+ struct list_head *netdevs = &handler->conf->netdevs;
if (!handler->am_root)
return 0;
- network = &handler->conf->network;
- lxc_list_for_each(iterator, network) {
+ list_for_each_entry(netdev, netdevs, head) {
int ret;
- struct lxc_netdev *netdev = iterator->elem;
/* Send network device name in the child's namespace to parent. */
ret = lxc_send_nointr(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
TRACE("Sent network device %s with ifindex %d to parent", maybe_empty(netdev->name), netdev->ifindex);
}
- if (!lxc_list_empty(network))
+ if (!list_empty(netdevs))
TRACE("Sent network device names and ifindices to parent");
return 0;
int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler)
{
- struct lxc_list *iterator, *network;
int data_sock = handler->data_sock[1];
+ struct lxc_netdev *netdev;
if (!handler->am_root)
return 0;
- network = &handler->conf->network;
- lxc_list_for_each(iterator, network) {
+ list_for_each_entry(netdev, &handler->conf->netdevs, head) {
int ret;
- struct lxc_netdev *netdev = iterator->elem;
/* Receive network device name in the child's namespace to
* parent.
#include <unistd.h>
#include "compiler.h"
+#include "hlist.h"
#include "list.h"
struct lxc_conf;
struct in6_addr *ipv6_gateway;
char *upscript;
char *downscript;
+ struct list_head head;
};
/* Convert a string mac address to a socket structure. */
__hidden extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
__hidden extern int lxc_requests_empty_network(struct lxc_handler *handler);
__hidden extern int lxc_restore_phys_nics_to_netns(struct lxc_handler *handler);
-__hidden extern int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf,
- struct lxc_list *network);
+__hidden extern int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf);
__hidden extern int lxc_network_send_to_child(struct lxc_handler *handler);
__hidden extern int lxc_network_recv_from_parent(struct lxc_handler *handler);
__hidden extern int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler);