mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-09 03:06:07 +00:00
add lxc.network.script.up configuration hook
This commit adds an configuration option to specify a script to be executed after creating and configuring the network used by the container. The following arguments are passed to the script: * container name * config section name (net) Additional arguments depend on the config section employing a script hook; the following are used by the network system: * execution context (up) * network type (empty/veth/macvlan/phys) Depending on the network type, other arguments may be passed: veth/macvlan/phys: * (host-sided) device name Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
This commit is contained in:
parent
49d3e78dce
commit
e3b4c4c44a
116
src/lxc/conf.c
116
src/lxc/conf.c
@ -24,11 +24,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#undef _GNU_SOURCE
|
#undef _GNU_SOURCE
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <pty.h>
|
#include <pty.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -92,7 +94,7 @@ lxc_log_define(lxc_conf, lxc);
|
|||||||
|
|
||||||
extern int pivot_root(const char * new_root, const char * put_old);
|
extern int pivot_root(const char * new_root, const char * put_old);
|
||||||
|
|
||||||
typedef int (*instanciate_cb)(struct lxc_netdev *);
|
typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
|
||||||
|
|
||||||
struct mount_opt {
|
struct mount_opt {
|
||||||
char *name;
|
char *name;
|
||||||
@ -105,11 +107,11 @@ struct caps_opt {
|
|||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int instanciate_veth(struct lxc_netdev *);
|
static int instanciate_veth(struct lxc_handler *, struct lxc_netdev *);
|
||||||
static int instanciate_macvlan(struct lxc_netdev *);
|
static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *);
|
||||||
static int instanciate_vlan(struct lxc_netdev *);
|
static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *);
|
||||||
static int instanciate_phys(struct lxc_netdev *);
|
static int instanciate_phys(struct lxc_handler *, struct lxc_netdev *);
|
||||||
static int instanciate_empty(struct lxc_netdev *);
|
static int instanciate_empty(struct lxc_handler *, struct lxc_netdev *);
|
||||||
|
|
||||||
static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
|
static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
|
||||||
[LXC_NET_VETH] = instanciate_veth,
|
[LXC_NET_VETH] = instanciate_veth,
|
||||||
@ -184,6 +186,53 @@ static struct caps_opt caps_opt[] = {
|
|||||||
{ "mac_admin", CAP_MAC_ADMIN },
|
{ "mac_admin", CAP_MAC_ADMIN },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int run_script(const char *name, const char *section, const char *script, ...)
|
||||||
|
{
|
||||||
|
va_list argp;
|
||||||
|
int vargc = 4;
|
||||||
|
/* count variable arguments and add 4 for script, container
|
||||||
|
* and section name as well as the terminating NULL
|
||||||
|
*/
|
||||||
|
va_start(argp, script);
|
||||||
|
while (va_arg(argp, char*)) vargc++;
|
||||||
|
va_end(argp);
|
||||||
|
INFO("Executing script '%s' for container '%s', config section '%s'", script, name, section);
|
||||||
|
|
||||||
|
int pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
ERROR("Error forking");
|
||||||
|
} else if (pid == 0) {
|
||||||
|
/* prepare command line arguments */
|
||||||
|
char *args[vargc];
|
||||||
|
int i;
|
||||||
|
args[0] = strdup(script);
|
||||||
|
args[1] = strdup(name);
|
||||||
|
args[2] = strdup(section);
|
||||||
|
va_start(argp, script);
|
||||||
|
for (i=3; i<vargc; i++) {
|
||||||
|
args[i] = va_arg(argp, char*);
|
||||||
|
}
|
||||||
|
va_end(argp);
|
||||||
|
args[vargc-1] = (char*) NULL;
|
||||||
|
|
||||||
|
execv(script, args);
|
||||||
|
/* if we cannot exec, we exit this fork */
|
||||||
|
SYSERROR("Failed to execute script '%s' for container '%s': %s", script, name, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
int status = 0;
|
||||||
|
waitpid( pid, &status, 0 );
|
||||||
|
if (status != 0) {
|
||||||
|
/* something weird happened */
|
||||||
|
SYSERROR("Script '%s' terminated with non-zero exitcode %d", name, status);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0; /* all is well */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int find_fstype_cb(char* buffer, void *data)
|
static int find_fstype_cb(char* buffer, void *data)
|
||||||
{
|
{
|
||||||
struct cbarg {
|
struct cbarg {
|
||||||
@ -1204,7 +1253,7 @@ struct lxc_conf *lxc_conf_init(void)
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instanciate_veth(struct lxc_netdev *netdev)
|
static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
char veth1buf[IFNAMSIZ], *veth1;
|
char veth1buf[IFNAMSIZ], *veth1;
|
||||||
char veth2buf[IFNAMSIZ], *veth2;
|
char veth2buf[IFNAMSIZ], *veth2;
|
||||||
@ -1267,6 +1316,16 @@ static int instanciate_veth(struct lxc_netdev *netdev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (netdev->upscript) {
|
||||||
|
err = run_script(handler->name, "net", netdev->upscript, "up", "veth",
|
||||||
|
veth1, (char*) NULL);
|
||||||
|
if (err) {
|
||||||
|
ERROR("Failed to run script '%s' for container '%s' and interface '%s'",
|
||||||
|
netdev->upscript, handler->name, veth1);
|
||||||
|
goto out_delete;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG("instanciated veth '%s/%s', index is '%d'",
|
DEBUG("instanciated veth '%s/%s', index is '%d'",
|
||||||
veth1, veth2, netdev->ifindex);
|
veth1, veth2, netdev->ifindex);
|
||||||
|
|
||||||
@ -1277,7 +1336,7 @@ out_delete:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instanciate_macvlan(struct lxc_netdev *netdev)
|
static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
char peerbuf[IFNAMSIZ], *peer;
|
char peerbuf[IFNAMSIZ], *peer;
|
||||||
int err;
|
int err;
|
||||||
@ -1310,6 +1369,16 @@ static int instanciate_macvlan(struct lxc_netdev *netdev)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (netdev->upscript) {
|
||||||
|
err = run_script(handler->name, "net", netdev->upscript, "up", "macvlan",
|
||||||
|
netdev->link, (char*) NULL);
|
||||||
|
if (err) {
|
||||||
|
ERROR("Failed to run script '%s' for container '%s' and interface '%s'",
|
||||||
|
netdev->upscript, handler->name, netdev->link);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
|
DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
|
||||||
peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
|
peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
|
||||||
|
|
||||||
@ -1317,7 +1386,7 @@ static int instanciate_macvlan(struct lxc_netdev *netdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: merge with instanciate_macvlan */
|
/* XXX: merge with instanciate_macvlan */
|
||||||
static int instanciate_vlan(struct lxc_netdev *netdev)
|
static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
char peer[IFNAMSIZ];
|
char peer[IFNAMSIZ];
|
||||||
int err;
|
int err;
|
||||||
@ -1349,7 +1418,7 @@ static int instanciate_vlan(struct lxc_netdev *netdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instanciate_phys(struct lxc_netdev *netdev)
|
static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
if (!netdev->link) {
|
if (!netdev->link) {
|
||||||
ERROR("no link specified for the physical interface");
|
ERROR("no link specified for the physical interface");
|
||||||
@ -1362,17 +1431,37 @@ static int instanciate_phys(struct lxc_netdev *netdev)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (netdev->upscript) {
|
||||||
|
int err;
|
||||||
|
err = run_script(handler->name, "net", netdev->upscript, "up", "phys",
|
||||||
|
netdev->link, (char*) NULL);
|
||||||
|
if (err) {
|
||||||
|
ERROR("Failed to run script '%s' for container '%s' and interface '%s'",
|
||||||
|
netdev->upscript, handler->name, netdev->link);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instanciate_empty(struct lxc_netdev *netdev)
|
static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
netdev->ifindex = 0;
|
netdev->ifindex = 0;
|
||||||
|
if (netdev->upscript) {
|
||||||
|
int err;
|
||||||
|
err = run_script(handler->name, "net", netdev->upscript, "up", "empty", (char*) NULL);
|
||||||
|
if (err) {
|
||||||
|
ERROR("Failed to run script '%s' for container '%s'", netdev->upscript, handler->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lxc_create_network(struct lxc_list *network)
|
int lxc_create_network(struct lxc_handler *handler)
|
||||||
{
|
{
|
||||||
|
struct lxc_list *network = &handler->conf->network;
|
||||||
struct lxc_list *iterator;
|
struct lxc_list *iterator;
|
||||||
struct lxc_netdev *netdev;
|
struct lxc_netdev *netdev;
|
||||||
|
|
||||||
@ -1386,10 +1475,11 @@ int lxc_create_network(struct lxc_list *network)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (netdev_conf[netdev->type](netdev)) {
|
if (netdev_conf[netdev->type](handler, netdev)) {
|
||||||
ERROR("failed to create netdev");
|
ERROR("failed to create netdev");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#include <lxc/list.h>
|
#include <lxc/list.h>
|
||||||
|
|
||||||
|
#include <start.h> /* for lxc_handler */
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
LXC_NET_EMPTY,
|
LXC_NET_EMPTY,
|
||||||
LXC_NET_VETH,
|
LXC_NET_VETH,
|
||||||
@ -94,11 +96,12 @@ union netdev_p {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Defines a structure to configure a network device
|
* Defines a structure to configure a network device
|
||||||
* @link : lxc.network.link, name of bridge or host iface to attach if any
|
* @link : lxc.network.link, name of bridge or host iface to attach if any
|
||||||
* @name : lxc.network.name, name of iface on the container side
|
* @name : lxc.network.name, name of iface on the container side
|
||||||
* @flags : flag of the network device (IFF_UP, ... )
|
* @flags : flag of the network device (IFF_UP, ... )
|
||||||
* @ipv4 : a list of ipv4 addresses to be set on the network device
|
* @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
|
* @ipv6 : a list of ipv6 addresses to be set on the network device
|
||||||
|
* @upscript : a script filename to be executed during interface configuration
|
||||||
*/
|
*/
|
||||||
struct lxc_netdev {
|
struct lxc_netdev {
|
||||||
int type;
|
int type;
|
||||||
@ -111,6 +114,7 @@ struct lxc_netdev {
|
|||||||
union netdev_p priv;
|
union netdev_p priv;
|
||||||
struct lxc_list ipv4;
|
struct lxc_list ipv4;
|
||||||
struct lxc_list ipv6;
|
struct lxc_list ipv6;
|
||||||
|
char *upscript;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -210,7 +214,7 @@ struct lxc_conf {
|
|||||||
*/
|
*/
|
||||||
extern struct lxc_conf *lxc_conf_init(void);
|
extern struct lxc_conf *lxc_conf_init(void);
|
||||||
|
|
||||||
extern int lxc_create_network(struct lxc_list *networks);
|
extern int lxc_create_network(struct lxc_handler *handler);
|
||||||
extern void lxc_delete_network(struct lxc_list *networks);
|
extern void lxc_delete_network(struct lxc_list *networks);
|
||||||
extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
|
extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
|
||||||
|
|
||||||
@ -221,8 +225,5 @@ extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
|
|||||||
* Configure the container from inside
|
* Configure the container from inside
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct lxc_handler;
|
|
||||||
|
|
||||||
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf);
|
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,6 +63,7 @@ static int config_network_hwaddr(const char *, char *, struct lxc_conf *);
|
|||||||
static int config_network_vlan_id(const char *, char *, struct lxc_conf *);
|
static int config_network_vlan_id(const char *, char *, struct lxc_conf *);
|
||||||
static int config_network_mtu(const char *, char *, struct lxc_conf *);
|
static int config_network_mtu(const char *, char *, struct lxc_conf *);
|
||||||
static int config_network_ipv4(const char *, char *, struct lxc_conf *);
|
static int config_network_ipv4(const char *, char *, struct lxc_conf *);
|
||||||
|
static int config_network_script(const char *, char *, struct lxc_conf *);
|
||||||
static int config_network_ipv6(const char *, char *, struct lxc_conf *);
|
static int config_network_ipv6(const char *, char *, struct lxc_conf *);
|
||||||
static int config_cap_drop(const char *, char *, struct lxc_conf *);
|
static int config_cap_drop(const char *, char *, struct lxc_conf *);
|
||||||
static int config_console(const char *, char *, struct lxc_conf *);
|
static int config_console(const char *, char *, struct lxc_conf *);
|
||||||
@ -91,6 +92,7 @@ static struct config config[] = {
|
|||||||
{ "lxc.network.name", config_network_name },
|
{ "lxc.network.name", config_network_name },
|
||||||
{ "lxc.network.macvlan.mode", config_network_macvlan_mode },
|
{ "lxc.network.macvlan.mode", config_network_macvlan_mode },
|
||||||
{ "lxc.network.veth.pair", config_network_veth_pair },
|
{ "lxc.network.veth.pair", config_network_veth_pair },
|
||||||
|
{ "lxc.network.script.up", config_network_script },
|
||||||
{ "lxc.network.hwaddr", config_network_hwaddr },
|
{ "lxc.network.hwaddr", config_network_hwaddr },
|
||||||
{ "lxc.network.mtu", config_network_mtu },
|
{ "lxc.network.mtu", config_network_mtu },
|
||||||
{ "lxc.network.vlan.id", config_network_vlan_id },
|
{ "lxc.network.vlan.id", config_network_vlan_id },
|
||||||
@ -478,6 +480,29 @@ static int config_network_ipv6(const char *key, char *value,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int config_network_script(const char *key, char *value,
|
||||||
|
struct lxc_conf *lxc_conf)
|
||||||
|
{
|
||||||
|
struct lxc_netdev *netdev;
|
||||||
|
|
||||||
|
netdev = network_netdev(key, value, &lxc_conf->network);
|
||||||
|
if (!netdev)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char *copy = strdup(value);
|
||||||
|
if (!copy) {
|
||||||
|
SYSERROR("failed to dup string '%s'", value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (strcmp(key, "lxc.network.script.up") == 0) {
|
||||||
|
netdev->upscript = copy;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SYSERROR("Unknown key: %s", key);
|
||||||
|
free(copy);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int config_personality(const char *key, char *value,
|
static int config_personality(const char *key, char *value,
|
||||||
struct lxc_conf *lxc_conf)
|
struct lxc_conf *lxc_conf)
|
||||||
{
|
{
|
||||||
|
@ -487,7 +487,7 @@ int lxc_spawn(struct lxc_handler *handler)
|
|||||||
/* that should be done before the clone because we will
|
/* that should be done before the clone because we will
|
||||||
* fill the netdev index and use them in the child
|
* fill the netdev index and use them in the child
|
||||||
*/
|
*/
|
||||||
if (lxc_create_network(&handler->conf->network)) {
|
if (lxc_create_network(handler)) {
|
||||||
ERROR("failed to create the network");
|
ERROR("failed to create the network");
|
||||||
lxc_sync_fini(handler);
|
lxc_sync_fini(handler);
|
||||||
return -1;
|
return -1;
|
||||||
|
Loading…
Reference in New Issue
Block a user