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 <christian.brauner@ubuntu.com>
This commit is contained in:
Christian Brauner 2020-01-10 12:30:02 +01:00
parent 0104c121a7
commit 8bf64b77ac
No known key found for this signature in database
GPG Key ID: 8EB056D53EECB12D

View File

@ -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 "<prefix>%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;
}