mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-14 20:42:50 +00:00
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:
parent
0104c121a7
commit
8bf64b77ac
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user