"autodev", "start", "stop",
"post-stop", "clone", "destroy"};
-typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
-
struct mount_opt {
char *name;
int clear;
/* Declare this here, since we don't want to reshuffle the whole file. */
static int in_caplist(int cap, struct lxc_list *caps);
-static int instantiate_veth(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_phys(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_empty(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_none(struct lxc_handler *, struct lxc_netdev *);
-
-static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
- [LXC_NET_VETH] = instantiate_veth,
- [LXC_NET_MACVLAN] = instantiate_macvlan,
- [LXC_NET_VLAN] = instantiate_vlan,
- [LXC_NET_PHYS] = instantiate_phys,
- [LXC_NET_EMPTY] = instantiate_empty,
- [LXC_NET_NONE] = instantiate_none,
-};
-
-static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_none(struct lxc_handler *, struct lxc_netdev *);
-
-static instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
- [LXC_NET_VETH] = shutdown_veth,
- [LXC_NET_MACVLAN] = shutdown_macvlan,
- [LXC_NET_VLAN] = shutdown_vlan,
- [LXC_NET_PHYS] = shutdown_phys,
- [LXC_NET_EMPTY] = shutdown_empty,
- [LXC_NET_NONE] = shutdown_none,
-};
-
static struct mount_opt mount_opt[] = {
{ "async", 1, MS_SYNCHRONOUS },
{ "atime", 1, MS_NOATIME },
return run_buffer(buffer);
}
-static int run_script(const char *name, const char *section, const char *script,
- ...)
+int run_script(const char *name, const char *section, const char *script, ...)
{
int ret;
char *buffer, *p;
return 0;
}
-static int setup_hw_addr(char *hwaddr, const char *ifname)
-{
- struct sockaddr sockaddr;
- struct ifreq ifr;
- int ret, fd, saved_errno;
-
- ret = lxc_convert_mac(hwaddr, &sockaddr);
- if (ret) {
- ERROR("mac address '%s' conversion failed : %s",
- hwaddr, strerror(-ret));
- return -1;
- }
-
- memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_name[IFNAMSIZ-1] = '\0';
- memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
-
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd < 0) {
- ERROR("socket failure : %s", strerror(errno));
- return -1;
- }
-
- ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
- saved_errno = errno;
- close(fd);
- if (ret)
- ERROR("ioctl failure : %s", strerror(saved_errno));
-
- DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifr.ifr_name);
-
- return ret;
-}
-
-static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
-{
- struct lxc_list *iterator;
- struct lxc_inetdev *inetdev;
- int err;
-
- lxc_list_for_each(iterator, ip) {
-
- inetdev = iterator->elem;
-
- err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
- &inetdev->bcast, inetdev->prefix);
- if (err) {
- ERROR("failed to setup_ipv4_addr ifindex %d : %s",
- ifindex, strerror(-err));
- return -1;
- }
- }
-
- return 0;
-}
-
-static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
-{
- struct lxc_list *iterator;
- struct lxc_inet6dev *inet6dev;
- int err;
-
- lxc_list_for_each(iterator, ip) {
-
- inet6dev = iterator->elem;
-
- err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
- &inet6dev->mcast, &inet6dev->acast,
- inet6dev->prefix);
- if (err) {
- ERROR("failed to setup_ipv6_addr ifindex %d : %s",
- ifindex, strerror(-err));
- return -1;
- }
- }
-
- return 0;
-}
-
-static int setup_netdev(struct lxc_netdev *netdev)
-{
- char ifname[IFNAMSIZ];
- char *current_ifname = ifname;
- int err;
-
- /* empty network namespace */
- if (!netdev->ifindex) {
- if (netdev->flags & IFF_UP) {
- err = lxc_netdev_up("lo");
- if (err) {
- ERROR("failed to set the loopback up : %s",
- strerror(-err));
- return -1;
- }
- }
- if (netdev->type != LXC_NET_VETH)
- return 0;
- netdev->ifindex = if_nametoindex(netdev->name);
- }
-
- /* get the new ifindex in case of physical netdev */
- if (netdev->type == LXC_NET_PHYS) {
- if (!(netdev->ifindex = if_nametoindex(netdev->link))) {
- ERROR("failed to get ifindex for %s",
- netdev->link);
- return -1;
- }
- }
-
- /* retrieve the name of the interface */
- if (!if_indextoname(netdev->ifindex, current_ifname)) {
- ERROR("no interface corresponding to index '%d'",
- netdev->ifindex);
- return -1;
- }
-
- /* Default: let the system to choose one interface name.
- * When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
- * netlink will replace the format specifier with an appropriate index.
- */
- if (!netdev->name)
- netdev->name = netdev->type == LXC_NET_PHYS ?
- netdev->link : "eth%d";
-
- /* rename the interface name */
- if (strcmp(ifname, netdev->name) != 0) {
- err = lxc_netdev_rename_by_name(ifname, netdev->name);
- if (err) {
- ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
- strerror(-err));
- return -1;
- }
- }
-
- /* Re-read the name of the interface because its name has changed
- * and would be automatically allocated by the system
- */
- if (!if_indextoname(netdev->ifindex, current_ifname)) {
- ERROR("no interface corresponding to index '%d'",
- netdev->ifindex);
- return -1;
- }
-
- /* set a mac address */
- if (netdev->hwaddr) {
- if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
- ERROR("failed to setup hw address for '%s'",
- current_ifname);
- return -1;
- }
- }
-
- /* setup ipv4 addresses on the interface */
- if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
- ERROR("failed to setup ip addresses for '%s'",
- ifname);
- return -1;
- }
-
- /* setup ipv6 addresses on the interface */
- if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
- ERROR("failed to setup ipv6 addresses for '%s'",
- ifname);
- return -1;
- }
-
- /* set the network device up */
- if (netdev->flags & IFF_UP) {
- int err;
-
- err = lxc_netdev_up(current_ifname);
- if (err) {
- ERROR("failed to set '%s' up : %s", current_ifname,
- strerror(-err));
- return -1;
- }
-
- /* the network is up, make the loopback up too */
- err = lxc_netdev_up("lo");
- if (err) {
- ERROR("failed to set the loopback up : %s",
- strerror(-err));
- return -1;
- }
- }
-
- /* We can only set up the default routes after bringing
- * up the interface, sine bringing up the interface adds
- * the link-local routes and we can't add a default
- * route if the gateway is not reachable. */
-
- /* setup ipv4 gateway on the interface */
- if (netdev->ipv4_gateway) {
- if (!(netdev->flags & IFF_UP)) {
- ERROR("Cannot add ipv4 gateway for %s when not bringing up the interface", ifname);
- return -1;
- }
-
- if (lxc_list_empty(&netdev->ipv4)) {
- ERROR("Cannot add ipv4 gateway for %s when not assigning an address", ifname);
- return -1;
- }
-
- err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
- if (err) {
- err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
- if (err) {
- ERROR("failed to add ipv4 dest for '%s': %s",
- ifname, strerror(-err));
- }
-
- err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
- if (err) {
- ERROR("failed to setup ipv4 gateway for '%s': %s",
- ifname, strerror(-err));
- if (netdev->ipv4_gateway_auto) {
- char buf[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
- ERROR("tried to set autodetected ipv4 gateway '%s'", buf);
- }
- return -1;
- }
- }
- }
-
- /* setup ipv6 gateway on the interface */
- if (netdev->ipv6_gateway) {
- if (!(netdev->flags & IFF_UP)) {
- ERROR("Cannot add ipv6 gateway for %s when not bringing up the interface", ifname);
- return -1;
- }
-
- if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
- ERROR("Cannot add ipv6 gateway for %s when not assigning an address", ifname);
- return -1;
- }
-
- err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
- if (err) {
- err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
- if (err) {
- ERROR("failed to add ipv6 dest for '%s': %s",
- ifname, strerror(-err));
- }
-
- err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
- if (err) {
- ERROR("failed to setup ipv6 gateway for '%s': %s",
- ifname, strerror(-err));
- if (netdev->ipv6_gateway_auto) {
- char buf[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
- ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
- }
- return -1;
- }
- }
- }
-
- DEBUG("'%s' has been setup", current_ifname);
-
- return 0;
-}
-
-static int setup_network(struct lxc_list *network)
-{
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
-
- lxc_list_for_each(iterator, network) {
-
- netdev = iterator->elem;
-
- if (setup_netdev(netdev)) {
- ERROR("failed to setup netdev");
- return -1;
- }
- }
-
- if (!lxc_list_empty(network))
- INFO("network has been setup");
-
- return 0;
-}
-
-/* try to move physical nics to the init netns */
-void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
-{
- int i, oldfd;
- char ifname[IFNAMSIZ];
-
- if (netnsfd < 0 || conf->num_savednics == 0)
- return;
-
- INFO("Running to reset %d nic names.", conf->num_savednics);
-
- oldfd = lxc_preserve_ns(getpid(), "net");
- if (oldfd < 0) {
- SYSERROR("Failed to open monitor netns fd.");
- return;
- }
-
- if (setns(netnsfd, 0) != 0) {
- SYSERROR("Failed to enter container netns to reset nics");
- close(oldfd);
- return;
- }
- for (i=0; i<conf->num_savednics; i++) {
- struct saved_nic *s = &conf->saved_nics[i];
- /* retrieve the name of the interface */
- if (!if_indextoname(s->ifindex, ifname)) {
- WARN("no interface corresponding to index '%d'", s->ifindex);
- continue;
- }
- if (lxc_netdev_move_by_name(ifname, 1, s->orig_name))
- WARN("Error moving nic name:%s back to host netns", ifname);
- free(s->orig_name);
- }
- conf->num_savednics = 0;
-
- if (setns(oldfd, 0) != 0)
- SYSERROR("Failed to re-enter monitor's netns");
- close(oldfd);
-}
-
static char *default_rootfs_mount = LXCROOTFSMOUNT;
struct lxc_conf *lxc_conf_init(void)
return new;
}
-static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char *veth1, *veth2;
- char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
- int bridge_index, err;
- unsigned int mtu = 0;
-
- if (netdev->priv.veth_attr.pair) {
- veth1 = netdev->priv.veth_attr.pair;
- if (handler->conf->reboot)
- lxc_netdev_delete_by_name(veth1);
- } else {
- err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
- if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */
- ERROR("veth1 name too long");
- return -1;
- }
- veth1 = lxc_mkifname(veth1buf);
- if (!veth1) {
- ERROR("failed to allocate a temporary name");
- return -1;
- }
- /* store away for deconf */
- memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
- }
-
- snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
- veth2 = lxc_mkifname(veth2buf);
- if (!veth2) {
- ERROR("failed to allocate a temporary name");
- goto out_delete;
- }
-
- err = lxc_veth_create(veth1, veth2);
- if (err) {
- ERROR("failed to create veth pair \"%s\" and \"%s\": %s", veth1,
- veth2, strerror(-err));
- goto out_delete;
- }
-
- /* changing the high byte of the mac address to 0xfe, the bridge interface
- * will always keep the host's mac address and not take the mac address
- * of a container */
- err = setup_private_host_hw_addr(veth1);
- if (err) {
- ERROR("failed to change mac address of host interface \"%s\": %s",
- veth1, strerror(-err));
- goto out_delete;
- }
-
- netdev->ifindex = if_nametoindex(veth2);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the index for \"%s\"", veth2);
- goto out_delete;
- }
-
- if (netdev->mtu) {
- if (lxc_safe_uint(netdev->mtu, &mtu) < 0)
- WARN("failed to parse mtu from");
- else
- INFO("retrieved mtu %d", mtu);
- } else if (netdev->link) {
- bridge_index = if_nametoindex(netdev->link);
- if (bridge_index) {
- mtu = netdev_get_mtu(bridge_index);
- INFO("retrieved mtu %d from %s", mtu, netdev->link);
- } else {
- mtu = netdev_get_mtu(netdev->ifindex);
- INFO("retrieved mtu %d from %s", mtu, veth2);
- }
- }
-
- if (mtu) {
- err = lxc_netdev_set_mtu(veth1, mtu);
- if (!err)
- err = lxc_netdev_set_mtu(veth2, mtu);
- if (err) {
- ERROR("failed to set mtu \"%d\" for veth pair \"%s\" "
- "and \"%s\": %s",
- mtu, veth1, veth2, strerror(-err));
- goto out_delete;
- }
- }
-
- if (netdev->link) {
- err = lxc_bridge_attach(netdev->link, veth1);
- if (err) {
- ERROR("failed to attach \"%s\" to bridge \"%s\": %s",
- veth1, netdev->link, strerror(-err));
- goto out_delete;
- }
- INFO("attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
- }
-
- err = lxc_netdev_up(veth1);
- if (err) {
- ERROR("failed to set \"%s\" up: %s", veth1, strerror(-err));
- goto out_delete;
- }
-
- if (netdev->upscript) {
- err = run_script(handler->name, "net", netdev->upscript, "up",
- "veth", veth1, (char*) NULL);
- if (err)
- goto out_delete;
- }
-
- DEBUG("instantiated veth \"%s/%s\", index is \"%d\"", veth1, veth2,
- netdev->ifindex);
-
- return 0;
-
-out_delete:
- if (netdev->ifindex != 0)
- lxc_netdev_delete_by_name(veth1);
- if (!netdev->priv.veth_attr.pair)
- free(veth1);
- free(veth2);
- return -1;
-}
-
-static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char *veth1;
- int err;
-
- if (netdev->priv.veth_attr.pair)
- veth1 = netdev->priv.veth_attr.pair;
- else
- veth1 = netdev->priv.veth_attr.veth1;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "veth", veth1, (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char peerbuf[IFNAMSIZ], *peer;
- int err;
-
- if (!netdev->link) {
- ERROR("no link specified for macvlan netdev");
- return -1;
- }
-
- err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
- if (err >= sizeof(peerbuf))
- return -1;
-
- peer = lxc_mkifname(peerbuf);
- if (!peer) {
- ERROR("failed to make a temporary name");
- return -1;
- }
-
- err = lxc_macvlan_create(netdev->link, peer,
- netdev->priv.macvlan_attr.mode);
- if (err) {
- ERROR("failed to create macvlan interface '%s' on '%s' : %s",
- peer, netdev->link, strerror(-err));
- goto out;
- }
-
- netdev->ifindex = if_nametoindex(peer);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the index for %s", peer);
- goto out;
- }
-
- if (netdev->upscript) {
- err = run_script(handler->name, "net", netdev->upscript, "up",
- "macvlan", netdev->link, (char*) NULL);
- if (err)
- goto out;
- }
-
- DEBUG("instantiated macvlan '%s', index is '%d' and mode '%d'",
- peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
-
- return 0;
-out:
- lxc_netdev_delete_by_name(peer);
- free(peer);
- return -1;
-}
-
-static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- int err;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "macvlan", netdev->link,
- (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-/* XXX: merge with instantiate_macvlan */
-static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char peer[IFNAMSIZ];
- int err;
- static uint16_t vlan_cntr = 0;
- unsigned int mtu = 0;
-
- if (!netdev->link) {
- ERROR("no link specified for vlan netdev");
- return -1;
- }
-
- err = snprintf(peer, sizeof(peer), "vlan%d-%d", netdev->priv.vlan_attr.vid, vlan_cntr++);
- if (err >= sizeof(peer)) {
- ERROR("peer name too long");
- return -1;
- }
-
- err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
- if (err) {
- ERROR("failed to create vlan interface '%s' on '%s' : %s",
- peer, netdev->link, strerror(-err));
- return -1;
- }
-
- netdev->ifindex = if_nametoindex(peer);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the ifindex for %s", peer);
- lxc_netdev_delete_by_name(peer);
- return -1;
- }
-
- DEBUG("instantiated vlan '%s', ifindex is '%d'", " vlan1000",
- netdev->ifindex);
- if (netdev->mtu) {
- if (lxc_safe_uint(netdev->mtu, &mtu) < 0) {
- ERROR("Failed to retrieve mtu from: '%d'/'%s'.",
- netdev->ifindex, netdev->name);
- return -1;
- }
- err = lxc_netdev_set_mtu(peer, mtu);
- if (err) {
- ERROR("failed to set mtu '%s' for %s : %s",
- netdev->mtu, peer, strerror(-err));
- lxc_netdev_delete_by_name(peer);
- return -1;
- }
- }
-
- return 0;
-}
-
-static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- return 0;
-}
-
-static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- if (!netdev->link) {
- ERROR("no link specified for the physical interface");
- return -1;
- }
-
- netdev->ifindex = if_nametoindex(netdev->link);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the index for %s", netdev->link);
- return -1;
- }
-
- if (netdev->upscript) {
- int err;
- err = run_script(handler->name, "net", netdev->upscript,
- "up", "phys", netdev->link, (char*) NULL);
- if (err)
- return -1;
- }
-
- return 0;
-}
-
-static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- int err;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "phys", netdev->link, (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- netdev->ifindex = 0;
- return 0;
-}
-
-static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- netdev->ifindex = 0;
- if (netdev->upscript) {
- int err;
- err = run_script(handler->name, "net", netdev->upscript,
- "up", "empty", (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- int err;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "empty", (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- return 0;
-}
-
-int lxc_requests_empty_network(struct lxc_handler *handler)
-{
- struct lxc_list *network = &handler->conf->network;
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
- bool found_none = false, found_nic = false;
-
- if (lxc_list_empty(network))
- return 0;
-
- lxc_list_for_each(iterator, network) {
-
- netdev = iterator->elem;
-
- if (netdev->type == LXC_NET_NONE)
- found_none = true;
- else
- found_nic = true;
- }
- if (found_none && !found_nic)
- return 1;
- return 0;
-}
-
-int lxc_create_network(struct lxc_handler *handler)
-{
- struct lxc_list *network = &handler->conf->network;
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
- int am_root = (getuid() == 0);
-
- if (!am_root)
- return 0;
-
- lxc_log_configured_netdevs(handler->conf);
-
- lxc_list_for_each(iterator, network) {
-
- netdev = iterator->elem;
-
- if (netdev_conf[netdev->type](handler, netdev)) {
- ERROR("failed to create netdev");
- return -1;
- }
-
- }
-
- return 0;
-}
-
-bool lxc_delete_network(struct lxc_handler *handler)
-{
- int ret;
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
- bool deleted_all = true;
-
- lxc_list_for_each(iterator, network) {
- 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.
- */
- if (!netdev->ifindex)
- continue;
-
- if (netdev->type == LXC_NET_PHYS) {
- ret = lxc_netdev_rename_by_index(netdev->ifindex, netdev->link);
- if (ret < 0)
- WARN("Failed to rename interface with index %d "
- "to its initial name \"%s\"",
- netdev->ifindex, netdev->link);
- else
- TRACE("Renamed interface with index %d to its "
- "initial name \"%s\"",
- netdev->ifindex, netdev->link);
- continue;
- }
-
- ret = netdev_deconf[netdev->type](handler, netdev);
- if (ret < 0)
- WARN("Failed to deconfigure network device");
-
- /* Recent kernels remove the virtual interfaces when the network
- * namespace is destroyed but in case we did not move the
- * interface to the network namespace, we have to destroy it.
- */
- if (!am_unpriv()) {
- ret = lxc_netdev_delete_by_index(netdev->ifindex);
- if (-ret == ENODEV) {
- INFO("Interface \"%s\" with index %d already "
- "deleted or existing in different network "
- "namespace",
- netdev->name ? netdev->name : "(null)",
- netdev->ifindex);
- } else if (ret < 0) {
- deleted_all = false;
- WARN("Failed to remove interface \"%s\" with "
- "index %d: %s",
- netdev->name ? netdev->name : "(null)",
- netdev->ifindex, strerror(-ret));
- continue;
- }
- INFO("Removed interface \"%s\" with index %d",
- netdev->name ? netdev->name : "(null)",
- netdev->ifindex);
- }
-
- if (netdev->type != LXC_NET_VETH)
- continue;
-
- if (am_unpriv()) {
- if (is_ovs_bridge(netdev->link)) {
- ret = lxc_unpriv_delete_nic(handler->lxcpath,
- handler->name,
- netdev, getpid());
- if (ret < 0)
- WARN("Failed to remove port \"%s\" "
- "from openvswitch bridge \"%s\"",
- netdev->priv.veth_attr.pair,
- netdev->link);
- }
-
- continue;
- }
-
- /* Explicitly delete host veth device to prevent lingering
- * devices. We had issues in LXD around this.
- */
- if (netdev->priv.veth_attr.pair)
- hostveth = netdev->priv.veth_attr.pair;
- else
- hostveth = netdev->priv.veth_attr.veth1;
- if (*hostveth == '\0')
- continue;
-
- ret = lxc_netdev_delete_by_name(hostveth);
- if (ret < 0) {
- deleted_all = false;
- WARN("Failed to remove interface \"%s\" from \"%s\": %s",
- hostveth, netdev->link, strerror(-ret));
- continue;
- }
- INFO("Removed interface \"%s\" from \"%s\"", hostveth, netdev->link);
-
- if (!is_ovs_bridge(netdev->link)) {
- netdev->priv.veth_attr.veth1[0] = '\0';
- continue;
- }
-
- /* Delete the openvswitch port. */
- ret = lxc_ovs_delete_port(netdev->link, hostveth);
- if (ret < 0)
- WARN("Failed to remove port \"%s\" from openvswitch "
- "bridge \"%s\"", hostveth, netdev->link);
- else
- INFO("Removed port \"%s\" from openvswitch bridge \"%s\"",
- hostveth, netdev->link);
-
- netdev->priv.veth_attr.veth1[0] = '\0';
- }
-
- return deleted_all;
-}
-
-#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
-static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
- struct lxc_netdev *netdev, pid_t pid)
-{
- int ret;
- pid_t child;
- int bytes, pipefd[2];
- char *token, *saveptr = NULL;
- char netdev_link[IFNAMSIZ + 1];
- char buffer[MAXPATHLEN] = {0};
-
- if (netdev->type != LXC_NET_VETH) {
- ERROR("nic type %d not support for unprivileged use",
- netdev->type);
- return -1;
- }
-
- if (pipe(pipefd) < 0) {
- SYSERROR("pipe failed");
- return -1;
- }
-
- child = fork();
- if (child < 0) {
- SYSERROR("fork");
- close(pipefd[0]);
- close(pipefd[1]);
- return -1;
- }
-
- if (child == 0) { // child
- /* Call lxc-user-nic pid type bridge. */
- int ret;
- char pidstr[LXC_NUMSTRLEN64];
-
- close(pipefd[0]); /* Close the read-end of the pipe. */
-
- /* Redirect stdout to write-end of the pipe. */
- ret = dup2(pipefd[1], STDOUT_FILENO);
- if (ret >= 0)
- ret = dup2(pipefd[1], STDERR_FILENO);
- close(pipefd[1]); /* Close the write-end of the pipe. */
- if (ret < 0) {
- SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
- exit(EXIT_FAILURE);
- }
-
- if (netdev->link)
- strncpy(netdev_link, netdev->link, IFNAMSIZ);
- else
- strncpy(netdev_link, "none", IFNAMSIZ);
-
- ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
- if (ret < 0 || ret >= LXC_NUMSTRLEN64)
- exit(EXIT_FAILURE);
- pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
-
- INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath,
- lxcname, pidstr, netdev_link,
- netdev->name ? netdev->name : "(null)");
- if (netdev->name)
- execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
- lxcpath, lxcname, pidstr, "veth", netdev_link,
- netdev->name, (char *)NULL);
- else
- execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
- lxcpath, lxcname, pidstr, "veth", netdev_link,
- (char *)NULL);
- SYSERROR("Failed to exec lxc-user-nic.");
- exit(EXIT_FAILURE);
- }
-
- /* close the write-end of the pipe */
- close(pipefd[1]);
-
- bytes = read(pipefd[0], &buffer, MAXPATHLEN);
- if (bytes < 0) {
- SYSERROR("Failed to read from pipe file descriptor.");
- close(pipefd[0]);
- return -1;
- }
- buffer[bytes - 1] = '\0';
-
- if (wait_for_pid(child) != 0) {
- ERROR("lxc-user-nic failed to configure requested network: %s",
- buffer[0] != '\0' ? buffer : "(null)");
- close(pipefd[0]);
- return -1;
- }
- TRACE("Received output \"%s\" from lxc-user-nic", buffer);
-
- /* close the read-end of the pipe */
- close(pipefd[0]);
-
- /* fill netdev->name field */
- token = strtok_r(buffer, ":", &saveptr);
- if (!token)
- return -1;
-
- netdev->name = malloc(IFNAMSIZ + 1);
- if (!netdev->name) {
- SYSERROR("Failed to allocate memory.");
- return -1;
- }
- memset(netdev->name, 0, IFNAMSIZ + 1);
- strncpy(netdev->name, token, IFNAMSIZ);
-
- /* fill netdev->veth_attr.pair field */
- token = strtok_r(NULL, ":", &saveptr);
- if (!token)
- return -1;
-
- netdev->priv.veth_attr.pair = strdup(token);
- if (!netdev->priv.veth_attr.pair) {
- ERROR("Failed to allocate memory.");
- return -1;
- }
-
- /* fill netdev->veth_attr.pair field */
- token = strtok_r(NULL, ":", &saveptr);
- if (!token)
- return -1;
-
- ret = lxc_safe_int(token, &netdev->ifindex);
- if (ret < 0) {
- ERROR("Failed to parse ifindex for network device \"%s\"", netdev->name);
- return -1;
- }
-
- return 0;
-}
-
-int lxc_assign_network(const char *lxcpath, char *lxcname,
- struct lxc_list *network, pid_t pid)
-{
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
- char ifname[IFNAMSIZ];
- int am_root = (getuid() == 0);
- int err;
-
- lxc_list_for_each(iterator, network) {
-
- netdev = iterator->elem;
-
- if (netdev->type == LXC_NET_VETH && !am_root) {
- if (netdev->mtu)
- INFO("mtu ignored due to insufficient privilege");
- 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.
- // netdev->ifindex will be filed in at setup_netdev.
- continue;
- }
-
- /* empty network namespace, nothing to move */
- if (!netdev->ifindex)
- continue;
-
- /* retrieve the name of the interface */
- if (!if_indextoname(netdev->ifindex, ifname)) {
- ERROR("no interface corresponding to index '%d'", netdev->ifindex);
- return -1;
- }
-
- err = lxc_netdev_move_by_name(ifname, pid, NULL);
- if (err) {
- ERROR("failed to move '%s' to the container : %s",
- netdev->link, strerror(-err));
- return -1;
- }
-
- DEBUG("move '%s'/'%s' to '%d': .", ifname, netdev->name, pid);
- }
-
- return 0;
-}
-
static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
size_t buf_size)
{
return freeid;
}
-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;
-
- if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
- continue;
-
- if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
- ERROR("gateway = auto only supported for "
- "veth and macvlan");
- return -1;
- }
-
- if (!netdev->link) {
- ERROR("gateway = auto needs a link interface");
- return -1;
- }
-
- link_index = if_nametoindex(netdev->link);
- if (!link_index)
- return -EINVAL;
-
- if (netdev->ipv4_gateway_auto) {
- if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
- ERROR("failed to automatically find ipv4 gateway "
- "address from link interface '%s'", netdev->link);
- return -1;
- }
- }
-
- if (netdev->ipv6_gateway_auto) {
- if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
- ERROR("failed to automatically find ipv6 gateway "
- "address from link interface '%s'", netdev->link);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
int lxc_create_tty(const char *name, struct lxc_conf *conf)
{
struct lxc_tty_info *tty_info = &conf->tty_info;
}
}
- if (setup_network(&lxc_conf->network)) {
+ if (lxc_setup_network_in_child_namespaces(lxc_conf, &lxc_conf->network)) {
ERROR("failed to setup the network for '%s'", name);
return -1;
}
return 0;
}
-
int lxc_clear_mount_entries(struct lxc_conf *c)
{
struct lxc_list *it,*next;
return result;
}
-
-int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname,
- struct lxc_netdev *netdev, pid_t pid)
-{
- pid_t child;
- int bytes, pipefd[2];
- char buffer[MAXPATHLEN] = {0};
-
- if (netdev->type != LXC_NET_VETH) {
- ERROR("nic type %d not support for unprivileged use",
- netdev->type);
- return -1;
- }
-
- if (pipe(pipefd) < 0) {
- SYSERROR("pipe failed");
- return -1;
- }
-
- child = fork();
- if (child < 0) {
- SYSERROR("fork");
- close(pipefd[0]);
- close(pipefd[1]);
- return -1;
- }
-
- if (child == 0) { /* child */
- /* Call lxc-user-nic pid type bridge. */
- int ret;
- char pidstr[LXC_NUMSTRLEN64];
-
- close(pipefd[0]); /* Close the read-end of the pipe. */
-
- /* Redirect stdout to write-end of the pipe. */
- ret = dup2(pipefd[1], STDOUT_FILENO);
- if (ret >= 0)
- ret = dup2(pipefd[1], STDERR_FILENO);
- close(pipefd[1]); /* Close the write-end of the pipe. */
- if (ret < 0) {
- SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
- exit(EXIT_FAILURE);
- }
-
- if (!netdev->link)
- SYSERROR("Network link for network device \"%s\" is "
- "missing", netdev->priv.veth_attr.pair);
-
- ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
- if (ret < 0 || ret >= LXC_NUMSTRLEN64)
- exit(EXIT_FAILURE);
- pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
-
- INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath,
- lxcname, pidstr, netdev->link, netdev->priv.veth_attr.pair);
- execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "delete", lxcpath,
- lxcname, pidstr, "veth", netdev->link,
- netdev->priv.veth_attr.pair, (char *)NULL);
- SYSERROR("Failed to exec lxc-user-nic.");
- exit(EXIT_FAILURE);
- }
-
- /* close the write-end of the pipe */
- close(pipefd[1]);
-
- bytes = read(pipefd[0], &buffer, MAXPATHLEN);
- if (bytes < 0) {
- SYSERROR("Failed to read from pipe file descriptor.");
- close(pipefd[0]);
- return -1;
- }
- buffer[bytes - 1] = '\0';
-
- if (wait_for_pid(child) != 0) {
- ERROR("lxc-user-nic failed to delete requested network: %s",
- buffer[0] != '\0' ? buffer : "(null)");
- close(pipefd[0]);
- return -1;
- }
- TRACE("Received output \"%s\" from lxc-user-nic", buffer);
-
- /* close the read-end of the pipe */
- close(pipefd[0]);
-
- return 0;
-}
#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.network.link, name of bridge or host iface to attach if any
- * @name : lxc.network.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.
* @lsm_se_context : selinux type to switch to or NULL
*/
enum lxchooks {
- LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV,
- LXCHOOK_START, LXCHOOK_STOP, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, LXCHOOK_DESTROY,
- NUM_LXC_HOOKS};
-extern char *lxchook_names[NUM_LXC_HOOKS];
-
-struct saved_nic {
- int ifindex;
- char *orig_name;
+ LXCHOOK_PRESTART,
+ LXCHOOK_PREMOUNT,
+ LXCHOOK_MOUNT,
+ LXCHOOK_AUTODEV,
+ LXCHOOK_START,
+ LXCHOOK_STOP,
+ LXCHOOK_POSTSTOP,
+ LXCHOOK_CLONE,
+ LXCHOOK_DESTROY,
+ NUM_LXC_HOOKS
};
+extern char *lxchook_names[NUM_LXC_HOOKS];
+
struct lxc_conf {
int is_execute;
char *fstab;
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_create_network(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);
struct cgroup_process_info;
extern int lxc_setup(struct lxc_handler *handler);
-
-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);
extern int chown_mapped_root(char *path, struct lxc_conf *conf);
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 lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname,
- struct lxc_netdev *netdev, pid_t pid);
+extern int run_script(const char *name, const char *section, const char *script,
+ ...);
#endif /* __LXC_CONF_H */
#include "error.h"
#include "log.h"
#include "list.h"
+#include "network.h"
+#include "parse.h"
#include "utils.h"
lxc_log_define(lxc_confile_utils, lxc);
* 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>
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "config.h"
-
+#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include "conf.h"
+#include "config.h"
+#include "confile_utils.h"
#include "log.h"
#include "network.h"
#include "nl.h"
lxc_log_define(lxc_network, lxc);
-int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname)
+typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
+
+static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ int bridge_index, err;
+ char *veth1, *veth2;
+ char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
+ unsigned int mtu = 0;
+
+ if (netdev->priv.veth_attr.pair) {
+ veth1 = netdev->priv.veth_attr.pair;
+ if (handler->conf->reboot)
+ lxc_netdev_delete_by_name(veth1);
+ } else {
+ err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
+ if (err < 0 || (size_t)err >= sizeof(veth1buf))
+ return -1;
+
+ veth1 = lxc_mkifname(veth1buf);
+ if (!veth1)
+ return -1;
+
+ /* store away for deconf */
+ memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
+ }
+
+ snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
+ veth2 = lxc_mkifname(veth2buf);
+ if (!veth2)
+ goto out_delete;
+
+ err = lxc_veth_create(veth1, veth2);
+ if (err) {
+ ERROR("Failed to create veth pair \"%s\" and \"%s\": %s", veth1,
+ veth2, strerror(-err));
+ goto out_delete;
+ }
+
+ /* changing the high byte of the mac address to 0xfe, the bridge interface
+ * will always keep the host's mac address and not take the mac address
+ * of a container */
+ err = setup_private_host_hw_addr(veth1);
+ if (err) {
+ ERROR("Failed to change mac address of host interface \"%s\": %s",
+ veth1, strerror(-err));
+ goto out_delete;
+ }
+
+ netdev->ifindex = if_nametoindex(veth2);
+ if (!netdev->ifindex) {
+ ERROR("Failed to retrieve ifindex for \"%s\"", veth2);
+ goto out_delete;
+ }
+
+ if (netdev->mtu) {
+ if (lxc_safe_uint(netdev->mtu, &mtu) < 0)
+ WARN("Failed to parse mtu");
+ else
+ INFO("Retrieved mtu %d", mtu);
+ } else if (netdev->link) {
+ bridge_index = if_nametoindex(netdev->link);
+ if (bridge_index) {
+ mtu = netdev_get_mtu(bridge_index);
+ INFO("Retrieved mtu %d from %s", mtu, netdev->link);
+ } else {
+ mtu = netdev_get_mtu(netdev->ifindex);
+ INFO("Retrieved mtu %d from %s", mtu, veth2);
+ }
+ }
+
+ if (mtu) {
+ err = lxc_netdev_set_mtu(veth1, mtu);
+ if (!err)
+ err = lxc_netdev_set_mtu(veth2, mtu);
+ if (err) {
+ ERROR("Failed to set mtu \"%d\" for veth pair \"%s\" "
+ "and \"%s\": %s",
+ mtu, veth1, veth2, strerror(-err));
+ goto out_delete;
+ }
+ }
+
+ if (netdev->link) {
+ err = lxc_bridge_attach(netdev->link, veth1);
+ if (err) {
+ ERROR("Failed to attach \"%s\" to bridge \"%s\": %s",
+ veth1, netdev->link, strerror(-err));
+ goto out_delete;
+ }
+ INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
+ }
+
+ err = lxc_netdev_up(veth1);
+ if (err) {
+ ERROR("Failed to set \"%s\" up: %s", veth1, strerror(-err));
+ goto out_delete;
+ }
+
+ if (netdev->upscript) {
+ err = run_script(handler->name, "net", netdev->upscript, "up",
+ "veth", veth1, (char*) NULL);
+ if (err)
+ goto out_delete;
+ }
+
+ DEBUG("Instantiated veth \"%s/%s\", index is \"%d\"", veth1, veth2,
+ netdev->ifindex);
+
+ return 0;
+
+out_delete:
+ if (netdev->ifindex != 0)
+ lxc_netdev_delete_by_name(veth1);
+ if (!netdev->priv.veth_attr.pair)
+ free(veth1);
+ free(veth2);
+ return -1;
+}
+
+static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ char peerbuf[IFNAMSIZ], *peer;
+ int err;
+
+ if (!netdev->link) {
+ ERROR("No link for macvlan network device specified");
+ return -1;
+ }
+
+ err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
+ if (err < 0 || (size_t)err >= sizeof(peerbuf))
+ return -1;
+
+ peer = lxc_mkifname(peerbuf);
+ if (!peer)
+ return -1;
+
+ err = lxc_macvlan_create(netdev->link, peer,
+ netdev->priv.macvlan_attr.mode);
+ if (err) {
+ ERROR("Failed to create macvlan interface \"%s\" on \"%s\": %s",
+ peer, netdev->link, strerror(-err));
+ goto out;
+ }
+
+ netdev->ifindex = if_nametoindex(peer);
+ if (!netdev->ifindex) {
+ ERROR("Failed to retrieve ifindex for \"%s\"", peer);
+ goto out;
+ }
+
+ if (netdev->upscript) {
+ err = run_script(handler->name, "net", netdev->upscript, "up",
+ "macvlan", netdev->link, (char*) NULL);
+ if (err)
+ goto out;
+ }
+
+ DEBUG("Instantiated macvlan \"%s\" with ifindex is %d and mode %d",
+ peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
+
+ return 0;
+out:
+ lxc_netdev_delete_by_name(peer);
+ free(peer);
+ return -1;
+}
+
+static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ char peer[IFNAMSIZ];
+ int err;
+ static uint16_t vlan_cntr = 0;
+ unsigned int mtu = 0;
+
+ if (!netdev->link) {
+ ERROR("No link for vlan network device specified");
+ return -1;
+ }
+
+ err = snprintf(peer, sizeof(peer), "vlan%d-%d", netdev->priv.vlan_attr.vid, vlan_cntr++);
+ if (err < 0 || (size_t)err >= sizeof(peer))
+ return -1;
+
+ err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
+ if (err) {
+ ERROR("Failed to create vlan interface \"%s\" on \"%s\": %s",
+ peer, netdev->link, strerror(-err));
+ return -1;
+ }
+
+ netdev->ifindex = if_nametoindex(peer);
+ if (!netdev->ifindex) {
+ ERROR("Failed to retrieve ifindex for \"%s\"", peer);
+ lxc_netdev_delete_by_name(peer);
+ return -1;
+ }
+
+ DEBUG("Instantiated vlan \"%s\" with ifindex is \"%d\" (vlan1000)",
+ peer, netdev->ifindex);
+ if (netdev->mtu) {
+ if (lxc_safe_uint(netdev->mtu, &mtu) < 0) {
+ ERROR("Failed to retrieve mtu from \"%d\"/\"%s\".",
+ netdev->ifindex,
+ netdev->name ? netdev->name : "(null)");
+ return -1;
+ }
+ err = lxc_netdev_set_mtu(peer, mtu);
+ if (err) {
+ ERROR("Failed to set mtu \"%s\" for \"%s\": %s",
+ netdev->mtu, peer, strerror(-err));
+ lxc_netdev_delete_by_name(peer);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ if (!netdev->link) {
+ ERROR("No link for physical interface specified");
+ return -1;
+ }
+
+ netdev->ifindex = if_nametoindex(netdev->link);
+ if (!netdev->ifindex) {
+ ERROR("Failed to retrieve ifindex for \"%s\"", netdev->link);
+ return -1;
+ }
+
+ if (netdev->upscript) {
+ int err;
+ err = run_script(handler->name, "net", netdev->upscript,
+ "up", "phys", netdev->link, (char*) NULL);
+ if (err)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ netdev->ifindex = 0;
+ if (netdev->upscript) {
+ int err;
+ err = run_script(handler->name, "net", netdev->upscript,
+ "up", "empty", (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
+static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ netdev->ifindex = 0;
+ return 0;
+}
+
+static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
+ [LXC_NET_VETH] = instantiate_veth,
+ [LXC_NET_MACVLAN] = instantiate_macvlan,
+ [LXC_NET_VLAN] = instantiate_vlan,
+ [LXC_NET_PHYS] = instantiate_phys,
+ [LXC_NET_EMPTY] = instantiate_empty,
+ [LXC_NET_NONE] = instantiate_none,
+};
+
+static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ char *veth1;
+ int err;
+
+ if (netdev->priv.veth_attr.pair)
+ veth1 = netdev->priv.veth_attr.pair;
+ else
+ veth1 = netdev->priv.veth_attr.veth1;
+
+ if (netdev->downscript) {
+ err = run_script(handler->name, "net", netdev->downscript,
+ "down", "veth", veth1, (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
+static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ int err;
+
+ if (netdev->downscript) {
+ err = run_script(handler->name, "net", netdev->downscript,
+ "down", "macvlan", netdev->link,
+ (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
+static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ return 0;
+}
+
+static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ int err;
+
+ if (netdev->downscript) {
+ err = run_script(handler->name, "net", netdev->downscript,
+ "down", "phys", netdev->link, (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
+static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ int err;
+
+ if (netdev->downscript) {
+ err = run_script(handler->name, "net", netdev->downscript,
+ "down", "empty", (char*) NULL);
+ if (err)
+ return -1;
+ }
+ return 0;
+}
+
+static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+ return 0;
+}
+
+static instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
+ [LXC_NET_VETH] = shutdown_veth,
+ [LXC_NET_MACVLAN] = shutdown_macvlan,
+ [LXC_NET_VLAN] = shutdown_vlan,
+ [LXC_NET_PHYS] = shutdown_phys,
+ [LXC_NET_EMPTY] = shutdown_empty,
+ [LXC_NET_NONE] = shutdown_none,
+};
+
+int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char *ifname)
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL;
static const char padchar[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-char *lxc_mkifname(char *template)
+char *lxc_mkifname(const char *template)
{
char *name = NULL;
size_t i = 0;
return 0;
}
+
+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;
+
+ if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
+ continue;
+
+ if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
+ ERROR("Automatic gateway detection is only supported "
+ "for veth and macvlan");
+ return -1;
+ }
+
+ if (!netdev->link) {
+ ERROR("Automatic gateway detection needs a link interface");
+ return -1;
+ }
+
+ link_index = if_nametoindex(netdev->link);
+ if (!link_index)
+ return -EINVAL;
+
+ if (netdev->ipv4_gateway_auto) {
+ if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
+ ERROR("Failed to automatically find ipv4 gateway "
+ "address from link interface \"%s\"", netdev->link);
+ return -1;
+ }
+ }
+
+ if (netdev->ipv6_gateway_auto) {
+ if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
+ ERROR("Failed to automatically find ipv6 gateway "
+ "address from link interface \"%s\"", netdev->link);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
+static int lxc_create_network_unpriv(const char *lxcpath, char *lxcname,
+ struct lxc_netdev *netdev, pid_t pid)
+{
+ int ret;
+ pid_t child;
+ int bytes, pipefd[2];
+ char *token, *saveptr = NULL;
+ char netdev_link[IFNAMSIZ + 1];
+ char buffer[MAXPATHLEN] = {0};
+
+ if (netdev->type != LXC_NET_VETH) {
+ ERROR("Network type %d not support for unprivileged use", netdev->type);
+ return -1;
+ }
+
+ ret = pipe(pipefd);
+ if (ret < 0) {
+ SYSERROR("Failed to create pipe");
+ return -1;
+ }
+
+ child = fork();
+ if (child < 0) {
+ SYSERROR("Failed to create new process");
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return -1;
+ }
+
+ if (child == 0) {
+ int ret;
+ char pidstr[LXC_NUMSTRLEN64];
+
+ close(pipefd[0]);
+
+ ret = dup2(pipefd[1], STDOUT_FILENO);
+ if (ret >= 0)
+ ret = dup2(pipefd[1], STDERR_FILENO);
+ close(pipefd[1]);
+ if (ret < 0) {
+ SYSERROR("Failed to duplicate std{err,out} file descriptor");
+ exit(EXIT_FAILURE);
+ }
+
+ if (netdev->link)
+ strncpy(netdev_link, netdev->link, IFNAMSIZ);
+ else
+ strncpy(netdev_link, "none", IFNAMSIZ);
+
+ ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
+ if (ret < 0 || ret >= LXC_NUMSTRLEN64)
+ exit(EXIT_FAILURE);
+ pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
+
+ INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath,
+ lxcname, pidstr, netdev_link,
+ netdev->name ? netdev->name : "(null)");
+ if (netdev->name)
+ execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
+ lxcpath, lxcname, pidstr, "veth", netdev_link,
+ netdev->name, (char *)NULL);
+ else
+ execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
+ lxcpath, lxcname, pidstr, "veth", netdev_link,
+ (char *)NULL);
+ SYSERROR("Failed to execute lxc-user-nic");
+ exit(EXIT_FAILURE);
+ }
+
+ /* close the write-end of the pipe */
+ close(pipefd[1]);
+
+ bytes = read(pipefd[0], &buffer, MAXPATHLEN);
+ if (bytes < 0) {
+ SYSERROR("Failed to read from pipe file descriptor.");
+ close(pipefd[0]);
+ return -1;
+ }
+ buffer[bytes - 1] = '\0';
+
+ ret = wait_for_pid(child);
+ close(pipefd[0]);
+ if (ret != 0) {
+ ERROR("lxc-user-nic failed to configure requested network: %s",
+ buffer[0] != '\0' ? buffer : "(null)");
+ return -1;
+ }
+ TRACE("Received output \"%s\" from lxc-user-nic", buffer);
+
+ /* netdev->name */
+ token = strtok_r(buffer, ":", &saveptr);
+ if (!token)
+ return -1;
+
+ netdev->name = malloc(IFNAMSIZ + 1);
+ if (!netdev->name) {
+ SYSERROR("Failed to allocate memory.");
+ return -1;
+ }
+ memset(netdev->name, 0, IFNAMSIZ + 1);
+ strncpy(netdev->name, token, IFNAMSIZ);
+
+ /* netdev->priv.veth_attr.pair */
+ token = strtok_r(NULL, ":", &saveptr);
+ if (!token)
+ return -1;
+
+ netdev->priv.veth_attr.pair = strdup(token);
+ if (!netdev->priv.veth_attr.pair) {
+ ERROR("Failed to allocate memory.");
+ return -1;
+ }
+
+ /* netdev->ifindex */
+ token = strtok_r(NULL, ":", &saveptr);
+ if (!token)
+ return -1;
+
+ ret = lxc_safe_int(token, &netdev->ifindex);
+ if (ret < 0) {
+ ERROR("Failed to parse ifindex for network device \"%s\"", netdev->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int lxc_delete_network_unpriv(const char *lxcpath, char *lxcname,
+ struct lxc_netdev *netdev, pid_t pid)
+{
+ int bytes, ret;
+ pid_t child;
+ int pipefd[2];
+ char buffer[MAXPATHLEN] = {0};
+
+ if (netdev->type != LXC_NET_VETH) {
+ ERROR("Network type %d not support for unprivileged use", netdev->type);
+ return -1;
+ }
+
+ ret = pipe(pipefd);
+ if (ret < 0) {
+ SYSERROR("Failed to create pipe");
+ return -1;
+ }
+
+ child = fork();
+ if (child < 0) {
+ SYSERROR("Failed to create new process");
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return -1;
+ }
+
+ if (child == 0) {
+ int ret;
+ char pidstr[LXC_NUMSTRLEN64];
+
+ close(pipefd[0]);
+
+ ret = dup2(pipefd[1], STDOUT_FILENO);
+ if (ret >= 0)
+ ret = dup2(pipefd[1], STDERR_FILENO);
+ close(pipefd[1]);
+ if (ret < 0) {
+ SYSERROR("Failed to duplicate std{err,out} file descriptor");
+ exit(EXIT_FAILURE);
+ }
+
+ if (!netdev->link)
+ SYSERROR("Network link for network device \"%s\" is "
+ "missing", netdev->priv.veth_attr.pair);
+
+ ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
+ if (ret < 0 || ret >= LXC_NUMSTRLEN64)
+ exit(EXIT_FAILURE);
+ pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
+
+ INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath,
+ lxcname, pidstr, netdev->link, netdev->priv.veth_attr.pair);
+ execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "delete", lxcpath,
+ lxcname, pidstr, "veth", netdev->link,
+ netdev->priv.veth_attr.pair, (char *)NULL);
+ SYSERROR("Failed to exec lxc-user-nic.");
+ exit(EXIT_FAILURE);
+ }
+
+ close(pipefd[1]);
+
+ bytes = read(pipefd[0], &buffer, MAXPATHLEN);
+ if (bytes < 0) {
+ SYSERROR("Failed to read from pipe file descriptor.");
+ close(pipefd[0]);
+ return -1;
+ }
+ buffer[bytes - 1] = '\0';
+
+ if (wait_for_pid(child) != 0) {
+ ERROR("lxc-user-nic failed to delete requested network: %s",
+ buffer[0] != '\0' ? buffer : "(null)");
+ close(pipefd[0]);
+ return -1;
+ }
+
+ close(pipefd[0]);
+
+ return 0;
+}
+
+int lxc_create_network_priv(struct lxc_handler *handler)
+{
+ bool am_root;
+ struct lxc_list *iterator;
+ struct lxc_list *network = &handler->conf->network;
+
+ /* We need to be root. */
+ am_root = (getuid() == 0);
+ if (!am_root)
+ return 0;
+
+ lxc_list_for_each(iterator, network) {
+ struct lxc_netdev *netdev = iterator->elem;
+
+ if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
+ ERROR("Invalid network configuration type %d", netdev->type);
+ return -1;
+ }
+
+ if (netdev_conf[netdev->type](handler, netdev)) {
+ ERROR("Failed to create network device");
+ return -1;
+ }
+
+ }
+
+ return 0;
+}
+
+int lxc_create_network(const char *lxcpath, char *lxcname,
+ struct lxc_list *network, pid_t pid)
+{
+ int err;
+ bool am_root;
+ char ifname[IFNAMSIZ];
+ struct lxc_list *iterator;
+
+ am_root = (getuid() == 0);
+
+ lxc_list_for_each(iterator, network) {
+ struct lxc_netdev *netdev = iterator->elem;
+
+ if (netdev->type == LXC_NET_VETH && !am_root) {
+ if (netdev->mtu)
+ INFO("mtu ignored due to insufficient privilege");
+ if (lxc_create_network_unpriv(lxcpath, lxcname, netdev, pid))
+ return -1;
+ /* lxc-user-nic has moved the nic to the new ns.
+ * unpriv_assign_nic() fills in netdev->name.
+ * netdev->ifindex will be filled in at
+ * lxc_setup_netdev_in_child_namespaces().
+ */
+ continue;
+ }
+
+ /* empty network namespace, nothing to move */
+ if (!netdev->ifindex)
+ continue;
+
+ /* retrieve the name of the interface */
+ if (!if_indextoname(netdev->ifindex, ifname)) {
+ ERROR("No interface corresponding to ifindex \"%d\"",
+ netdev->ifindex);
+ return -1;
+ }
+
+ err = lxc_netdev_move_by_name(ifname, pid, NULL);
+ if (err) {
+ ERROR("Failed to move network device \"%s\" to "
+ "network namespace %d: %s", ifname, pid,
+ strerror(-err));
+ return -1;
+ }
+
+ DEBUG("Moved network device \"%s\"/\"%s\" to network namespace "
+ "of %d:", ifname, netdev->name ? netdev->name : "(null)",
+ pid);
+ }
+
+ return 0;
+}
+
+bool lxc_delete_network(struct lxc_handler *handler)
+{
+ int ret;
+ struct lxc_list *iterator;
+ struct lxc_list *network = &handler->conf->network;
+ bool deleted_all = true;
+
+ lxc_list_for_each(iterator, network) {
+ 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.
+ */
+ if (!netdev->ifindex)
+ continue;
+
+ if (netdev->type == LXC_NET_PHYS) {
+ ret = lxc_netdev_rename_by_index(netdev->ifindex, netdev->link);
+ if (ret < 0)
+ WARN("Failed to rename interface with index %d "
+ "to its initial name \"%s\"",
+ netdev->ifindex, netdev->link);
+ else
+ TRACE("Renamed interface with index %d to its "
+ "initial name \"%s\"",
+ netdev->ifindex, netdev->link);
+ continue;
+ }
+
+ ret = netdev_deconf[netdev->type](handler, netdev);
+ if (ret < 0)
+ WARN("Failed to deconfigure network device");
+
+ /* Recent kernels remove the virtual interfaces when the network
+ * namespace is destroyed but in case we did not move the
+ * interface to the network namespace, we have to destroy it.
+ */
+ if (!am_unpriv()) {
+ ret = lxc_netdev_delete_by_index(netdev->ifindex);
+ if (-ret == ENODEV) {
+ INFO("Interface \"%s\" with index %d already "
+ "deleted or existing in different network "
+ "namespace",
+ netdev->name ? netdev->name : "(null)",
+ netdev->ifindex);
+ } else if (ret < 0) {
+ deleted_all = false;
+ WARN("Failed to remove interface \"%s\" with "
+ "index %d: %s",
+ netdev->name ? netdev->name : "(null)",
+ netdev->ifindex, strerror(-ret));
+ continue;
+ }
+ INFO("Removed interface \"%s\" with index %d",
+ netdev->name ? netdev->name : "(null)",
+ netdev->ifindex);
+ }
+
+ if (netdev->type != LXC_NET_VETH)
+ continue;
+
+ if (am_unpriv()) {
+ if (is_ovs_bridge(netdev->link)) {
+ ret = lxc_delete_network_unpriv(handler->lxcpath,
+ handler->name,
+ netdev, getpid());
+ if (ret < 0)
+ WARN("Failed to remove port \"%s\" "
+ "from openvswitch bridge \"%s\"",
+ netdev->priv.veth_attr.pair,
+ netdev->link);
+ }
+
+ continue;
+ }
+
+ /* Explicitly delete host veth device to prevent lingering
+ * devices. We had issues in LXD around this.
+ */
+ if (netdev->priv.veth_attr.pair)
+ hostveth = netdev->priv.veth_attr.pair;
+ else
+ hostveth = netdev->priv.veth_attr.veth1;
+ if (*hostveth == '\0')
+ continue;
+
+ ret = lxc_netdev_delete_by_name(hostveth);
+ if (ret < 0) {
+ deleted_all = false;
+ WARN("Failed to remove interface \"%s\" from \"%s\": %s",
+ hostveth, netdev->link, strerror(-ret));
+ continue;
+ }
+ INFO("Removed interface \"%s\" from \"%s\"", hostveth, netdev->link);
+
+ if (!is_ovs_bridge(netdev->link)) {
+ netdev->priv.veth_attr.veth1[0] = '\0';
+ continue;
+ }
+
+ /* Delete the openvswitch port. */
+ ret = lxc_ovs_delete_port(netdev->link, hostveth);
+ if (ret < 0)
+ WARN("Failed to remove port \"%s\" from openvswitch "
+ "bridge \"%s\"", hostveth, netdev->link);
+ else
+ INFO("Removed port \"%s\" from openvswitch bridge \"%s\"",
+ hostveth, netdev->link);
+
+ netdev->priv.veth_attr.veth1[0] = '\0';
+ }
+
+ return deleted_all;
+}
+
+int lxc_requests_empty_network(struct lxc_handler *handler)
+{
+ struct lxc_list *network = &handler->conf->network;
+ struct lxc_list *iterator;
+ bool found_none = false, found_nic = false;
+
+ if (lxc_list_empty(network))
+ return 0;
+
+ lxc_list_for_each(iterator, network) {
+ struct lxc_netdev *netdev = iterator->elem;
+
+ if (netdev->type == LXC_NET_NONE)
+ found_none = true;
+ else
+ found_nic = true;
+ }
+ if (found_none && !found_nic)
+ return 1;
+ return 0;
+}
+
+/* try to move physical nics to the init netns */
+void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
+{
+ int ret;
+ int i, oldfd;
+ char ifname[IFNAMSIZ];
+
+ if (netnsfd < 0 || conf->num_savednics == 0)
+ return;
+
+ INFO("Trying to restore network device names in original namespace for "
+ "%d network devices", conf->num_savednics);
+
+ oldfd = lxc_preserve_ns(getpid(), "net");
+ if (oldfd < 0) {
+ SYSERROR("Failed to preserve network namespace");
+ return;
+ }
+
+ ret = setns(netnsfd, 0);
+ if (ret < 0) {
+ SYSERROR("Failed to enter network namespace");
+ close(oldfd);
+ return;
+ }
+
+ for (i = 0; i < conf->num_savednics; i++) {
+ struct saved_nic *s = &conf->saved_nics[i];
+
+ /* retrieve the name of the interface */
+ if (!if_indextoname(s->ifindex, ifname)) {
+ WARN("No interface corresponding to ifindex %d",
+ s->ifindex);
+ continue;
+ }
+ if (lxc_netdev_move_by_name(ifname, 1, s->orig_name))
+ WARN("Error moving network device \"%s\" back to "
+ "network namespace", ifname);
+ free(s->orig_name);
+ }
+ conf->num_savednics = 0;
+
+ ret = setns(oldfd, 0);
+ if (ret < 0)
+ SYSERROR("Failed to enter network namespace");
+ close(oldfd);
+}
+
+static int setup_hw_addr(char *hwaddr, const char *ifname)
+{
+ struct sockaddr sockaddr;
+ struct ifreq ifr;
+ int ret, fd, saved_errno;
+
+ ret = lxc_convert_mac(hwaddr, &sockaddr);
+ if (ret) {
+ ERROR("Mac address \"%s\" conversion failed: %s", hwaddr,
+ strerror(-ret));
+ return -1;
+ }
+
+ memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = '\0';
+ memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return -1;
+
+ ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
+ saved_errno = errno;
+ close(fd);
+ if (ret)
+ ERROR("Failed to perform ioctl: %s", strerror(saved_errno));
+
+ DEBUG("Mac address \"%s\" on \"%s\" has been setup", hwaddr,
+ ifr.ifr_name);
+
+ return ret;
+}
+
+static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
+{
+ struct lxc_list *iterator;
+ int err;
+
+ lxc_list_for_each(iterator, ip) {
+ struct lxc_inetdev *inetdev = iterator->elem;
+
+ err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
+ &inetdev->bcast, inetdev->prefix);
+ if (err) {
+ ERROR("Failed to setup ipv4 address for network device "
+ "with eifindex %d: %s", ifindex, strerror(-err));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
+{
+ struct lxc_list *iterator;
+ int err;
+
+ lxc_list_for_each(iterator, ip) {
+ struct lxc_inet6dev *inet6dev = iterator->elem;
+
+ err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
+ &inet6dev->mcast, &inet6dev->acast,
+ inet6dev->prefix);
+ if (err) {
+ ERROR("Failed to setup ipv6 address for network device "
+ "with eifindex %d: %s", ifindex, strerror(-err));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
+{
+ char ifname[IFNAMSIZ];
+ int err;
+ const char *net_type_name;
+ char *current_ifname = ifname;
+
+ /* empty network namespace */
+ if (!netdev->ifindex) {
+ if (netdev->flags & IFF_UP) {
+ err = lxc_netdev_up("lo");
+ if (err) {
+ ERROR("Failed to set the loopback network "
+ "device up: %s",
+ strerror(-err));
+ return -1;
+ }
+ }
+
+ if (netdev->type == LXC_NET_EMPTY)
+ return 0;
+
+ if (netdev->type == LXC_NET_NONE)
+ return 0;
+
+ if (netdev->type != LXC_NET_VETH) {
+ net_type_name = lxc_net_type_to_str(netdev->type);
+ ERROR("%s networks are not supported for containers "
+ "not setup up by privileged users",
+ net_type_name);
+ return -1;
+ }
+
+ netdev->ifindex = if_nametoindex(netdev->name);
+ }
+
+ /* get the new ifindex in case of physical netdev */
+ if (netdev->type == LXC_NET_PHYS) {
+ netdev->ifindex = if_nametoindex(netdev->link);
+ if (!netdev->ifindex) {
+ ERROR("Failed to get ifindex for network device \"%s\"",
+ netdev->link);
+ return -1;
+ }
+ }
+
+ /* retrieve the name of the interface */
+ if (!if_indextoname(netdev->ifindex, current_ifname)) {
+ ERROR("Failed get name for network device with ifindex %d",
+ netdev->ifindex);
+ return -1;
+ }
+
+ /* Default: let the system to choose one interface name.
+ * When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
+ * netlink will replace the format specifier with an appropriate index.
+ */
+ if (!netdev->name)
+ netdev->name = netdev->type == LXC_NET_PHYS ?
+ netdev->link : "eth%d";
+
+ /* rename the interface name */
+ if (strcmp(ifname, netdev->name) != 0) {
+ err = lxc_netdev_rename_by_name(ifname, netdev->name);
+ if (err) {
+ ERROR("Failed to rename network device \"%s\" to "
+ "\"%s\": %s", ifname, netdev->name, strerror(-err));
+ return -1;
+ }
+ }
+
+ /* Re-read the name of the interface because its name has changed
+ * and would be automatically allocated by the system
+ */
+ if (!if_indextoname(netdev->ifindex, current_ifname)) {
+ ERROR("Failed get name for network device with ifindex %d",
+ netdev->ifindex);
+ return -1;
+ }
+
+ /* set a mac address */
+ if (netdev->hwaddr) {
+ if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
+ ERROR("Failed to setup hw address for network device \"%s\"",
+ current_ifname);
+ return -1;
+ }
+ }
+
+ /* setup ipv4 addresses on the interface */
+ if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
+ ERROR("Failed to setup ip addresses for network device \"%s\"",
+ ifname);
+ return -1;
+ }
+
+ /* setup ipv6 addresses on the interface */
+ if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
+ ERROR("Failed to setup ipv6 addresses for network device \"%s\"",
+ ifname);
+ return -1;
+ }
+
+ /* set the network device up */
+ if (netdev->flags & IFF_UP) {
+ int err;
+
+ err = lxc_netdev_up(current_ifname);
+ if (err) {
+ ERROR("Failed to set network device \"%s\" up: %s",
+ current_ifname, strerror(-err));
+ return -1;
+ }
+
+ /* the network is up, make the loopback up too */
+ err = lxc_netdev_up("lo");
+ if (err) {
+ ERROR("Failed to set the loopback network device up: %s",
+ strerror(-err));
+ return -1;
+ }
+ }
+
+ /* We can only set up the default routes after bringing
+ * up the interface, sine bringing up the interface adds
+ * the link-local routes and we can't add a default
+ * route if the gateway is not reachable. */
+
+ /* setup ipv4 gateway on the interface */
+ if (netdev->ipv4_gateway) {
+ if (!(netdev->flags & IFF_UP)) {
+ ERROR("Cannot add ipv4 gateway for network device "
+ "\"%s\" when not bringing up the interface", ifname);
+ return -1;
+ }
+
+ if (lxc_list_empty(&netdev->ipv4)) {
+ ERROR("Cannot add ipv4 gateway for network device "
+ "\"%s\" when not assigning an address", ifname);
+ return -1;
+ }
+
+ err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
+ if (err) {
+ err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
+ if (err) {
+ ERROR("Failed to add ipv4 dest for network "
+ "device \"%s\": %s", ifname, strerror(-err));
+ }
+
+ err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
+ if (err) {
+ ERROR("Failed to setup ipv4 gateway for "
+ "network device \"%s\": %s",
+ ifname, strerror(-err));
+ if (netdev->ipv4_gateway_auto) {
+ char buf[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
+ ERROR("Fried to set autodetected ipv4 gateway \"%s\"", buf);
+ }
+ return -1;
+ }
+ }
+ }
+
+ /* setup ipv6 gateway on the interface */
+ if (netdev->ipv6_gateway) {
+ if (!(netdev->flags & IFF_UP)) {
+ ERROR("Cannot add ipv6 gateway for network device "
+ "\"%s\" when not bringing up the interface", ifname);
+ return -1;
+ }
+
+ if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
+ ERROR("Cannot add ipv6 gateway for network device "
+ "\"%s\" when not assigning an address", ifname);
+ return -1;
+ }
+
+ err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
+ if (err) {
+ err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
+ if (err) {
+ ERROR("Failed to add ipv6 dest for network "
+ "device \"%s\": %s", ifname, strerror(-err));
+ }
+
+ err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
+ if (err) {
+ ERROR("Failed to setup ipv6 gateway for "
+ "network device \"%s\": %s", ifname,
+ strerror(-err));
+ if (netdev->ipv6_gateway_auto) {
+ char buf[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
+ ERROR("Tried to set autodetected ipv6 "
+ "gateway for network device "
+ "\"%s\"", buf);
+ }
+ return -1;
+ }
+ }
+ }
+
+ DEBUG("Network devie \"%s\" has been setup", current_ifname);
+
+ return 0;
+}
+
+int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf,
+ struct lxc_list *network)
+{
+ struct lxc_list *iterator;
+ struct lxc_netdev *netdev;
+
+ lxc_log_configured_netdevs(conf);
+
+ lxc_list_for_each(iterator, network) {
+ netdev = iterator->elem;
+
+ /* REMOVE in LXC 3.0 */
+ if (netdev->idx < 0) {
+ ERROR("WARNING: using \"lxc.network.*\" keys to define "
+ "networks is DEPRECATED, please switch to using "
+ "\"lxc.net.[i].* keys\"");
+ }
+
+ if (lxc_setup_netdev_in_child_namespaces(netdev)) {
+ ERROR("failed to setup netdev");
+ return -1;
+ }
+ }
+
+ if (!lxc_list_empty(network))
+ INFO("network has been setup");
+
+ return 0;
+}
#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;
+};
+
/*
- * Convert a string mac address to a socket structure
+ * 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);
/*
*/
extern int lxc_neigh_proxy_off(const char *name, int family);
-/*
- * Generate a new unique network interface name
+/* Generate a new unique network interface name.
+ * Allocated memory must be freed by caller.
*/
-extern char *lxc_mkifname(char *template);
+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);
-#endif
+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 */
#include "mainloop.h"
#include "monitor.h"
#include "namespace.h"
+#include "network.h"
#include "start.h"
#include "storage.h"
#include "storage_utils.h"
/* That should be done before the clone because we will
* fill the netdev index and use them in the child.
*/
- if (lxc_create_network(handler)) {
+ if (lxc_create_network_priv(handler)) {
ERROR("Failed to create the network.");
lxc_sync_fini(handler);
return -1;
/* 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;