}
if (netdev->link) {
- err = lxc_bridge_attach(netdev->link, veth1);
+ err = lxc_bridge_attach(handler->lxcpath, handler->name, netdev->link, veth1);
if (err) {
ERROR("failed to attach '%s' to the bridge '%s': %s",
veth1, netdev->link, strerror(-err));
/* lxc-user-nic returns "interface_name:interface_name\n" */
#define MAX_BUFFER_SIZE IFNAMSIZ*2 + 2
-static int unpriv_assign_nic(struct lxc_netdev *netdev, pid_t pid)
+static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
+ struct lxc_netdev *netdev, pid_t pid)
{
pid_t child;
int bytes, pipefd[2];
} else {
strncpy(netdev_link, "none", IFNAMSIZ);
}
- char *args[] = {LXC_USERNIC_PATH, pidstr, "veth", netdev_link, netdev->name, NULL };
snprintf(pidstr, 19, "%lu", (unsigned long) pid);
pidstr[19] = '\0';
- execvp(args[0], args);
+ execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, lxcpath, lxcname,
+ pidstr, "veth", netdev_link, netdev->name, NULL);
SYSERROR("execvp lxc-user-nic");
exit(1);
}
return 0;
}
-int lxc_assign_network(struct lxc_list *network, pid_t pid)
+int lxc_assign_network(const char *lxcpath, char *lxcname,
+ struct lxc_list *network, pid_t pid)
{
struct lxc_list *iterator;
struct lxc_netdev *netdev;
netdev = iterator->elem;
if (netdev->type == LXC_NET_VETH && !am_root) {
- if (unpriv_assign_nic(netdev, pid))
+ if (unpriv_assign_nic(lxcpath, lxcname, netdev, pid))
return -1;
// lxc-user-nic has moved the nic to the new ns.
// unpriv_assign_nic() fills in netdev->name.
extern int lxc_requests_empty_network(struct lxc_handler *handler);
extern int lxc_create_network(struct lxc_handler *handler);
extern void lxc_delete_network(struct lxc_handler *handler);
-extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
+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);
static void usage(char *me, bool fail)
{
- fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
+ 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);
}
+static char *lxcpath, *lxcname;
+
static int open_and_lock(char *path)
{
int fd;
}
/* attach veth1 to bridge */
- if (lxc_bridge_attach(br, veth1buf) < 0) {
+ if (lxc_bridge_attach(lxcpath, lxcname, br, veth1buf) < 0) {
fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
goto out_del;
}
exit(1);
}
- if (argc < 4)
+ if (argc < 6)
usage(argv[0], true);
- if (argc >= 5)
- vethname = argv[4];
+ if (argc >= 7)
+ vethname = argv[6];
+
+ lxcpath = argv[1];
+ lxcname = argv[2];
errno = 0;
- pid = (int) strtol(argv[1], NULL, 10);
+ pid = (int) strtol(argv[3], NULL, 10);
if (errno) {
fprintf(stderr, "Could not read pid: %s\n", argv[1]);
exit(1);
exit(1);
}
- n = get_alloted(me, argv[2], argv[3], &alloted);
+ n = get_alloted(me, argv[4], argv[5], &alloted);
if (n > 0)
- gotone = get_nic_if_avail(fd, alloted, pid, argv[2], argv[3], n, &nicname, &cnic);
+ gotone = get_nic_if_avail(fd, alloted, pid, argv[4], argv[5], n, &nicname, &cnic);
close(fd);
free_alloted(&alloted);
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/ioctl.h>
+#include <sys/inotify.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
return false;
}
-static int attach_to_ovs_bridge(const char *bridge, const char *nic)
+/*
+ * Called from a background thread - when nic goes away, remove
+ * it from the bridge
+ */
+static void ovs_cleanup_nic(const char *lxcpath, const char *name, const char *bridge, const char *nic)
+{
+ if (lxc_check_inherited(NULL, true, -1) < 0)
+ return;
+ if (lxc_wait(name, "STOPPED", -1, lxcpath) < 0)
+ return;
+ execlp("ovs-vsctl", "ovs-vsctl", "del-port", bridge, nic, NULL);
+ exit(1); /* not reached */
+}
+
+static int attach_to_ovs_bridge(const char *lxcpath, const char *name, const char *bridge, const char *nic)
{
pid_t pid;
char *cmd;
+ int ret;
cmd = on_path("ovs-vsctl", NULL);
if (!cmd)
pid = fork();
if (pid < 0)
return -1;
- if (pid > 0)
- return wait_for_pid(pid);
+ if (pid > 0) {
+ ret = wait_for_pid(pid);
+ if (ret < 0)
+ return ret;
+ pid = fork();
+ if (pid < 0)
+ return -1; // how to properly recover?
+ if (pid > 0)
+ return 0;
+ ovs_cleanup_nic(lxcpath, name, bridge, nic);
+ exit(0);
+ }
if (execlp("ovs-vsctl", "ovs-vsctl", "add-port", bridge, nic, NULL))
exit(1);
* There is a lxc_bridge_attach, but no need of a bridge detach
* as automatically done by kernel when a netdev is deleted.
*/
-int lxc_bridge_attach(const char *bridge, const char *ifname)
+int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge, const char *ifname)
{
int fd, index, err;
struct ifreq ifr;
return -EINVAL;
if (is_ovs_bridge(bridge))
- return attach_to_ovs_bridge(bridge, ifname);
+ return attach_to_ovs_bridge(lxcpath, name, bridge, ifname);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
/*
* Attach an interface to the bridge
*/
-extern int lxc_bridge_attach(const char *bridge, const char *ifname);
+extern int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge, const char *ifname);
/*
* Create default gateway
/* Create the network configuration */
if (handler->clone_flags & CLONE_NEWNET) {
- if (lxc_assign_network(&handler->conf->network, handler->pid)) {
+ if (lxc_assign_network(handler->lxcpath, handler->name,
+ &handler->conf->network, handler->pid)) {
ERROR("failed to create the configured network");
goto out_delete_net;
}