diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 8cafdae50..1f1f9ea90 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -3442,11 +3442,9 @@ static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname, } ret = lxc_netdev_isup(ifname); - if (ret < 0) - goto err; - /* netdev of ifname is up. */ - if (ret) { + if (ret > 0) { + /* netdev of ifname is up. */ ret = lxc_netdev_down(ifname); if (ret) goto err; @@ -3457,11 +3455,8 @@ static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname, goto err; return true; + err: - /* -EINVAL means there is no netdev named as ifanme. */ - if (ret == -EINVAL) { - ERROR("No network device named as %s.", ifname); - } return false; } diff --git a/src/lxc/network.c b/src/lxc/network.c index 941cb35e4..136e4e06d 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -141,9 +141,116 @@ out: return err; } +/* + * If we are asked to move a wireless interface, then + * we must actually move its phyN device. Detect + * that condition and return the physname here. The + * physname will be passed to lxc_netdev_move_wlan() + * which will free it when done + */ +#define PHYSNAME "/sys/class/net/%s/phy80211/name" +static char * is_wlan(const char *ifname) +{ + char *path, *physname = NULL; + size_t len = strlen(ifname) + strlen(PHYSNAME) - 1; + struct stat sb; + long physlen; + FILE *f; + int ret, i; + + path = alloca(len+1); + ret = snprintf(path, len, PHYSNAME, ifname); + if (ret < 0 || ret >= len) + goto bad; + ret = stat(path, &sb); + if (ret) + goto bad; + if (!(f = fopen(path, "r"))) + goto bad; + // feh - sb.st_size is always 4096 + fseek(f, 0, SEEK_END); + physlen = ftell(f); + fseek(f, 0, SEEK_SET); + physname = malloc(physlen+1); + if (!physname) + goto bad; + memset(physname, 0, physlen+1); + ret = fread(physname, 1, physlen, f); + fclose(f); + if (ret < 0) + goto bad; + + for (i = 0; i < physlen; i++) { + if (physname[i] == '\n') + physname[i] = '\0'; + if (physname[i] == '\0') + break; + } + + return physname; + +bad: + if (physname) + free(physname); + return NULL; +} + +static int +lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old, const char *new) +{ + pid_t fpid = fork(); + + if (fpid < 0) + return -1; + if (fpid != 0) + return wait_for_pid(fpid); + if (!switch_to_ns(pid, "net")) + return -1; + exit(lxc_netdev_rename_by_name(old, new)); +} + +static int +lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, const char* newname) +{ + int err = -1; + pid_t fpid; + char *cmd; + + /* Move phyN into the container. TODO - do this using netlink. + * However, IIUC this involves a bit more complicated work to + * talk to the 80211 module, so for now just call out to iw + */ + cmd = on_path("iw", NULL); + if (!cmd) + goto out1; + free(cmd); + + fpid = fork(); + if (fpid < 0) + goto out1; + if (fpid == 0) { + char pidstr[30]; + sprintf(pidstr, "%d", pid); + if (execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, NULL)) + exit(1); + exit(0); // notreached + } + if (wait_for_pid(fpid)) + goto out1; + + err = 0; + if (newname) + err = lxc_netdev_rename_by_name_in_netns(pid, ifname, newname); + +out1: + free(physname); + return err; +} + int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname) { int index; + char *physname; if (!ifname) return -EINVAL; @@ -152,6 +259,9 @@ int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname) if (!index) return -EINVAL; + if ((physname = is_wlan(ifname))) + return lxc_netdev_move_wlan(physname, ifname, pid, newname); + return lxc_netdev_move_by_index(index, pid, newname); }