return 0;
}
-static int link_configure_after_setting_mtu(Link *link);
+static int link_configure_continue(Link *link);
static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
log_link_debug(link, "Setting MTU done.");
if (link->state == LINK_STATE_INITIALIZED) {
- r = link_configure_after_setting_mtu(link);
+ r = link_configure_continue(link);
if (r < 0)
link_enter_failed(link);
}
log_link_debug(link, "Starting IPv6 Router Advertisements");
+ r = radv_emit_dns(link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to configure DNS or Domains in IPv6 Router Advertisement: %m");
+
r = sd_radv_start(link->radv);
if (r < 0 && r != -EBUSY)
return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m");
assert(link);
+ link->setting_genmode = false;
+
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0)
log_link_message_warning_errno(link, m, r, "Could not set address genmode for interface, ignoring");
+ else
+ log_link_debug(link, "Setting address genmode done.");
+
+ if (link->state == LINK_STATE_INITIALIZED) {
+ r = link_configure_continue(link);
+ if (r < 0)
+ link_enter_failed(link);
+ }
return 1;
}
assert(link->manager);
assert(link->manager->rtnl);
- if (!socket_ipv6_is_supported())
+ if (!socket_ipv6_is_supported() || link->setting_genmode)
return 0;
log_link_debug(link, "Setting address genmode for link");
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
+ link->setting_genmode = true;
return 0;
}
if (strv_isempty(carrier->network->bind_carrier))
continue;
- if (strv_fnmatch(carrier->network->bind_carrier, link->ifname, 0)) {
+ if (strv_fnmatch(carrier->network->bind_carrier, link->ifname)) {
r = link_put_carrier(link, carrier, &link->bound_by_links);
if (r < 0)
return r;
m = link->manager;
HASHMAP_FOREACH (carrier, m->links, i) {
- if (strv_fnmatch(link->network->bind_carrier, carrier->ifname, 0)) {
+ if (strv_fnmatch(link->network->bind_carrier, carrier->ifname)) {
r = link_put_carrier(link, carrier, &link->bound_to_links);
if (r < 0)
return r;
return false;
}
+static int link_enumerate_ipv6_tentative_addresses(Link *link) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ sd_netlink_message *addr;
+ int r;
+
+ assert(link);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+
+ r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_GETADDR, 0, AF_INET6);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(link->manager->rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
+ unsigned char flags;
+ int ifindex;
+
+ r = sd_rtnl_message_addr_get_ifindex(addr, &ifindex);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: invalid ifindex, ignoring: %m");
+ continue;
+ } else if (link->ifindex != ifindex)
+ continue;
+
+ r = sd_rtnl_message_addr_get_flags(addr, &flags);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address message with invalid flags, ignoring: %m");
+ continue;
+ } else if (!(flags & IFA_F_TENTATIVE))
+ continue;
+
+ log_link_debug(link, "Found tentative ipv6 link-local address");
+ (void) manager_rtnl_process_address(link->manager->rtnl, addr, link->manager);
+ }
+
+ return 0;
+}
+
static int link_drop_foreign_config(Link *link) {
Address *address;
Neighbor *neighbor;
Iterator i;
int r;
+ /* The kernel doesn't notify us about tentative addresses;
+ * so if ipv6ll is disabled, we need to enumerate them now so we can drop them below */
+ if (!link_ipv6ll_enabled(link)) {
+ r = link_enumerate_ipv6_tentative_addresses(link);
+ if (r < 0)
+ return r;
+ }
+
SET_FOREACH(address, link->addresses_foreign, i) {
/* we consider IPv6LL addresses to be managed by the kernel */
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
if (link->iftype == ARPHRD_CAN)
return link_configure_can(link);
- /* Drop foreign config, but ignore loopback or critical devices.
- * We do not want to remove loopback address or addresses used for root NFS. */
- if (!(link->flags & IFF_LOOPBACK) &&
- link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
- r = link_drop_foreign_config(link);
- if (r < 0)
- return r;
- }
-
/* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
* for this interface, then enable IPv6 */
(void) link_update_ipv6_sysctl(link);
if (r < 0)
return r;
- return link_configure_after_setting_mtu(link);
+ return link_configure_continue(link);
}
-static int link_configure_after_setting_mtu(Link *link) {
+/* The configuration continues in this separate function, instead of
+ * including this in the above link_configure() function, for two
+ * reasons:
+ * 1) some devices reset the link when the mtu is set, which caused
+ * an infinite loop here in networkd; see:
+ * https://github.com/systemd/systemd/issues/6593
+ * https://github.com/systemd/systemd/issues/9831
+ * 2) if ipv6ll is disabled, then bringing the interface up must be
+ * delayed until after we get confirmation from the kernel that
+ * the addr_gen_mode parameter has been set (via netlink), see:
+ * https://github.com/systemd/systemd/issues/13882
+ */
+static int link_configure_continue(Link *link) {
int r;
assert(link);
assert(link->network);
assert(link->state == LINK_STATE_INITIALIZED);
- if (link->setting_mtu)
+ if (link->setting_mtu || link->setting_genmode)
return 0;
+ /* Drop foreign config, but ignore loopback or critical devices.
+ * We do not want to remove loopback address or addresses used for root NFS. */
+ if (!(link->flags & IFF_LOOPBACK) &&
+ link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
+ r = link_drop_foreign_config(link);
+ if (r < 0)
+ return r;
+ }
+
/* The kernel resets ipv6 mtu after changing device mtu;
* we must set this here, after we've set device mtu */
r = link_set_ipv6_mtu(link);
Network *network;
int r;
- if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_LINGER))
- return 0;
-
if (m) {
_cleanup_strv_free_ char **s = NULL;
return r;
link_set_state(link, LINK_STATE_INITIALIZED);
+ link_dirty(link);
/* link_configure_duid() returns 0 if it requests product UUID. In that case,
* link_configure() is called later asynchronously. */
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
+ if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_LINGER))
+ return 0;
+
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK,
link->ifindex);
if (r < 0)