networkd: netdev - reduce chance of race when receiving netdev's ifindex
When creating a new link, the kernel will not inform us about the new ifindex in its ack. We have to listen for newly created devices and deduce the new ifindex by matching on the ifname. We used to do this by waiting for a new device from libudev, but that is asking for trouble, as udev will happily rename the device before handing it to us. Listen on rtnl instead, the chance of the name being changed before reaching us is much smaller (if not nil). Kernel patch in the works to make this unneccessary.
This commit is contained in:
parent
3815f36f05
commit
50add2909c
|
@ -96,7 +96,6 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) {
|
|||
Network *network;
|
||||
int r;
|
||||
uint64_t ifindex;
|
||||
NetdevKind kind;
|
||||
|
||||
assert(m);
|
||||
assert(device);
|
||||
|
@ -114,13 +113,6 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) {
|
|||
|
||||
*ret = link;
|
||||
|
||||
kind = netdev_kind_from_string(udev_device_get_devtype(device));
|
||||
if (kind != _NETDEV_KIND_INVALID) {
|
||||
r = netdev_set_link(m, kind, link);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = network_get(m, device, &network);
|
||||
if (r < 0)
|
||||
return r == -ENOENT ? 0 : r;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "networkd.h"
|
||||
#include "libudev-private.h"
|
||||
#include "udev-util.h"
|
||||
#include "rtnl-util.h"
|
||||
#include "mkdir.h"
|
||||
|
||||
const char* const network_dirs[] = {
|
||||
|
@ -244,15 +245,31 @@ int manager_udev_listen(Manager *m) {
|
|||
static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
Link *link;
|
||||
const char *name;
|
||||
uint64_t ifindex_64;
|
||||
int r, ifindex;
|
||||
|
||||
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
||||
if (r < 0) {
|
||||
if (r < 0 || ifindex <= 0) {
|
||||
log_debug("received RTM_NEWLINK message without valid ifindex");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = rtnl_message_link_get_ifname(message, &name);
|
||||
if (r < 0)
|
||||
log_debug("received RTM_NEWLINK message without valid IFLA_IFNAME");
|
||||
else {
|
||||
Netdev *netdev;
|
||||
|
||||
r = netdev_get(m, name, &netdev);
|
||||
if (r >= 0) {
|
||||
r = netdev_set_ifindex(netdev, ifindex);
|
||||
if (r < 0)
|
||||
log_debug("could not set ifindex of netdev '%s' to %d: %s",
|
||||
name, ifindex, strerror(-r));
|
||||
}
|
||||
}
|
||||
|
||||
ifindex_64 = ifindex;
|
||||
link = hashmap_get(m->links, &ifindex_64);
|
||||
if (!link) {
|
||||
|
|
|
@ -98,7 +98,7 @@ static int netdev_enslave_ready(Netdev *netdev, Link* link, sd_rtnl_message_hand
|
|||
return r;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->link->ifindex);
|
||||
r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
|
||||
if (r < 0) {
|
||||
log_error_netdev(netdev,
|
||||
"Could not append IFLA_MASTER attribute: %s",
|
||||
|
@ -140,7 +140,7 @@ static int netdev_enter_ready(Netdev *netdev) {
|
|||
|
||||
static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
|
||||
Netdev *netdev = userdata;
|
||||
int r;
|
||||
int r, ifindex;
|
||||
|
||||
assert(netdev->state != _NETDEV_STATE_INVALID);
|
||||
|
||||
|
@ -152,6 +152,14 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
|
|||
return 1;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
|
||||
if (r < 0)
|
||||
log_warning_netdev(netdev, "created netdev with unknown ifindex: %s", strerror(-r));
|
||||
else {
|
||||
log_info_netdev(netdev, "created netdev with ifindex %d", ifindex);
|
||||
netdev_set_ifindex(netdev, ifindex);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -288,21 +296,18 @@ int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callbac
|
|||
return 0;
|
||||
}
|
||||
|
||||
int netdev_set_link(Manager *m, NetdevKind kind, Link *link) {
|
||||
Netdev *netdev;
|
||||
int r;
|
||||
int netdev_set_ifindex(Netdev *netdev, int ifindex) {
|
||||
assert(netdev);
|
||||
assert(ifindex > 0);
|
||||
|
||||
r = netdev_get(m, link->ifname, &netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (netdev->ifindex > 0) {
|
||||
if (netdev->ifindex == ifindex)
|
||||
return 0;
|
||||
else
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (netdev->link && netdev->link != link)
|
||||
return -EEXIST;
|
||||
|
||||
if (netdev->kind != kind)
|
||||
return -EINVAL;
|
||||
|
||||
netdev->link = link;
|
||||
netdev->ifindex = ifindex;
|
||||
|
||||
netdev_enter_ready(netdev);
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ struct Netdev {
|
|||
|
||||
int vlanid;
|
||||
|
||||
Link *link;
|
||||
int ifindex;
|
||||
NetdevState state;
|
||||
|
||||
LIST_HEAD(netdev_enslave_callback, callbacks);
|
||||
|
@ -234,7 +234,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Netdev*, netdev_free);
|
|||
#define _cleanup_netdev_free_ _cleanup_(netdev_freep)
|
||||
|
||||
int netdev_get(Manager *manager, const char *name, Netdev **ret);
|
||||
int netdev_set_link(Manager *m, NetdevKind kind, Link *link);
|
||||
int netdev_set_ifindex(Netdev *netdev, int ifindex);
|
||||
int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t cb);
|
||||
|
||||
const char *netdev_kind_to_string(NetdevKind d) _const_;
|
||||
|
|
Loading…
Reference in New Issue