mirror of
git://github.com/lxc/lxc
synced 2025-08-31 00:49:33 +00:00
Merge pull request #1761 from brauner/2017-08-10/further_lxc_2.1_preparations
further lxc 2.1 preparations
This commit is contained in:
@@ -1199,6 +1199,7 @@ out_free:
|
||||
|
||||
static int cgroup_rmdir(char *dirname)
|
||||
{
|
||||
int ret;
|
||||
struct dirent *direntp;
|
||||
DIR *dir;
|
||||
int r = 0;
|
||||
@@ -1208,8 +1209,8 @@ static int cgroup_rmdir(char *dirname)
|
||||
return -1;
|
||||
|
||||
while ((direntp = readdir(dir))) {
|
||||
struct stat mystat;
|
||||
char *pathname;
|
||||
struct stat mystat;
|
||||
|
||||
if (!direntp)
|
||||
break;
|
||||
@@ -1220,32 +1221,40 @@ static int cgroup_rmdir(char *dirname)
|
||||
|
||||
pathname = must_make_path(dirname, direntp->d_name, NULL);
|
||||
|
||||
if (lstat(pathname, &mystat)) {
|
||||
ret = lstat(pathname, &mystat);
|
||||
if (ret < 0) {
|
||||
if (!r)
|
||||
WARN("failed to stat %s", pathname);
|
||||
WARN("Failed to stat %s", pathname);
|
||||
r = -1;
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(mystat.st_mode))
|
||||
goto next;
|
||||
if (cgroup_rmdir(pathname) < 0)
|
||||
|
||||
ret = cgroup_rmdir(pathname);
|
||||
if (ret < 0)
|
||||
r = -1;
|
||||
next:
|
||||
free(pathname);
|
||||
}
|
||||
|
||||
if (rmdir(dirname) < 0) {
|
||||
ret = rmdir(dirname);
|
||||
if (ret < 0) {
|
||||
if (!r)
|
||||
WARN("failed to delete %s: %s", dirname, strerror(errno));
|
||||
WARN("Failed to delete \"%s\": %s", dirname,
|
||||
strerror(errno));
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (closedir(dir) < 0) {
|
||||
ret = closedir(dir);
|
||||
if (ret < 0) {
|
||||
if (!r)
|
||||
WARN("failed to delete %s: %s", dirname, strerror(errno));
|
||||
WARN("Failed to delete \"%s\": %s", dirname,
|
||||
strerror(errno));
|
||||
r = -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1263,35 +1272,91 @@ static int rmdir_wrapper(void *data)
|
||||
return cgroup_rmdir(path);
|
||||
}
|
||||
|
||||
void recursive_destroy(char *path, struct lxc_conf *conf)
|
||||
int recursive_destroy(char *path, struct lxc_conf *conf)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (conf && !lxc_list_empty(&conf->id_map))
|
||||
r = userns_exec_1(conf, rmdir_wrapper, path, "rmdir_wrapper");
|
||||
else
|
||||
r = cgroup_rmdir(path);
|
||||
|
||||
if (r < 0)
|
||||
ERROR("Error destroying %s", path);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
|
||||
{
|
||||
int i;
|
||||
char *clean_parent, *clean_fullcgpath;
|
||||
char **fields;
|
||||
size_t recurse_upwards = 0;
|
||||
struct cgfsng_handler_data *d = hdata;
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
if (d->container_cgroup && hierarchies) {
|
||||
int i;
|
||||
for (i = 0; hierarchies[i]; i++) {
|
||||
struct hierarchy *h = hierarchies[i];
|
||||
if (h->fullcgpath) {
|
||||
recursive_destroy(h->fullcgpath, conf);
|
||||
free(h->fullcgpath);
|
||||
h->fullcgpath = NULL;
|
||||
}
|
||||
if (!d->container_cgroup || !hierarchies)
|
||||
return;
|
||||
|
||||
if (d->cgroup_meta.dir)
|
||||
clean_parent = d->cgroup_meta.dir;
|
||||
else
|
||||
clean_parent = d->cgroup_pattern;
|
||||
fields = lxc_normalize_path(clean_parent);
|
||||
if (fields) {
|
||||
recurse_upwards = lxc_array_len((void **)fields);
|
||||
if (recurse_upwards > 0 && clean_parent == d->cgroup_pattern)
|
||||
recurse_upwards--;
|
||||
lxc_free_array((void **)fields, free);
|
||||
}
|
||||
|
||||
for (i = 0; hierarchies[i]; i++) {
|
||||
int ret;
|
||||
size_t j;
|
||||
struct hierarchy *h = hierarchies[i];
|
||||
|
||||
if (!h->fullcgpath)
|
||||
continue;
|
||||
|
||||
clean_fullcgpath = lxc_deslashify(h->fullcgpath);
|
||||
if (!clean_fullcgpath)
|
||||
clean_fullcgpath = h->fullcgpath;
|
||||
|
||||
/* Delete the container's cgroup */
|
||||
ret = recursive_destroy(clean_fullcgpath, conf);
|
||||
if (ret < 0)
|
||||
goto next;
|
||||
|
||||
if (h->fullcgpath == clean_fullcgpath)
|
||||
goto next;
|
||||
|
||||
/* Delete parent cgroups as specified in the containers config
|
||||
* file. This takes care of not having useless empty cgroups
|
||||
* around.
|
||||
*/
|
||||
for (j = 0; j < recurse_upwards; j++) {
|
||||
char *s = clean_fullcgpath;
|
||||
|
||||
s = strrchr(s, '/');
|
||||
if (!s)
|
||||
break;
|
||||
*s = '\0';
|
||||
|
||||
/* If we fail to delete a cgroup we know that any parent
|
||||
* cgroup also cannot be removed.
|
||||
*/
|
||||
ret = recursive_destroy(clean_fullcgpath, conf);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
next:
|
||||
if (h->fullcgpath != clean_fullcgpath)
|
||||
free(clean_fullcgpath);
|
||||
free(h->fullcgpath);
|
||||
h->fullcgpath = NULL;
|
||||
}
|
||||
|
||||
free_handler_data(d);
|
||||
@@ -1336,11 +1401,11 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
|
||||
*/
|
||||
static inline bool cgfsng_create(void *hdata)
|
||||
{
|
||||
struct cgfsng_handler_data *d = hdata;
|
||||
char *tmp, *cgname, *offset;
|
||||
int i;
|
||||
int idx = 0;
|
||||
size_t len;
|
||||
char *cgname, *offset, *tmp;
|
||||
int idx = 0;
|
||||
struct cgfsng_handler_data *d = hdata;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
@@ -1351,7 +1416,7 @@ static inline bool cgfsng_create(void *hdata)
|
||||
}
|
||||
|
||||
if (d->cgroup_meta.dir)
|
||||
tmp = strdup(d->cgroup_meta.dir);
|
||||
tmp = lxc_string_join("/", (const char *[]){d->cgroup_meta.dir, d->name, NULL}, false);
|
||||
else
|
||||
tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
|
||||
if (!tmp) {
|
||||
|
1087
src/lxc/conf.c
1087
src/lxc/conf.c
File diff suppressed because it is too large
Load Diff
112
src/lxc/conf.h
112
src/lxc/conf.h
@@ -46,103 +46,6 @@ typedef void * scmp_filter_ctx;
|
||||
#define subuidfile "/etc/subuid"
|
||||
#define subgidfile "/etc/subgid"
|
||||
|
||||
enum {
|
||||
LXC_NET_EMPTY,
|
||||
LXC_NET_VETH,
|
||||
LXC_NET_MACVLAN,
|
||||
LXC_NET_PHYS,
|
||||
LXC_NET_VLAN,
|
||||
LXC_NET_NONE,
|
||||
LXC_NET_MAXCONFTYPE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines the structure to configure an ipv4 address
|
||||
* @address : ipv4 address
|
||||
* @broadcast : ipv4 broadcast address
|
||||
* @mask : network mask
|
||||
*/
|
||||
struct lxc_inetdev {
|
||||
struct in_addr addr;
|
||||
struct in_addr bcast;
|
||||
unsigned int prefix;
|
||||
};
|
||||
|
||||
struct lxc_route {
|
||||
struct in_addr addr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines the structure to configure an ipv6 address
|
||||
* @flags : set the address up
|
||||
* @address : ipv6 address
|
||||
* @broadcast : ipv6 broadcast address
|
||||
* @mask : network mask
|
||||
*/
|
||||
struct lxc_inet6dev {
|
||||
struct in6_addr addr;
|
||||
struct in6_addr mcast;
|
||||
struct in6_addr acast;
|
||||
unsigned int prefix;
|
||||
};
|
||||
|
||||
struct lxc_route6 {
|
||||
struct in6_addr addr;
|
||||
};
|
||||
|
||||
struct ifla_veth {
|
||||
char *pair; /* pair name */
|
||||
char veth1[IFNAMSIZ]; /* needed for deconf */
|
||||
};
|
||||
|
||||
struct ifla_vlan {
|
||||
unsigned int flags;
|
||||
unsigned int fmask;
|
||||
unsigned short vid;
|
||||
unsigned short pad;
|
||||
};
|
||||
|
||||
struct ifla_macvlan {
|
||||
int mode; /* private, vepa, bridge, passthru */
|
||||
};
|
||||
|
||||
union netdev_p {
|
||||
struct ifla_veth veth_attr;
|
||||
struct ifla_vlan vlan_attr;
|
||||
struct ifla_macvlan macvlan_attr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines a structure to configure a network device
|
||||
* @link : lxc.net.[i].link, name of bridge or host iface to attach if any
|
||||
* @name : lxc.net.[i].name, name of iface on the container side
|
||||
* @flags : flag of the network device (IFF_UP, ... )
|
||||
* @ipv4 : a list of ipv4 addresses to be set on the network device
|
||||
* @ipv6 : a list of ipv6 addresses to be set on the network device
|
||||
* @upscript : a script filename to be executed during interface configuration
|
||||
* @downscript : a script filename to be executed during interface destruction
|
||||
* @idx : network counter
|
||||
*/
|
||||
struct lxc_netdev {
|
||||
ssize_t idx;
|
||||
int type;
|
||||
int flags;
|
||||
int ifindex;
|
||||
char *link;
|
||||
char *name;
|
||||
char *hwaddr;
|
||||
char *mtu;
|
||||
union netdev_p priv;
|
||||
struct lxc_list ipv4;
|
||||
struct lxc_list ipv6;
|
||||
struct in_addr *ipv4_gateway;
|
||||
bool ipv4_gateway_auto;
|
||||
struct in6_addr *ipv6_gateway;
|
||||
bool ipv6_gateway_auto;
|
||||
char *upscript;
|
||||
char *downscript;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines a generic struct to configure the control group. It is up to the
|
||||
* programmer to specify the right subsystem.
|
||||
@@ -327,12 +230,8 @@ enum lxchooks {
|
||||
LXCHOOK_DESTROY,
|
||||
NUM_LXC_HOOKS
|
||||
};
|
||||
extern char *lxchook_names[NUM_LXC_HOOKS];
|
||||
|
||||
struct saved_nic {
|
||||
int ifindex;
|
||||
char *orig_name;
|
||||
};
|
||||
extern char *lxchook_names[NUM_LXC_HOOKS];
|
||||
|
||||
struct lxc_conf {
|
||||
int is_execute;
|
||||
@@ -458,13 +357,7 @@ extern int detect_shared_rootfs(void);
|
||||
extern struct lxc_conf *lxc_conf_init(void);
|
||||
extern void lxc_conf_free(struct lxc_conf *conf);
|
||||
extern int pin_rootfs(const char *rootfs);
|
||||
extern int lxc_requests_empty_network(struct lxc_handler *handler);
|
||||
extern int lxc_setup_networks_in_parent_namespaces(struct lxc_handler *handler);
|
||||
extern bool lxc_delete_network(struct lxc_handler *handler);
|
||||
extern int lxc_assign_network(const char *lxcpath, char *lxcname,
|
||||
struct lxc_list *networks, pid_t pid);
|
||||
extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid);
|
||||
extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
|
||||
extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
|
||||
extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
|
||||
extern int lxc_clear_config_caps(struct lxc_conf *c);
|
||||
@@ -483,7 +376,6 @@ extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
|
||||
const char *lxcpath);
|
||||
extern int lxc_setup(struct lxc_handler *handler);
|
||||
extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
|
||||
extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
|
||||
extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
|
||||
extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
|
||||
enum idtype idtype);
|
||||
@@ -500,5 +392,7 @@ extern FILE *make_anonymous_mount_file(struct lxc_list *mount);
|
||||
extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings);
|
||||
extern unsigned long add_required_remount_flags(const char *s, const char *d,
|
||||
unsigned long flags);
|
||||
extern int run_script(const char *name, const char *section, const char *script,
|
||||
...);
|
||||
|
||||
#endif /* __LXC_CONF_H */
|
||||
|
@@ -1431,9 +1431,6 @@ static int set_config_cgroup_dir(const char *key, const char *value,
|
||||
if (lxc_config_value_empty(value))
|
||||
return clr_config_cgroup_dir(key, lxc_conf, NULL);
|
||||
|
||||
if (lxc_conf->cgroup_meta.dir)
|
||||
clr_config_cgroup_dir(key, lxc_conf, NULL);
|
||||
|
||||
return set_config_string_item(&lxc_conf->cgroup_meta.dir, value);
|
||||
}
|
||||
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "error.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
#include "network.h"
|
||||
#include "parse.h"
|
||||
#include "utils.h"
|
||||
|
||||
@@ -253,6 +254,7 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
|
||||
netdev = it->elem;
|
||||
|
||||
TRACE("index: %zd", netdev->idx);
|
||||
TRACE("ifindex: %d", netdev->ifindex);
|
||||
switch (netdev->type) {
|
||||
case LXC_NET_VETH:
|
||||
TRACE("type: veth");
|
||||
|
@@ -17,7 +17,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#define _GNU_SOURCE
|
||||
#include <alloca.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
@@ -59,21 +59,27 @@
|
||||
|
||||
static void usage(char *me, bool fail)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s lxcpath name pid type bridge nicname\n", me);
|
||||
fprintf(stderr, " nicname is the name to use inside the container\n");
|
||||
exit(fail ? 1 : 0);
|
||||
}
|
||||
fprintf(stderr, "Usage: %s create {lxcpath} {name} {pid} {type} "
|
||||
"{bridge} {nicname}\n", me);
|
||||
fprintf(stderr, "Usage: %s delete {lxcpath} {name} {pid} {type} "
|
||||
"{bridge} {nicname}\n", me);
|
||||
fprintf(stderr, "{nicname} is the name to use inside the container\n");
|
||||
|
||||
static char *lxcpath, *lxcname;
|
||||
if (fail)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int open_and_lock(char *path)
|
||||
{
|
||||
int fd;
|
||||
int fd, ret;
|
||||
struct flock lk;
|
||||
|
||||
fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
|
||||
fd = open(path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
|
||||
if (fd < 0) {
|
||||
usernic_error("Failed to open %s: %s\n", path, strerror(errno));
|
||||
usernic_error("Failed to open \"%s\": %s\n", path,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -81,8 +87,11 @@ static int open_and_lock(char *path)
|
||||
lk.l_whence = SEEK_SET;
|
||||
lk.l_start = 0;
|
||||
lk.l_len = 0;
|
||||
if (fcntl(fd, F_SETLKW, &lk) < 0) {
|
||||
usernic_error("Failed to lock %s: %s\n", path, strerror(errno));
|
||||
|
||||
ret = fcntl(fd, F_SETLKW, &lk);
|
||||
if (ret < 0) {
|
||||
usernic_error("Failed to lock \"%s\": %s\n", path,
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -90,14 +99,13 @@ static int open_and_lock(char *path)
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
static char *get_username(void)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
|
||||
pwd = getpwuid(getuid());
|
||||
if (!pwd) {
|
||||
usernic_error("Failed to call get username: %s\n", strerror(errno));
|
||||
usernic_error("Failed to get username: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -127,9 +135,8 @@ static char **get_groupnames(void)
|
||||
|
||||
ngroups = getgroups(0, NULL);
|
||||
if (ngroups < 0) {
|
||||
usernic_error(
|
||||
"Failed to get number of groups the user belongs to: %s\n",
|
||||
strerror(errno));
|
||||
usernic_error("Failed to get number of groups the user "
|
||||
"belongs to: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (ngroups == 0)
|
||||
@@ -203,19 +210,21 @@ struct alloted_s {
|
||||
struct alloted_s *next;
|
||||
};
|
||||
|
||||
static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int n)
|
||||
static struct alloted_s *append_alloted(struct alloted_s **head, char *name,
|
||||
int n)
|
||||
{
|
||||
struct alloted_s *cur, *al;
|
||||
|
||||
if (!head || !name) {
|
||||
/* sanity check. parameters should not be null */
|
||||
/* Sanity check. Parameters should not be null. */
|
||||
usernic_error("%s\n", "Unexpected NULL argument");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
al = malloc(sizeof(struct alloted_s));
|
||||
if (!al) {
|
||||
usernic_error("Failed to allocate memory: %s\n", strerror(errno));
|
||||
usernic_error("Failed to allocate memory: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -266,7 +275,8 @@ static void free_alloted(struct alloted_s **head)
|
||||
* Return the count entry for the calling user if there is one. Else
|
||||
* return -1.
|
||||
*/
|
||||
static int get_alloted(char *me, char *intype, char *link, struct alloted_s **alloted)
|
||||
static int get_alloted(char *me, char *intype, char *link,
|
||||
struct alloted_s **alloted)
|
||||
{
|
||||
int n, ret;
|
||||
char name[100], type[100], br[100];
|
||||
@@ -279,13 +289,15 @@ static int get_alloted(char *me, char *intype, char *link, struct alloted_s **al
|
||||
|
||||
fin = fopen(LXC_USERNIC_CONF, "r");
|
||||
if (!fin) {
|
||||
usernic_error("Failed to open \"%s\": %s\n", LXC_USERNIC_CONF, strerror(errno));
|
||||
usernic_error("Failed to open \"%s\": %s\n", LXC_USERNIC_CONF,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
groups = get_groupnames();
|
||||
while ((getline(&line, &len, fin)) != -1) {
|
||||
ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, type, br, &n);
|
||||
ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name,
|
||||
type, br, &n);
|
||||
if (ret != 4)
|
||||
continue;
|
||||
|
||||
@@ -358,7 +370,8 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
|
||||
p++;
|
||||
|
||||
p2 = get_eow(p, e);
|
||||
if (!p2 || ((size_t)(p2 - p)) != strlen(u) || strncmp(p, u, strlen(u)))
|
||||
if (!p2 || ((size_t)(p2 - p)) != strlen(u) ||
|
||||
strncmp(p, u, strlen(u)))
|
||||
goto next;
|
||||
|
||||
p = p2 + 1;
|
||||
@@ -366,7 +379,8 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
|
||||
p++;
|
||||
|
||||
p2 = get_eow(p, e);
|
||||
if (!p2 || ((size_t)(p2 - p)) != strlen(t) || strncmp(p, t, strlen(t)))
|
||||
if (!p2 || ((size_t)(p2 - p)) != strlen(t) ||
|
||||
strncmp(p, t, strlen(t)))
|
||||
goto next;
|
||||
|
||||
p = p2 + 1;
|
||||
@@ -374,11 +388,12 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
|
||||
p++;
|
||||
|
||||
p2 = get_eow(p, e);
|
||||
if (!p2 || ((size_t)(p2 - p)) != strlen(l) || strncmp(p, l, strlen(l)))
|
||||
if (!p2 || ((size_t)(p2 - p)) != strlen(l) ||
|
||||
strncmp(p, l, strlen(l)))
|
||||
goto next;
|
||||
|
||||
return ret;
|
||||
next:
|
||||
next:
|
||||
p = p1 + 1;
|
||||
}
|
||||
|
||||
@@ -417,7 +432,8 @@ static int instantiate_veth(char *n1, char **n2)
|
||||
|
||||
err = lxc_veth_create(n1, *n2);
|
||||
if (err) {
|
||||
usernic_error("Failed to create %s-%s : %s.\n", n1, *n2, strerror(-err));
|
||||
usernic_error("Failed to create %s-%s : %s.\n", n1, *n2,
|
||||
strerror(-err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -427,8 +443,7 @@ static int instantiate_veth(char *n1, char **n2)
|
||||
err = setup_private_host_hw_addr(n1);
|
||||
if (err)
|
||||
usernic_error("Failed to change mac address of host interface "
|
||||
"%s : %s\n",
|
||||
n1, strerror(-err));
|
||||
"%s : %s\n", n1, strerror(-err));
|
||||
|
||||
return netdev_set_flag(n1, IFF_UP);
|
||||
}
|
||||
@@ -471,13 +486,15 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
|
||||
if (mtu > 0) {
|
||||
ret = lxc_netdev_set_mtu(veth1buf, mtu);
|
||||
if (ret < 0) {
|
||||
usernic_error("Failed to set mtu to %d on %s\n", mtu, veth1buf);
|
||||
usernic_error("Failed to set mtu to %d on %s\n",
|
||||
mtu, veth1buf);
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
ret = lxc_netdev_set_mtu(veth2buf, mtu);
|
||||
if (ret < 0) {
|
||||
usernic_error("Failed to set mtu to %d on %s\n", mtu, veth2buf);
|
||||
usernic_error("Failed to set mtu to %d on %s\n",
|
||||
mtu, veth2buf);
|
||||
goto out_del;
|
||||
}
|
||||
}
|
||||
@@ -493,7 +510,8 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
|
||||
/* pass veth2 to target netns */
|
||||
ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
|
||||
if (ret < 0) {
|
||||
usernic_error("Error moving %s to network namespace of %d\n", veth2buf, pid);
|
||||
usernic_error("Error moving %s to network namespace of %d\n",
|
||||
veth2buf, pid);
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
@@ -510,25 +528,29 @@ out_del:
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a new nic.
|
||||
* *dest will contain the name (vethXXXXXX) which is attached
|
||||
* on the host to the lxc bridge
|
||||
/* get_new_nicname() will return the name (vethXXXXXX) which is attached on the
|
||||
* host to the lxc bridge. The returned string must be freed by caller.
|
||||
*/
|
||||
static bool get_new_nicname(char **dest, char *br, int pid, char **cnic)
|
||||
static char *get_new_nicname(char *br, int pid, char **cnic)
|
||||
{
|
||||
int ret;
|
||||
char *nicname;
|
||||
char template[IFNAMSIZ];
|
||||
|
||||
ret = snprintf(template, sizeof(template), "vethXXXXXX");
|
||||
if (ret < 0 || (size_t)ret >= sizeof(template))
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
*dest = lxc_mkifname(template);
|
||||
if (!create_nic(*dest, br, pid, cnic))
|
||||
return false;
|
||||
nicname = lxc_mkifname(template);
|
||||
if (!nicname)
|
||||
return NULL;
|
||||
|
||||
return true;
|
||||
if (!create_nic(nicname, br, pid, cnic)) {
|
||||
free(nicname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nicname;
|
||||
}
|
||||
|
||||
static bool get_nic_from_line(char *p, char **nic)
|
||||
@@ -536,7 +558,8 @@ static bool get_nic_from_line(char *p, char **nic)
|
||||
int ret;
|
||||
char user[100], type[100], br[100];
|
||||
|
||||
ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user, type, br, *nic);
|
||||
ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user,
|
||||
type, br, *nic);
|
||||
if (ret != 4)
|
||||
return false;
|
||||
|
||||
@@ -549,19 +572,22 @@ struct entry_line {
|
||||
bool keep;
|
||||
};
|
||||
|
||||
static bool cull_entries(int fd, char *me, char *t, char *br)
|
||||
static bool cull_entries(int fd, char *me, char *t, char *br, char *nicname,
|
||||
bool *found_nicname)
|
||||
{
|
||||
int i, n = 0;
|
||||
int i, ret;
|
||||
off_t len;
|
||||
char *buf, *p, *e, *nic;
|
||||
char *buf, *e, *nic, *p;
|
||||
struct stat sb;
|
||||
int n = 0;
|
||||
struct entry_line *entry_lines = NULL;
|
||||
|
||||
nic = alloca(100);
|
||||
if (!nic)
|
||||
return false;
|
||||
|
||||
if (fstat(fd, &sb) < 0) {
|
||||
ret = fstat(fd, &sb);
|
||||
if (ret < 0) {
|
||||
usernic_error("Failed to fstat: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
@@ -570,9 +596,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
|
||||
if (len == 0)
|
||||
return true;
|
||||
|
||||
buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
buf = lxc_strmmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
usernic_error("Failed to establish shared memory mapping: %s\n", strerror(errno));
|
||||
usernic_error("Failed to establish shared memory mapping: %s\n",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -598,6 +625,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
|
||||
if (nic && !nic_exists(nic))
|
||||
entry_lines[n - 1].keep = false;
|
||||
|
||||
if (nicname)
|
||||
if (!strcmp(nic, nicname))
|
||||
*found_nicname = true;
|
||||
|
||||
p += entry_lines[n - 1].len + 1;
|
||||
if (p >= e)
|
||||
break;
|
||||
@@ -615,9 +646,11 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
|
||||
}
|
||||
free(entry_lines);
|
||||
|
||||
munmap(buf, sb.st_size);
|
||||
if (ftruncate(fd, p - buf))
|
||||
usernic_error("Failed to set new file size: %s\n", strerror(errno));
|
||||
lxc_strmunmap(buf, sb.st_size);
|
||||
ret = ftruncate(fd, p - buf);
|
||||
if (ret < 0)
|
||||
usernic_error("Failed to set new file size: %s\n",
|
||||
strerror(errno));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -638,41 +671,39 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* The dbfile has lines of the format:
|
||||
* user type bridge nicname
|
||||
*/
|
||||
static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid,
|
||||
char *intype, char *br, int allowed,
|
||||
char **nicname, char **cnic)
|
||||
/* The dbfile has lines of the format: user type bridge nicname. */
|
||||
static char *get_nic_if_avail(int fd, struct alloted_s *names, int pid,
|
||||
char *intype, char *br, int allowed, char **cnic)
|
||||
{
|
||||
int ret;
|
||||
off_t len, slen;
|
||||
char *newline, *owner;
|
||||
char *newline, *nicname, *owner;
|
||||
struct stat sb;
|
||||
struct alloted_s *n;
|
||||
int count = 0;
|
||||
char *buf = NULL;
|
||||
|
||||
for (n = names; n != NULL; n = n->next)
|
||||
cull_entries(fd, n->name, intype, br);
|
||||
cull_entries(fd, n->name, intype, br, NULL, NULL);
|
||||
|
||||
if (allowed == 0)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
owner = names->name;
|
||||
|
||||
if (fstat(fd, &sb) < 0) {
|
||||
usernic_error("Failed to fstat: %s\n", strerror(errno));
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = sb.st_size;
|
||||
if (len > 0) {
|
||||
buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
buf =
|
||||
mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
usernic_error("Failed to establish shared memory mapping: %s\n", strerror(errno));
|
||||
return false;
|
||||
usernic_error("Failed to establish shared memory mapping: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
owner = NULL;
|
||||
@@ -688,47 +719,56 @@ static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid,
|
||||
}
|
||||
|
||||
if (owner == NULL)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
if (!get_new_nicname(nicname, br, pid, cnic))
|
||||
return false;
|
||||
|
||||
/* owner ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
|
||||
slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
|
||||
newline = alloca(slen);
|
||||
if (!newline) {
|
||||
usernic_error("Failed allocate memory: %s\n", strerror(errno));
|
||||
return false;
|
||||
nicname = get_new_nicname(br, pid, cnic);
|
||||
if (!nicname) {
|
||||
usernic_error("%s", "Failed to get new nic name\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = snprintf(newline, slen, "%s %s %s %s\n", owner, intype, br, *nicname);
|
||||
/* owner ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
|
||||
slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(nicname) + 5;
|
||||
newline = alloca(slen);
|
||||
if (!newline) {
|
||||
free(nicname);
|
||||
usernic_error("Failed allocate memory: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = snprintf(newline, slen, "%s %s %s %s\n", owner, intype, br, nicname);
|
||||
if (ret < 0 || ret >= slen) {
|
||||
if (lxc_netdev_delete_by_name(*nicname) != 0)
|
||||
usernic_error("Error unlinking %s\n", *nicname);
|
||||
return false;
|
||||
if (lxc_netdev_delete_by_name(nicname) != 0)
|
||||
usernic_error("Error unlinking %s\n", nicname);
|
||||
free(nicname);
|
||||
return NULL;
|
||||
}
|
||||
if (len)
|
||||
munmap(buf, len);
|
||||
|
||||
if (ftruncate(fd, len + slen))
|
||||
usernic_error("Failed to set new file size: %s\n", strerror(errno));
|
||||
usernic_error("Failed to set new file size: %s\n",
|
||||
strerror(errno));
|
||||
|
||||
buf = mmap(NULL, len + slen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
buf = mmap(NULL, len + slen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
usernic_error("Failed to establish shared memory mapping: %s\n", strerror(errno));
|
||||
if (lxc_netdev_delete_by_name(*nicname) != 0)
|
||||
usernic_error("Error unlinking %s\n", *nicname);
|
||||
return false;
|
||||
usernic_error("Failed to establish shared memory mapping: %s\n",
|
||||
strerror(errno));
|
||||
if (lxc_netdev_delete_by_name(nicname) != 0)
|
||||
usernic_error("Error unlinking %s\n", nicname);
|
||||
free(nicname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(buf + len, newline);
|
||||
munmap(buf, len + slen);
|
||||
|
||||
return true;
|
||||
return nicname;
|
||||
}
|
||||
|
||||
static bool create_db_dir(char *fnam)
|
||||
{
|
||||
int ret;
|
||||
char *p;
|
||||
|
||||
p = alloca(strlen(fnam) + 1);
|
||||
@@ -743,8 +783,11 @@ again:
|
||||
return true;
|
||||
|
||||
*p = '\0';
|
||||
if (mkdir(fnam, 0755) && errno != EEXIST) {
|
||||
usernic_error("Failed to create %s: %s\n", fnam, strerror(errno));
|
||||
|
||||
ret = mkdir(fnam, 0755);
|
||||
if (ret < 0 && errno != EEXIST) {
|
||||
usernic_error("Failed to create %s: %s\n", fnam,
|
||||
strerror(errno));
|
||||
*p = '/';
|
||||
return false;
|
||||
}
|
||||
@@ -753,18 +796,19 @@ again:
|
||||
goto again;
|
||||
}
|
||||
|
||||
#define VETH_DEF_NAME "eth%d"
|
||||
static int rename_in_ns(int pid, char *oldname, char **newnamep)
|
||||
static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
|
||||
int *ifidx)
|
||||
{
|
||||
int ret;
|
||||
uid_t ruid, suid, euid;
|
||||
int fret = -1;
|
||||
int fd = -1, ifindex = -1, ofd = -1, ret;
|
||||
bool grab_newname = false;
|
||||
char ifname[IFNAMSIZ];
|
||||
char *string_ret = NULL, *name = NULL;
|
||||
int fd = -1, ifindex = -1, ofd = -1;
|
||||
|
||||
ofd = lxc_preserve_ns(getpid(), "net");
|
||||
if (ofd < 0) {
|
||||
usernic_error("Failed opening network namespace path for %d", getpid());
|
||||
return fret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd = lxc_preserve_ns(pid, "net");
|
||||
@@ -804,63 +848,70 @@ static int rename_in_ns(int pid, char *oldname, char **newnamep)
|
||||
goto do_full_cleanup;
|
||||
}
|
||||
|
||||
if (!*newnamep) {
|
||||
grab_newname = true;
|
||||
*newnamep = VETH_DEF_NAME;
|
||||
|
||||
ifindex = if_nametoindex(oldname);
|
||||
if (!ifindex) {
|
||||
usernic_error("Failed to get netdev index: %s\n", strerror(errno));
|
||||
goto do_full_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = lxc_netdev_rename_by_name(oldname, *newnamep);
|
||||
if (ret < 0) {
|
||||
usernic_error("Error %d renaming netdev %s to %s in container\n", ret, oldname, *newnamep);
|
||||
/* Check if old interface exists. */
|
||||
ifindex = if_nametoindex(oldname);
|
||||
if (!ifindex) {
|
||||
usernic_error("Failed to get netdev index: %s\n", strerror(errno));
|
||||
goto do_full_cleanup;
|
||||
}
|
||||
|
||||
if (grab_newname) {
|
||||
char ifname[IFNAMSIZ];
|
||||
char *namep = ifname;
|
||||
/* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
|
||||
* netlink will replace the format specifier with an appropriate index.
|
||||
* So we pass "eth%d".
|
||||
*/
|
||||
if (newname)
|
||||
name = newname;
|
||||
else
|
||||
name = "eth%d";
|
||||
|
||||
if (!if_indextoname(ifindex, namep)) {
|
||||
usernic_error("Failed to get new netdev name: %s\n", strerror(errno));
|
||||
goto do_full_cleanup;
|
||||
}
|
||||
|
||||
*newnamep = strdup(namep);
|
||||
if (!*newnamep)
|
||||
goto do_full_cleanup;
|
||||
ret = lxc_netdev_rename_by_name(oldname, name);
|
||||
name = NULL;
|
||||
if (ret < 0) {
|
||||
usernic_error("Error %d renaming netdev %s to %s in container\n",
|
||||
ret, oldname, newname ? newname : "eth%d");
|
||||
goto do_full_cleanup;
|
||||
}
|
||||
|
||||
fret = 0;
|
||||
/* Retrieve new name for interface. */
|
||||
if (!if_indextoname(ifindex, ifname)) {
|
||||
usernic_error("Failed to get new netdev name: %s\n", strerror(errno));
|
||||
goto do_full_cleanup;
|
||||
}
|
||||
|
||||
/* Allocation failure for strdup() is checked below. */
|
||||
name = strdup(ifname);
|
||||
string_ret = name;
|
||||
*ifidx = ifindex;
|
||||
|
||||
do_full_cleanup:
|
||||
ret = setresuid(ruid, euid, suid);
|
||||
if (ret < 0) {
|
||||
usernic_error("Failed to restore privilege by setting effective "
|
||||
"user id to %d, real user id to %d, and saved user "
|
||||
"ID to %d: %s\n",
|
||||
ruid, euid, suid, strerror(errno));
|
||||
fret = -1;
|
||||
usernic_error("Failed to restore privilege by setting "
|
||||
"effective user id to %d, real user id to %d, "
|
||||
"and saved user ID to %d: %s\n", ruid, euid, suid,
|
||||
strerror(errno));
|
||||
|
||||
string_ret = NULL;
|
||||
}
|
||||
|
||||
ret = setns(ofd, CLONE_NEWNET);
|
||||
if (ret < 0) {
|
||||
usernic_error("Failed to setns() to original network namespace "
|
||||
"of PID %d: %s\n",
|
||||
ofd, strerror(errno));
|
||||
fret = -1;
|
||||
"of PID %d: %s\n", ofd, strerror(errno));
|
||||
|
||||
string_ret = NULL;
|
||||
}
|
||||
|
||||
do_partial_cleanup:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (!string_ret && name)
|
||||
free(name);
|
||||
|
||||
close(ofd);
|
||||
|
||||
return fret;
|
||||
return string_ret;
|
||||
}
|
||||
|
||||
/* If the caller (real uid, not effective uid) may read the /proc/[pid]/ns/net,
|
||||
@@ -912,50 +963,73 @@ static bool may_access_netns(int pid)
|
||||
return may_access;
|
||||
}
|
||||
|
||||
struct user_nic_args {
|
||||
char *cmd;
|
||||
char *lxc_path;
|
||||
char *lxc_name;
|
||||
char *pid;
|
||||
char *type;
|
||||
char *link;
|
||||
char *veth_name;
|
||||
};
|
||||
|
||||
#define LXC_USERNIC_CREATE 0
|
||||
#define LXC_USERNIC_DELETE 1
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int n, fd;
|
||||
char *me;
|
||||
char *nicname;
|
||||
int pid;
|
||||
char *cnic = NULL; /* Created nic name in container is returned here. */
|
||||
char *vethname = NULL;
|
||||
bool gotone = false;
|
||||
int fd, ifindex, n, pid, request, ret;
|
||||
char *me, *newname;
|
||||
char *cnic = NULL, *nicname = NULL;
|
||||
struct alloted_s *alloted = NULL;
|
||||
struct user_nic_args args;
|
||||
|
||||
nicname = alloca(40);
|
||||
if (!nicname) {
|
||||
usernic_error("Failed allocate memory: %s\n", strerror(errno));
|
||||
if (argc < 7 || argc > 8) {
|
||||
usage(argv[0], true);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* set a sane env, because we are setuid-root */
|
||||
if (clearenv() < 0) {
|
||||
memset(&args, 0, sizeof(struct user_nic_args));
|
||||
args.cmd = argv[1];
|
||||
args.lxc_path = argv[2];
|
||||
args.lxc_name = argv[3];
|
||||
args.pid = argv[4];
|
||||
args.type = argv[5];
|
||||
args.link = argv[6];
|
||||
if (argc >= 8)
|
||||
args.veth_name = argv[7];
|
||||
|
||||
if (!strcmp(args.cmd, "create")) {
|
||||
request = LXC_USERNIC_CREATE;
|
||||
} else if (!strcmp(args.cmd, "delete")) {
|
||||
request = LXC_USERNIC_DELETE;
|
||||
} else {
|
||||
usage(argv[0], true);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Set a sane env, because we are setuid-root. */
|
||||
ret = clearenv();
|
||||
if (ret) {
|
||||
usernic_error("%s", "Failed to clear environment\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1) < 0) {
|
||||
|
||||
ret = setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
|
||||
if (ret < 0) {
|
||||
usernic_error("%s", "Failed to set PATH, exiting\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ((me = get_username()) == NULL) {
|
||||
|
||||
me = get_username();
|
||||
if (!me) {
|
||||
usernic_error("%s", "Failed to get username\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc < 6)
|
||||
usage(argv[0], true);
|
||||
|
||||
if (argc >= 7)
|
||||
vethname = argv[6];
|
||||
|
||||
lxcpath = argv[1];
|
||||
lxcname = argv[2];
|
||||
|
||||
errno = 0;
|
||||
pid = strtol(argv[3], NULL, 10);
|
||||
if (errno) {
|
||||
usernic_error("Could not read pid: %s\n", argv[1]);
|
||||
ret = lxc_safe_int(args.pid, &pid);
|
||||
if (ret < 0) {
|
||||
usernic_error("Could not read pid: %s\n", args.pid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -964,7 +1038,8 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ((fd = open_and_lock(LXC_USERNIC_DB)) < 0) {
|
||||
fd = open_and_lock(LXC_USERNIC_DB);
|
||||
if (fd < 0) {
|
||||
usernic_error("Failed to lock %s\n", LXC_USERNIC_DB);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -974,28 +1049,74 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
n = get_alloted(me, argv[4], argv[5], &alloted);
|
||||
n = get_alloted(me, args.type, args.link, &alloted);
|
||||
|
||||
if (request == LXC_USERNIC_DELETE) {
|
||||
int ret;
|
||||
struct alloted_s *it;
|
||||
bool found_nicname = false;
|
||||
|
||||
if (!is_ovs_bridge(args.link)) {
|
||||
usernic_error("%s", "Deletion of non ovs type network "
|
||||
"devices not implemented\n");
|
||||
close(fd);
|
||||
free_alloted(&alloted);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Check whether the network device we are supposed to delete
|
||||
* exists in the db. If it doesn't we will not delete it as we
|
||||
* need to assume the network device is not under our control.
|
||||
* As a side effect we also clear any invalid entries from the
|
||||
* database.
|
||||
*/
|
||||
for (it = alloted; it; it = it->next)
|
||||
cull_entries(fd, it->name, args.type, args.link,
|
||||
args.veth_name, &found_nicname);
|
||||
close(fd);
|
||||
free_alloted(&alloted);
|
||||
|
||||
if (!found_nicname) {
|
||||
usernic_error("%s", "Caller is not allowed to delete "
|
||||
"network device\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = lxc_ovs_delete_port(args.link, args.veth_name);
|
||||
if (ret < 0) {
|
||||
usernic_error("Failed to remove port \"%s\" from "
|
||||
"openvswitch bridge \"%s\"",
|
||||
args.veth_name, args.link);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if (n > 0)
|
||||
gotone = get_nic_if_avail(fd, alloted, pid, argv[4], argv[5], n, &nicname, &cnic);
|
||||
nicname = get_nic_if_avail(fd, alloted, pid, args.type,
|
||||
args.link, n, &cnic);
|
||||
|
||||
close(fd);
|
||||
free_alloted(&alloted);
|
||||
if (!gotone) {
|
||||
if (!nicname) {
|
||||
usernic_error("%s", "Quota reached\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Now rename the link. */
|
||||
if (rename_in_ns(pid, cnic, &vethname) < 0) {
|
||||
newname = lxc_secure_rename_in_ns(pid, cnic, args.veth_name, &ifindex);
|
||||
if (!newname) {
|
||||
usernic_error("%s", "Failed to rename the link\n");
|
||||
if (lxc_netdev_delete_by_name(cnic) < 0)
|
||||
usernic_error("Failed to delete link \"%s\" the link. Manual cleanup needed\n", cnic);
|
||||
ret = lxc_netdev_delete_by_name(cnic);
|
||||
if (ret < 0)
|
||||
usernic_error("Failed to delete \"%s\"\n", cnic);
|
||||
free(nicname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Write the name of the interface pair to the stdout - like
|
||||
* eth0:veth9MT2L4.
|
||||
*/
|
||||
fprintf(stdout, "%s:%s\n", vethname, nicname);
|
||||
/* Write the name of the interface pair to the stdout: eth0:veth9MT2L4 */
|
||||
fprintf(stdout, "%s:%s:%d\n", newname, nicname, ifindex);
|
||||
free(newname);
|
||||
free(nicname);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
1195
src/lxc/network.c
1195
src/lxc/network.c
File diff suppressed because it is too large
Load Diff
@@ -23,11 +23,120 @@
|
||||
#ifndef __LXC_NETWORK_H
|
||||
#define __LXC_NETWORK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "list.h"
|
||||
|
||||
struct lxc_conf;
|
||||
struct lxc_handler;
|
||||
struct lxc_netdev;
|
||||
|
||||
enum {
|
||||
LXC_NET_EMPTY,
|
||||
LXC_NET_VETH,
|
||||
LXC_NET_MACVLAN,
|
||||
LXC_NET_PHYS,
|
||||
LXC_NET_VLAN,
|
||||
LXC_NET_NONE,
|
||||
LXC_NET_MAXCONFTYPE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines the structure to configure an ipv4 address
|
||||
* @address : ipv4 address
|
||||
* @broadcast : ipv4 broadcast address
|
||||
* @mask : network mask
|
||||
*/
|
||||
struct lxc_inetdev {
|
||||
struct in_addr addr;
|
||||
struct in_addr bcast;
|
||||
unsigned int prefix;
|
||||
};
|
||||
|
||||
struct lxc_route {
|
||||
struct in_addr addr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines the structure to configure an ipv6 address
|
||||
* @flags : set the address up
|
||||
* @address : ipv6 address
|
||||
* @broadcast : ipv6 broadcast address
|
||||
* @mask : network mask
|
||||
*/
|
||||
struct lxc_inet6dev {
|
||||
struct in6_addr addr;
|
||||
struct in6_addr mcast;
|
||||
struct in6_addr acast;
|
||||
unsigned int prefix;
|
||||
};
|
||||
|
||||
struct lxc_route6 {
|
||||
struct in6_addr addr;
|
||||
};
|
||||
|
||||
struct ifla_veth {
|
||||
char *pair; /* pair name */
|
||||
char veth1[IFNAMSIZ]; /* needed for deconf */
|
||||
};
|
||||
|
||||
struct ifla_vlan {
|
||||
unsigned int flags;
|
||||
unsigned int fmask;
|
||||
unsigned short vid;
|
||||
unsigned short pad;
|
||||
};
|
||||
|
||||
struct ifla_macvlan {
|
||||
int mode; /* private, vepa, bridge, passthru */
|
||||
};
|
||||
|
||||
union netdev_p {
|
||||
struct ifla_veth veth_attr;
|
||||
struct ifla_vlan vlan_attr;
|
||||
struct ifla_macvlan macvlan_attr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines a structure to configure a network device
|
||||
* @link : lxc.net.[i].link, name of bridge or host iface to attach if any
|
||||
* @name : lxc.net.[i].name, name of iface on the container side
|
||||
* @flags : flag of the network device (IFF_UP, ... )
|
||||
* @ipv4 : a list of ipv4 addresses to be set on the network device
|
||||
* @ipv6 : a list of ipv6 addresses to be set on the network device
|
||||
* @upscript : a script filename to be executed during interface configuration
|
||||
* @downscript : a script filename to be executed during interface destruction
|
||||
* @idx : network counter
|
||||
*/
|
||||
struct lxc_netdev {
|
||||
ssize_t idx;
|
||||
int type;
|
||||
int flags;
|
||||
int ifindex;
|
||||
char *link;
|
||||
char *name;
|
||||
char *hwaddr;
|
||||
char *mtu;
|
||||
union netdev_p priv;
|
||||
struct lxc_list ipv4;
|
||||
struct lxc_list ipv6;
|
||||
struct in_addr *ipv4_gateway;
|
||||
bool ipv4_gateway_auto;
|
||||
struct in6_addr *ipv6_gateway;
|
||||
bool ipv6_gateway_auto;
|
||||
char *upscript;
|
||||
char *downscript;
|
||||
};
|
||||
|
||||
struct saved_nic {
|
||||
int ifindex;
|
||||
char *orig_name;
|
||||
};
|
||||
|
||||
/* Convert a string mac address to a socket structure. */
|
||||
extern int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr);
|
||||
|
||||
@@ -106,11 +215,22 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
|
||||
/* Disable neighbor proxying. */
|
||||
extern int lxc_neigh_proxy_off(const char *name, int family);
|
||||
|
||||
/* Generate a new unique network interface name. */
|
||||
extern char *lxc_mkifname(char *template);
|
||||
/* Generate a new unique network interface name.
|
||||
* Allocated memory must be freed by caller.
|
||||
*/
|
||||
extern char *lxc_mkifname(const char *template);
|
||||
|
||||
extern const char *lxc_net_type_to_str(int type);
|
||||
extern int setup_private_host_hw_addr(char *veth1);
|
||||
extern int netdev_get_mtu(int ifindex);
|
||||
extern int lxc_create_network_priv(struct lxc_handler *handler);
|
||||
extern bool lxc_delete_network(struct lxc_handler *handler);
|
||||
extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
|
||||
extern int lxc_create_network(const char *lxcpath, char *lxcname,
|
||||
struct lxc_list *network, pid_t pid);
|
||||
extern int lxc_requests_empty_network(struct lxc_handler *handler);
|
||||
extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
|
||||
extern int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf,
|
||||
struct lxc_list *network);
|
||||
|
||||
#endif /* __LXC_NETWORK_H */
|
||||
|
@@ -77,6 +77,7 @@
|
||||
#include "mainloop.h"
|
||||
#include "monitor.h"
|
||||
#include "namespace.h"
|
||||
#include "network.h"
|
||||
#include "start.h"
|
||||
#include "storage.h"
|
||||
#include "storage_utils.h"
|
||||
@@ -1246,7 +1247,7 @@ static int lxc_spawn(struct lxc_handler *handler)
|
||||
/* That should be done before the clone because we will
|
||||
* fill the netdev index and use them in the child.
|
||||
*/
|
||||
if (lxc_setup_networks_in_parent_namespaces(handler)) {
|
||||
if (lxc_create_network_priv(handler)) {
|
||||
ERROR("Failed to create the network.");
|
||||
lxc_sync_fini(handler);
|
||||
return -1;
|
||||
@@ -1364,7 +1365,7 @@ static int lxc_spawn(struct lxc_handler *handler)
|
||||
|
||||
/* Create the network configuration. */
|
||||
if (handler->clone_flags & CLONE_NEWNET) {
|
||||
if (lxc_assign_network(handler->lxcpath, handler->name,
|
||||
if (lxc_create_network(handler->lxcpath, handler->name,
|
||||
&handler->conf->network, handler->pid)) {
|
||||
ERROR("Failed to create the configured network.");
|
||||
goto out_delete_net;
|
||||
|
@@ -153,7 +153,7 @@ lxcpath=/home/usernic-user/.local/share/lxc
|
||||
lxcname=b1
|
||||
|
||||
# Assign one veth, should fail as no allowed entries yet
|
||||
if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx1"; then
|
||||
if run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx1"; then
|
||||
echo "FAIL: able to create nic with no entries"
|
||||
exit 1
|
||||
fi
|
||||
@@ -164,24 +164,24 @@ sed -i '/^usernic-user/d' /etc/lxc/lxc-usernet
|
||||
echo "usernic-user veth usernic-br0 2" >> /etc/lxc/lxc-usernet
|
||||
|
||||
# Assign one veth to second bridge, should fail
|
||||
if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br1 xx1"; then
|
||||
if run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br1 xx1"; then
|
||||
echo "FAIL: able to create nic with no entries"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Assign two veths, should succeed
|
||||
if ! run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx2"; then
|
||||
if ! run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx2"; then
|
||||
echo "FAIL: unable to create first nic"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx3"; then
|
||||
if ! run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx3"; then
|
||||
echo "FAIL: unable to create second nic"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Assign one more veth, should fail.
|
||||
if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx4"; then
|
||||
if run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx4"; then
|
||||
echo "FAIL: able to create third nic"
|
||||
exit 1
|
||||
fi
|
||||
@@ -191,7 +191,7 @@ run_cmd "lxc-stop -n b1 -k"
|
||||
run_cmd "lxc-start -n b1 -d"
|
||||
p1=$(run_cmd "lxc-info -n b1 -p -H")
|
||||
|
||||
if ! run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx5"; then
|
||||
if ! run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx5"; then
|
||||
echo "FAIL: unable to create nic after destroying the old"
|
||||
cleanup 1
|
||||
fi
|
||||
@@ -204,7 +204,7 @@ lxc-start -n usernic-c1 -d
|
||||
p2=$(lxc-info -n usernic-c1 -p -H)
|
||||
|
||||
# assign veth to it - should fail
|
||||
if run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p2 veth usernic-br0 xx6"; then
|
||||
if run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p2 veth usernic-br0 xx6"; then
|
||||
echo "FAIL: able to attach nic to root-owned container"
|
||||
cleanup 1
|
||||
fi
|
||||
|
Reference in New Issue
Block a user