From 8bf64b77ac8a6f7d447709cdb6c6ad768f2302c1 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 10 Jan 2020 12:30:02 +0100 Subject: [PATCH] network: rework network device creation This makes all the codepaths easier to follow and also moves and renames devices in one single step. Signed-off-by: Christian Brauner --- src/lxc/network.c | 229 +++++++++++++++++++++++++++------------------- 1 file changed, 133 insertions(+), 96 deletions(-) diff --git a/src/lxc/network.c b/src/lxc/network.c index 5618caea8..c8f44dd80 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -47,6 +47,7 @@ lxc_log_define(network, lxc); typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *); +typedef int (*instantiate_ns_cb)(struct lxc_netdev *); static const char loop_device[] = "lo"; static int lxc_ip_route_dest(__u16 nlmsg_type, int family, int ifindex, void *dest, unsigned int netmask) @@ -501,6 +502,8 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n } strlcpy(netdev->created_name, peer, IFNAMSIZ); + if (netdev->name[0] == '\0') + (void)strlcpy(netdev->name, peer, IFNAMSIZ); netdev->ifindex = if_nametoindex(peer); if (!netdev->ifindex) { @@ -663,6 +666,8 @@ static int instantiate_ipvlan(struct lxc_handler *handler, struct lxc_netdev *ne } strlcpy(netdev->created_name, peer, IFNAMSIZ); + if (netdev->name[0] == '\0') + (void)strlcpy(netdev->name, peer, IFNAMSIZ); netdev->ifindex = if_nametoindex(peer); if (!netdev->ifindex) { @@ -736,6 +741,8 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd } strlcpy(netdev->created_name, peer, IFNAMSIZ); + if (netdev->name[0] == '\0') + (void)strlcpy(netdev->name, peer, IFNAMSIZ); netdev->ifindex = if_nametoindex(peer); if (!netdev->ifindex) { @@ -809,6 +816,8 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd } strlcpy(netdev->created_name, netdev->link, IFNAMSIZ); + if (netdev->name[0] == '\0') + (void)strlcpy(netdev->name, netdev->link, IFNAMSIZ); /* * Store the ifindex of the host's network device in the host's @@ -903,6 +912,102 @@ static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = { [LXC_NET_NONE] = instantiate_none, }; +static int instantiate_ns_veth(struct lxc_netdev *netdev) +{ + char current_ifname[IFNAMSIZ]; + + netdev->ifindex = if_nametoindex(netdev->created_name); + if (!netdev->ifindex) + return log_error_errno(-1, + errno, "Failed to retrieve ifindex for network device with name %s", + netdev->created_name); + + if (netdev->name[0] == '\0') + (void)strlcpy(netdev->name, "eth%d", IFNAMSIZ); + + if (strcmp(netdev->created_name, netdev->name) != 0) { + int ret; + + ret = lxc_netdev_rename_by_name(netdev->created_name, netdev->name); + if (ret) + return log_error_errno(-1, + -ret, "Failed to rename network device \"%s\" to \"%s\"", + netdev->created_name, + netdev->name); + + TRACE("Renamed network device from \"%s\" to \"%s\"", netdev->created_name, netdev->name); + } + + /* + * 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)) + return log_error_errno(-1, + errno, "Failed get name for network device with ifindex %d", + netdev->ifindex); + + /* + * Now update the recorded name of the network device to reflect the + * name of the network device in the child's network namespace. We will + * later on send this information back to the parent. + */ + (void)strlcpy(netdev->name, current_ifname, IFNAMSIZ); + + return 0; +} + +static int __instantiate_common(struct lxc_netdev *netdev) +{ + netdev->ifindex = if_nametoindex(netdev->name); + if (!netdev->ifindex) + return log_error_errno(-1, + errno, "Failed to retrieve ifindex for network device with name %s", + netdev->name); + + return 0; +} + +static int instantiate_ns_macvlan(struct lxc_netdev *netdev) +{ + return __instantiate_common(netdev); +} + +static int instantiate_ns_ipvlan(struct lxc_netdev *netdev) +{ + return __instantiate_common(netdev); +} + +static int instantiate_ns_vlan(struct lxc_netdev *netdev) +{ + return __instantiate_common(netdev); +} + +static int instantiate_ns_phys(struct lxc_netdev *netdev) +{ + return __instantiate_common(netdev); +} + +static int instantiate_ns_empty(struct lxc_netdev *netdev) +{ + return 0; +} + +static int instantiate_ns_none(struct lxc_netdev *netdev) +{ + return 0; +} + +static instantiate_ns_cb netdev_ns_conf[LXC_NET_MAXCONFTYPE + 1] = { + [LXC_NET_VETH] = instantiate_ns_veth, + [LXC_NET_MACVLAN] = instantiate_ns_macvlan, + [LXC_NET_IPVLAN] = instantiate_ns_ipvlan, + [LXC_NET_VLAN] = instantiate_ns_vlan, + [LXC_NET_PHYS] = instantiate_ns_phys, + [LXC_NET_EMPTY] = instantiate_ns_empty, + [LXC_NET_NONE] = instantiate_ns_none, +}; + static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) { int ret; @@ -3249,7 +3354,7 @@ int lxc_network_move_created_netdev_priv(struct lxc_handler *handler) if (physname) ret = lxc_netdev_move_wlan(physname, netdev->link, pid, NULL); else - ret = lxc_netdev_move_by_index(netdev->ifindex, pid, NULL); + ret = lxc_netdev_move_by_index(netdev->ifindex, pid, netdev->name); if (ret) { errno = -ret; SYSERROR("Failed to move network device \"%s\" with ifindex %d to network namespace %d", @@ -3585,98 +3690,26 @@ static int setup_ipv6_addr(struct lxc_list *ip, int ifindex) return 0; } -static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) +static int lxc_network_setup_in_child_namespaces_common(struct lxc_netdev *netdev) { - char ifname[IFNAMSIZ]; int err; - char *current_ifname = ifname; char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN]; /* empty network namespace */ - if (!netdev->ifindex) { - if (netdev->flags & IFF_UP) { - err = lxc_netdev_up("lo"); - if (err) { - errno = -err; - SYSERROR("Failed to set the loopback network device up"); - return -1; - } - } - - if (netdev->type == LXC_NET_EMPTY) - return 0; - - if (netdev->type == LXC_NET_NONE) - return 0; - - netdev->ifindex = if_nametoindex(netdev->created_name); - if (!netdev->ifindex) - SYSERROR("Failed to retrieve ifindex for network device with name %s", - netdev->created_name ?: "(null)"); - } - - /* 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)) { - SYSERROR("Failed to retrieve name for network device with ifindex %d", - netdev->ifindex); - return -1; - } - - /* Default: let the system choose an interface name. - * When the IFLA_IFNAME attribute is passed something like "%d" - * netlink will replace the format specifier with an appropriate index. - */ - if (netdev->name[0] == '\0') { - if (netdev->type == LXC_NET_PHYS) - (void)strlcpy(netdev->name, netdev->link, IFNAMSIZ); - else - (void)strlcpy(netdev->name, "eth%d", IFNAMSIZ); - } - - /* rename the interface name */ - if (strcmp(current_ifname, netdev->name) != 0) { - err = lxc_netdev_rename_by_name(current_ifname, netdev->name); + if (!netdev->ifindex && netdev->flags & IFF_UP) { + err = lxc_netdev_up("lo"); if (err) { errno = -err; - SYSERROR("Failed to rename network device \"%s\" to \"%s\"", - current_ifname, netdev->name); + SYSERROR( "Failed to set the loopback network device up"); return -1; } - - TRACE("Renamed network device from \"%s\" to \"%s\"", - current_ifname, netdev->name); - } - - /* 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; } - /* Now update the recorded name of the network device to reflect the - * name of the network device in the child's network namespace. We will - * later on send this information back to the parent. - */ - (void)strlcpy(netdev->name, current_ifname, IFNAMSIZ); - /* set a mac address */ if (netdev->hwaddr) { - if (setup_hw_addr(netdev->hwaddr, current_ifname)) { + if (setup_hw_addr(netdev->hwaddr, netdev->name)) { ERROR("Failed to setup hw address for network device \"%s\"", - current_ifname); + netdev->name); return -1; } } @@ -3684,24 +3717,24 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) /* setup ipv4 addresses on the interface */ if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) { ERROR("Failed to setup ip addresses for network device \"%s\"", - current_ifname); + netdev->name); 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\"", - current_ifname); + netdev->name); return -1; } /* set the network device up */ if (netdev->flags & IFF_UP) { - err = lxc_netdev_up(current_ifname); + err = lxc_netdev_up(netdev->name); if (err) { errno = -err; SYSERROR("Failed to set network device \"%s\" up", - current_ifname); + netdev->name); return -1; } @@ -3718,13 +3751,13 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) if (netdev->ipv4_gateway || netdev->ipv4_gateway_dev) { if (!(netdev->flags & IFF_UP)) { ERROR("Cannot add ipv4 gateway for network device " - "\"%s\" when not bringing up the interface", current_ifname); + "\"%s\" when not bringing up the interface", netdev->name); return -1; } if (lxc_list_empty(&netdev->ipv4)) { ERROR("Cannot add ipv4 gateway for network device " - "\"%s\" when not assigning an address", current_ifname); + "\"%s\" when not assigning an address", netdev->name); return -1; } @@ -3733,7 +3766,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) err = lxc_ipv4_gateway_add(netdev->ifindex, NULL); if (err < 0) { SYSERROR("Failed to setup ipv4 gateway to network device \"%s\"", - current_ifname); + netdev->name); return ret_set_errno(-1, -err); } } else { @@ -3753,7 +3786,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) if (err < 0) { errno = -err; SYSERROR("Failed to add ipv4 dest \"%s\" for network device \"%s\"", - bufinet4, current_ifname); + bufinet4, netdev->name); return -1; } @@ -3761,7 +3794,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) if (err < 0) { errno = -err; SYSERROR("Failed to setup ipv4 gateway \"%s\" for network device \"%s\"", - bufinet4, current_ifname); + bufinet4, netdev->name); return -1; } } @@ -3772,13 +3805,13 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) if (netdev->ipv6_gateway || netdev->ipv6_gateway_dev) { if (!(netdev->flags & IFF_UP)) { ERROR("Cannot add ipv6 gateway for network device \"%s\" when not bringing up the interface", - current_ifname); + netdev->name); 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", - current_ifname); + netdev->name); return -1; } @@ -3787,7 +3820,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) err = lxc_ipv6_gateway_add(netdev->ifindex, NULL); if (err < 0) { SYSERROR("Failed to setup ipv6 gateway to network device \"%s\"", - current_ifname); + netdev->name); return ret_set_errno(-1, -err); } } else { @@ -3807,7 +3840,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) if (err < 0) { errno = -err; SYSERROR("Failed to add ipv6 dest \"%s\" for network device \"%s\"", - bufinet6, current_ifname); + bufinet6, netdev->name); return -1; } @@ -3815,14 +3848,14 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev) if (err < 0) { errno = -err; SYSERROR("Failed to setup ipv6 gateway \"%s\" for network device \"%s\"", - bufinet6, current_ifname); + bufinet6, netdev->name); return -1; } } } } - DEBUG("Network device \"%s\" has been setup", current_ifname); + DEBUG("Network device \"%s\" has been setup", netdev->name); return 0; } @@ -3832,10 +3865,14 @@ int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf, { struct lxc_list *iterator; - lxc_list_for_each(iterator, network) { + lxc_list_for_each (iterator, network) { struct lxc_netdev *netdev = iterator->elem; + int ret; - if (lxc_setup_netdev_in_child_namespaces(netdev)) { + ret = netdev_ns_conf[netdev->type](netdev); + if (!ret) + ret = lxc_network_setup_in_child_namespaces_common(netdev); + if (ret) { ERROR("Failed to setup netdev"); return -1; } -- 2.39.5