network: improve veth device creation

This allows us to avoid having to move the network device. It also allows us to work around a kernel bug that in combination with a recent change in systemd 244 causes uses of systemd-networkd to not get an ip address. Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 90ddf3c0
...@@ -487,11 +487,11 @@ static char *find_line(char *buf_start, char *buf_end, char *name, ...@@ -487,11 +487,11 @@ static char *find_line(char *buf_start, char *buf_end, char *name,
return NULL; return NULL;
} }
static int instantiate_veth(char *veth1, char *veth2) static int instantiate_veth(char *veth1, char *veth2, pid_t pid, unsigned int mtu)
{ {
int ret; int ret;
ret = lxc_veth_create(veth1, veth2); ret = lxc_veth_create(veth1, veth2, pid, mtu);
if (ret < 0) { if (ret < 0) {
errno = -ret; errno = -ret;
CMD_SYSERROR("Failed to create %s-%s\n", veth1, veth2); CMD_SYSERROR("Failed to create %s-%s\n", veth1, veth2);
...@@ -524,8 +524,9 @@ static int get_mtu(char *name) ...@@ -524,8 +524,9 @@ static int get_mtu(char *name)
static int create_nic(char *nic, char *br, int pid, char **cnic) static int create_nic(char *nic, char *br, int pid, char **cnic)
{ {
unsigned int mtu = 1500;
int ret;
char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ]; char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
int mtu, ret;
ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic); ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
if (ret < 0 || ret >= IFNAMSIZ) { if (ret < 0 || ret >= IFNAMSIZ) {
...@@ -539,16 +540,19 @@ static int create_nic(char *nic, char *br, int pid, char **cnic) ...@@ -539,16 +540,19 @@ static int create_nic(char *nic, char *br, int pid, char **cnic)
return -1; return -1;
} }
if (strcmp(br, "none"))
mtu = get_mtu(br);
if (!mtu)
mtu = 1500;
/* create the nics */ /* create the nics */
ret = instantiate_veth(veth1buf, veth2buf); ret = instantiate_veth(veth1buf, veth2buf, pid, mtu);
if (ret < 0) { if (ret < 0) {
usernic_error("%s", "Error creating veth tunnel\n"); usernic_error("%s", "Error creating veth tunnel\n");
return -1; return -1;
} }
if (strcmp(br, "none")) { if (strcmp(br, "none")) {
/* copy the bridge's mtu to both ends */
mtu = get_mtu(br);
if (mtu > 0) { if (mtu > 0) {
ret = lxc_netdev_set_mtu(veth1buf, mtu); ret = lxc_netdev_set_mtu(veth1buf, mtu);
if (ret < 0) { if (ret < 0) {
...@@ -556,13 +560,6 @@ static int create_nic(char *nic, char *br, int pid, char **cnic) ...@@ -556,13 +560,6 @@ static int create_nic(char *nic, char *br, int pid, char **cnic)
mtu, veth1buf); mtu, veth1buf);
goto out_del; goto out_del;
} }
ret = lxc_netdev_set_mtu(veth2buf, mtu);
if (ret < 0) {
usernic_error("Failed to set mtu to %d on %s\n",
mtu, veth2buf);
goto out_del;
}
} }
/* attach veth1 to bridge */ /* attach veth1 to bridge */
...@@ -573,14 +570,6 @@ static int create_nic(char *nic, char *br, int pid, char **cnic) ...@@ -573,14 +570,6 @@ static int create_nic(char *nic, char *br, int pid, char **cnic)
} }
} }
/* pass veth2 to target netns */
ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
if (ret < 0) {
usernic_error("Error moving %s to network namespace of %d\n",
veth2buf, pid);
goto out_del;
}
*cnic = strdup(veth2buf); *cnic = strdup(veth2buf);
if (!*cnic) { if (!*cnic) {
usernic_error("Failed to copy string \"%s\"\n", veth2buf); usernic_error("Failed to copy string \"%s\"\n", veth2buf);
......
...@@ -271,10 +271,10 @@ static int lxc_is_ip_forwarding_enabled(const char *ifname, int family) ...@@ -271,10 +271,10 @@ static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
int bridge_index, err; int err;
unsigned int mtu;
char *veth1, *veth2; char *veth1, *veth2;
char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ]; char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
unsigned int mtu = 0;
if (netdev->priv.veth_attr.pair[0] != '\0') { if (netdev->priv.veth_attr.pair[0] != '\0') {
veth1 = netdev->priv.veth_attr.pair; veth1 = netdev->priv.veth_attr.pair;
...@@ -299,13 +299,25 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -299,13 +299,25 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
veth2 = lxc_mkifname(veth2buf); veth2 = lxc_mkifname(veth2buf);
if (!veth2) if (!veth2)
goto out_delete; return -1;
if (netdev->mtu && lxc_safe_uint(netdev->mtu, &mtu)) {
return log_error_errno(-1, errno, "Failed to parse mtu");
} else if (netdev->link[0] != '\0') {
int ifindex_mtu;
err = lxc_veth_create(veth1, veth2); ifindex_mtu = if_nametoindex(netdev->link);
if (ifindex_mtu) {
mtu = netdev_get_mtu(ifindex_mtu);
INFO("Retrieved mtu %d from %s", mtu, netdev->link);
}
}
err = lxc_veth_create(veth1, veth2, handler->pid, mtu);
if (err) { if (err) {
errno = -err; errno = -err;
SYSERROR("Failed to create veth pair \"%s\" and \"%s\"", veth1, veth2); SYSERROR("Failed to create veth pair \"%s\" and \"%s\"", veth1, veth2);
goto out_delete; return -1;
} }
strlcpy(netdev->created_name, veth2, IFNAMSIZ); strlcpy(netdev->created_name, veth2, IFNAMSIZ);
...@@ -327,42 +339,11 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -327,42 +339,11 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
goto out_delete; goto out_delete;
} }
/* Note that we're retrieving the container's ifindex in the host's
* network namespace because we need it to move the device from the
* host's network namespace to the container's network namespace later
* on.
*/
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[0] != '\0') {
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) { if (mtu) {
err = lxc_netdev_set_mtu(veth1, mtu); err = lxc_netdev_set_mtu(veth1, mtu);
if (!err)
err = lxc_netdev_set_mtu(veth2, mtu);
if (err) { if (err) {
errno = -err; errno = -err;
SYSERROR("Failed to set mtu \"%d\" for veth pair \"%s\" " SYSERROR("Failed to set mtu \"%d\" for veth pair \"%s\" ", mtu, veth1);
"and \"%s\"", mtu, veth1, veth2);
goto out_delete; goto out_delete;
} }
} }
...@@ -484,14 +465,12 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -484,14 +465,12 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
goto out_delete; goto out_delete;
} }
DEBUG("Instantiated veth \"%s/%s\", index is \"%d\"", veth1, veth2, DEBUG("Instantiated veth tunnel \"%s <--> %s\"", veth1, veth2);
netdev->ifindex);
return 0; return 0;
out_delete: out_delete:
if (netdev->ifindex != 0) lxc_netdev_delete_by_name(veth1);
lxc_netdev_delete_by_name(veth1);
return -1; return -1;
} }
...@@ -499,7 +478,6 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n ...@@ -499,7 +478,6 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
{ {
char peer[IFNAMSIZ]; char peer[IFNAMSIZ];
int err; int err;
unsigned int mtu = 0;
if (netdev->link[0] == '\0') { if (netdev->link[0] == '\0') {
ERROR("No link for macvlan network device specified"); ERROR("No link for macvlan network device specified");
...@@ -531,6 +509,8 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n ...@@ -531,6 +509,8 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
} }
if (netdev->mtu) { if (netdev->mtu) {
unsigned int mtu;
err = lxc_safe_uint(netdev->mtu, &mtu); err = lxc_safe_uint(netdev->mtu, &mtu);
if (err < 0) { if (err < 0) {
errno = -err; errno = -err;
...@@ -661,7 +641,6 @@ static int instantiate_ipvlan(struct lxc_handler *handler, struct lxc_netdev *ne ...@@ -661,7 +641,6 @@ static int instantiate_ipvlan(struct lxc_handler *handler, struct lxc_netdev *ne
{ {
char peer[IFNAMSIZ]; char peer[IFNAMSIZ];
int err; int err;
unsigned int mtu = 0;
if (netdev->link[0] == '\0') { if (netdev->link[0] == '\0') {
ERROR("No link for ipvlan network device specified"); ERROR("No link for ipvlan network device specified");
...@@ -692,19 +671,19 @@ static int instantiate_ipvlan(struct lxc_handler *handler, struct lxc_netdev *ne ...@@ -692,19 +671,19 @@ static int instantiate_ipvlan(struct lxc_handler *handler, struct lxc_netdev *ne
} }
if (netdev->mtu) { if (netdev->mtu) {
unsigned int mtu;
err = lxc_safe_uint(netdev->mtu, &mtu); err = lxc_safe_uint(netdev->mtu, &mtu);
if (err < 0) { if (err < 0) {
errno = -err; errno = -err;
SYSERROR("Failed to parse mtu \"%s\" for interface \"%s\"", SYSERROR("Failed to parse mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
netdev->mtu, peer);
goto on_error; goto on_error;
} }
err = lxc_netdev_set_mtu(peer, mtu); err = lxc_netdev_set_mtu(peer, mtu);
if (err < 0) { if (err < 0) {
errno = -err; errno = -err;
SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
netdev->mtu, peer);
goto on_error; goto on_error;
} }
} }
...@@ -737,7 +716,6 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -737,7 +716,6 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
char peer[IFNAMSIZ]; char peer[IFNAMSIZ];
int err; int err;
static uint16_t vlan_cntr = 0; static uint16_t vlan_cntr = 0;
unsigned int mtu = 0;
if (netdev->link[0] == '\0') { if (netdev->link[0] == '\0') {
ERROR("No link for vlan network device specified"); ERROR("No link for vlan network device specified");
...@@ -766,19 +744,19 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -766,19 +744,19 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
} }
if (netdev->mtu) { if (netdev->mtu) {
unsigned int mtu;
err = lxc_safe_uint(netdev->mtu, &mtu); err = lxc_safe_uint(netdev->mtu, &mtu);
if (err < 0) { if (err < 0) {
errno = -err; errno = -err;
SYSERROR("Failed to parse mtu \"%s\" for interface \"%s\"", SYSERROR("Failed to parse mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
netdev->mtu, peer);
goto on_error; goto on_error;
} }
err = lxc_netdev_set_mtu(peer, mtu); err = lxc_netdev_set_mtu(peer, mtu);
if (err) { if (err < 0) {
errno = -err; errno = -err;
SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
netdev->mtu, peer);
goto on_error; goto on_error;
} }
} }
...@@ -810,7 +788,6 @@ on_error: ...@@ -810,7 +788,6 @@ on_error:
static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
int err, mtu_orig = 0; int err, mtu_orig = 0;
unsigned int mtu = 0;
if (netdev->link[0] == '\0') { if (netdev->link[0] == '\0') {
ERROR("No link for physical interface specified"); ERROR("No link for physical interface specified");
...@@ -852,6 +829,8 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -852,6 +829,8 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
netdev->priv.phys_attr.mtu = mtu_orig; netdev->priv.phys_attr.mtu = mtu_orig;
if (netdev->mtu) { if (netdev->mtu) {
unsigned int mtu;
err = lxc_safe_uint(netdev->mtu, &mtu); err = lxc_safe_uint(netdev->mtu, &mtu);
if (err < 0) { if (err < 0) {
errno = -err; errno = -err;
...@@ -863,8 +842,7 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -863,8 +842,7 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
err = lxc_netdev_set_mtu(netdev->link, mtu); err = lxc_netdev_set_mtu(netdev->link, mtu);
if (err < 0) { if (err < 0) {
errno = -err; errno = -err;
SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", netdev->mtu, netdev->link);
netdev->mtu, netdev->link);
return -1; return -1;
} }
} }
...@@ -1642,7 +1620,7 @@ out: ...@@ -1642,7 +1620,7 @@ out:
int lxc_netdev_set_mtu(const char *name, int mtu) int lxc_netdev_set_mtu(const char *name, int mtu)
{ {
int err, index, len; int err, len;
struct ifinfomsg *ifi; struct ifinfomsg *ifi;
struct nl_handler nlh; struct nl_handler nlh;
struct nlmsg *answer = NULL, *nlmsg = NULL; struct nlmsg *answer = NULL, *nlmsg = NULL;
...@@ -1665,11 +1643,6 @@ int lxc_netdev_set_mtu(const char *name, int mtu) ...@@ -1665,11 +1643,6 @@ int lxc_netdev_set_mtu(const char *name, int mtu)
if (!answer) if (!answer)
goto out; goto out;
err = -EINVAL;
index = if_nametoindex(name);
if (!index)
goto out;
nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
...@@ -1679,7 +1652,9 @@ int lxc_netdev_set_mtu(const char *name, int mtu) ...@@ -1679,7 +1652,9 @@ int lxc_netdev_set_mtu(const char *name, int mtu)
goto out; goto out;
} }
ifi->ifi_family = AF_UNSPEC; ifi->ifi_family = AF_UNSPEC;
ifi->ifi_index = index;
if (nla_put_string(nlmsg, IFLA_IFNAME, name))
goto out;
if (nla_put_u32(nlmsg, IFLA_MTU, mtu)) if (nla_put_u32(nlmsg, IFLA_MTU, mtu))
goto out; goto out;
...@@ -1702,7 +1677,7 @@ int lxc_netdev_down(const char *name) ...@@ -1702,7 +1677,7 @@ int lxc_netdev_down(const char *name)
return netdev_set_flag(name, 0); return netdev_set_flag(name, 0);
} }
int lxc_veth_create(const char *name1, const char *name2) int lxc_veth_create(const char *name1, const char *name2, pid_t pid, unsigned int mtu)
{ {
int err, len; int err, len;
struct ifinfomsg *ifi; struct ifinfomsg *ifi;
...@@ -1766,6 +1741,12 @@ int lxc_veth_create(const char *name1, const char *name2) ...@@ -1766,6 +1741,12 @@ int lxc_veth_create(const char *name1, const char *name2)
if (nla_put_string(nlmsg, IFLA_IFNAME, name2)) if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
goto out; goto out;
if (mtu > 0 && nla_put_u32(nlmsg, IFLA_MTU, mtu))
goto out;
if (pid > 0 && nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
goto out;
nla_end_nested(nlmsg, nest3); nla_end_nested(nlmsg, nest3);
nla_end_nested(nlmsg, nest2); nla_end_nested(nlmsg, nest2);
nla_end_nested(nlmsg, nest1); nla_end_nested(nlmsg, nest1);
...@@ -3926,6 +3907,7 @@ int lxc_network_recv_from_parent(struct lxc_handler *handler) ...@@ -3926,6 +3907,7 @@ int lxc_network_recv_from_parent(struct lxc_handler *handler)
ret = lxc_recv_nointr(data_sock, netdev->created_name, IFNAMSIZ, 0); ret = lxc_recv_nointr(data_sock, netdev->created_name, IFNAMSIZ, 0);
if (ret < 0) if (ret < 0)
return -1; return -1;
TRACE("Received network device name \"%s\" from parent", netdev->created_name); TRACE("Received network device name \"%s\" from parent", netdev->created_name);
} }
......
...@@ -203,7 +203,8 @@ extern int lxc_netdev_down(const char *name); ...@@ -203,7 +203,8 @@ extern int lxc_netdev_down(const char *name);
extern int lxc_netdev_set_mtu(const char *name, int mtu); extern int lxc_netdev_set_mtu(const char *name, int mtu);
/* Create a virtual network devices. */ /* Create a virtual network devices. */
extern int lxc_veth_create(const char *name1, const char *name2); extern int lxc_veth_create(const char *name1, const char *name2, pid_t pid,
unsigned int mtu);
extern int lxc_macvlan_create(const char *master, const char *name, int mode); extern int lxc_macvlan_create(const char *master, const char *name, int mode);
extern int lxc_vlan_create(const char *master, const char *name, extern int lxc_vlan_create(const char *master, const char *name,
unsigned short vid); unsigned short vid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment