network: use request queue to set IPv6LL address generation mode

This commit is contained in:
Yu Watanabe
2021-06-08 06:33:27 +09:00
parent cc4c8fb136
commit 8e00e24cc9
3 changed files with 78 additions and 93 deletions
+1 -93
View File
@@ -56,7 +56,6 @@
#include "stdio-util.h"
#include "string-table.h"
#include "strv.h"
#include "sysctl-util.h"
#include "tc.h"
#include "tmpfile-util.h"
#include "udev-util.h"
@@ -1026,97 +1025,6 @@ bool link_has_carrier(Link *link) {
return false;
}
static int link_address_genmode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0) {
log_link_message_warning_errno(link, m, r, "Could not set IPv6LL address generation mode, ignoring");
return 0;
}
log_link_debug(link, "IPv6LL address genaration mode set.");
r = link_drop_ipv6ll_addresses(link);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to drop IPv6LL address: %m");
link_enter_failed(link);
}
return 0;
}
static int link_configure_addrgen_mode(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
uint8_t ipv6ll_mode;
int r;
assert(link);
assert(link->network);
assert(link->manager);
assert(link->manager->rtnl);
if (!socket_ipv6_is_supported())
return 0;
log_link_debug(link, "Setting IPv6LL address generation mode for link");
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
r = sd_netlink_message_open_container(req, AF_INET6);
if (r < 0)
return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
if (!link_ipv6ll_enabled(link))
ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE;
else if (link->network->ipv6ll_address_gen_mode < 0) {
r = sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL);
if (r < 0) {
/* The file may not exist. And even if it exists, when stable_secret is unset,
* reading the file fails with ENOMEM when read_full_virtual_file(), which uses
* read() as the backend, and EIO when read_one_line_file() which uses fgetc(). */
log_link_debug_errno(link, r, "Failed to read sysctl property stable_secret, ignoring: %m");
ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
} else
ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
} else
ipv6ll_mode = link->network->ipv6ll_address_gen_mode;
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE attribute: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, link_address_genmode_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return 0;
}
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@@ -1879,7 +1787,7 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = link_configure_addrgen_mode(link);
r = link_request_to_set_addrgen_mode(link);
if (r < 0)
return r;
+75
View File
@@ -9,8 +9,10 @@
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "string-table.h"
#include "sysctl-util.h"
static const char *const set_link_operation_table[_SET_LINK_OPERATION_MAX] = {
[SET_LINK_ADDRESS_GENERATION_MODE] = "IPv6LL address generation mode",
[SET_LINK_FLAGS] = "link flags",
[SET_LINK_GROUP] = "interface group",
[SET_LINK_MAC] = "MAC address",
@@ -48,6 +50,22 @@ static int set_link_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Li
return 1;
}
static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
r = set_link_handler_internal(rtnl, m, link, SET_LINK_ADDRESS_GENERATION_MODE, true);
if (r <= 0)
return r;
r = link_drop_ipv6ll_addresses(link);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to drop IPv6LL addresses: %m");
link_enter_failed(link);
}
return 0;
}
static int link_set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_FLAGS, true);
}
@@ -105,6 +123,27 @@ static int link_configure(
return log_link_debug_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
switch (op) {
case SET_LINK_ADDRESS_GENERATION_MODE:
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
if (r < 0)
return log_link_debug_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
r = sd_netlink_message_open_container(req, AF_INET6);
if (r < 0)
return log_link_debug_errno(link, r, "Could not open AF_INET6 container: %m");
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, PTR_TO_UINT8(userdata));
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE attribute: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close AF_INET6 container: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
break;
case SET_LINK_FLAGS: {
unsigned ifi_change = 0, ifi_flags = 0;
@@ -221,6 +260,42 @@ static int link_request_set_link(
return 0;
}
int link_request_to_set_addrgen_mode(Link *link) {
Request *req;
uint8_t mode;
int r;
assert(link);
assert(link->network);
if (!socket_ipv6_is_supported())
return 0;
if (!link_ipv6ll_enabled(link))
mode = IN6_ADDR_GEN_MODE_NONE;
else if (link->network->ipv6ll_address_gen_mode >= 0)
mode = link->network->ipv6ll_address_gen_mode;
else {
r = sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL);
if (r < 0) {
/* The file may not exist. And even if it exists, when stable_secret is unset,
* reading the file fails with ENOMEM when read_full_virtual_file(), which uses
* read() as the backend, and EIO when read_one_line_file() which uses fgetc(). */
log_link_debug_errno(link, r, "Failed to read sysctl property stable_secret, ignoring: %m");
mode = IN6_ADDR_GEN_MODE_EUI64;
} else
mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
}
r = link_request_set_link(link, SET_LINK_ADDRESS_GENERATION_MODE, link_set_addrgen_mode_handler, &req);
if (r < 0)
return r;
req->userdata = UINT8_TO_PTR(mode);
return 0;
}
int link_request_to_set_flags(Link *link) {
assert(link);
assert(link->network);
+2
View File
@@ -7,6 +7,7 @@ typedef struct Link Link;
typedef struct Request Request;
typedef enum SetLinkOperation {
SET_LINK_ADDRESS_GENERATION_MODE, /* Setting IPv6LL address generation mode. */
SET_LINK_FLAGS, /* Setting IFF_NOARP or friends. */
SET_LINK_GROUP, /* Setting interface group. */
SET_LINK_MAC, /* Setting MAC address. */
@@ -15,6 +16,7 @@ typedef enum SetLinkOperation {
_SET_LINK_OPERATION_INVALID = -EINVAL,
} SetLinkOperation;
int link_request_to_set_addrgen_mode(Link *link);
int link_request_to_set_flags(Link *link);
int link_request_to_set_group(Link *link);
int link_request_to_set_mac(Link *link);