summaryrefslogtreecommitdiff
path: root/src/network/networkd-link.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/networkd-link.c')
-rw-r--r--src/network/networkd-link.c194
1 files changed, 129 insertions, 65 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 9d97089576..ec4b082542 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -130,6 +130,57 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
return link->network->ipv6_privacy_extensions;
}
+void link_update_operstate(Link *link) {
+ LinkOperationalState operstate;
+ assert(link);
+
+ if (link->kernel_operstate == IF_OPER_DORMANT)
+ operstate = LINK_OPERSTATE_DORMANT;
+ else if (link_has_carrier(link)) {
+ Address *address;
+ uint8_t scope = RT_SCOPE_NOWHERE;
+ Iterator i;
+
+ /* if we have carrier, check what addresses we have */
+ SET_FOREACH(address, link->addresses, i) {
+ if (!address_is_ready(address))
+ continue;
+
+ if (address->scope < scope)
+ scope = address->scope;
+ }
+
+ /* for operstate we also take foreign addresses into account */
+ SET_FOREACH(address, link->addresses_foreign, i) {
+ if (!address_is_ready(address))
+ continue;
+
+ if (address->scope < scope)
+ scope = address->scope;
+ }
+
+ if (scope < RT_SCOPE_SITE)
+ /* universally accessible addresses found */
+ operstate = LINK_OPERSTATE_ROUTABLE;
+ else if (scope < RT_SCOPE_HOST)
+ /* only link or site local addresses found */
+ operstate = LINK_OPERSTATE_DEGRADED;
+ else
+ /* no useful addresses found */
+ operstate = LINK_OPERSTATE_CARRIER;
+ } else if (link->flags & IFF_UP)
+ operstate = LINK_OPERSTATE_NO_CARRIER;
+ else
+ operstate = LINK_OPERSTATE_OFF;
+
+ if (link->operstate != operstate) {
+ link->operstate = operstate;
+ link_send_changed(link, "OperationalState", NULL);
+ link_dirty(link);
+ manager_dirty(link->manager);
+ }
+}
+
#define FLAG_STRING(string, flag, old, new) \
(((old ^ new) & flag) \
? ((old & flag) ? (" -" string) : (" +" string)) \
@@ -202,7 +253,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) {
link->flags = flags;
link->kernel_operstate = operstate;
- link_save(link);
+ link_update_operstate(link);
return 0;
}
@@ -297,6 +348,11 @@ static void link_free(Link *link) {
set_free(link->addresses);
+ while (!set_isempty(link->addresses_foreign))
+ address_free(set_first(link->addresses_foreign));
+
+ set_free(link->addresses_foreign);
+
while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address);
address_free(address);
@@ -321,6 +377,7 @@ static void link_free(Link *link) {
free(link->ifname);
+ (void)unlink(link->state_file);
free(link->state_file);
udev_device_unref(link->udev_device);
@@ -399,7 +456,7 @@ static void link_enter_unmanaged(Link *link) {
link_set_state(link, LINK_STATE_UNMANAGED);
- link_save(link);
+ link_dirty(link);
}
static int link_stop_clients(Link *link) {
@@ -457,7 +514,7 @@ void link_enter_failed(Link *link) {
link_stop_clients(link);
- link_save(link);
+ link_dirty(link);
}
static Address* link_find_dhcp_server_address(Link *link) {
@@ -498,14 +555,19 @@ static int link_enter_configured(Link *link) {
link_set_state(link, LINK_STATE_CONFIGURED);
- link_save(link);
+ link_dirty(link);
return 0;
}
-void link_client_handler(Link *link) {
+void link_check_ready(Link *link) {
+ Address *a;
+ Iterator i;
+
assert(link);
- assert(link->network);
+
+ if (!link->network)
+ return;
if (!link->static_configured)
return;
@@ -523,6 +585,10 @@ void link_client_handler(Link *link) {
!link->dhcp4_configured && !link->dhcp6_configured))
return;
+ SET_FOREACH(a, link->addresses, i)
+ if (!address_is_ready(a))
+ return;
+
if (link->state != LINK_STATE_CONFIGURED)
link_enter_configured(link);
@@ -550,7 +616,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
if (link->link_messages == 0) {
log_link_debug(link, "Routes set");
link->static_configured = true;
- link_client_handler(link);
+ link_check_ready(link);
}
return 1;
@@ -579,7 +645,7 @@ static int link_enter_set_routes(Link *link) {
if (link->link_messages == 0) {
link->static_configured = true;
- link_client_handler(link);
+ link_check_ready(link);
} else
log_link_debug(link, "Setting routes");
@@ -736,7 +802,7 @@ static int link_enter_set_addresses(Link *link) {
link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
- r = address_configure(ad, link, &address_handler);
+ r = address_configure(ad, link, &address_handler, false);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set addresses: %m");
link_enter_failed(link);
@@ -1446,14 +1512,14 @@ static int link_new_bound_by_list(Link *link) {
}
if (list_updated)
- link_save(link);
+ link_dirty(link);
HASHMAP_FOREACH (carrier, link->bound_by_links, i) {
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
if (r < 0)
return r;
- link_save(carrier);
+ link_dirty(carrier);
}
return 0;
@@ -1488,14 +1554,14 @@ static int link_new_bound_to_list(Link *link) {
}
if (list_updated)
- link_save(link);
+ link_dirty(link);
HASHMAP_FOREACH (carrier, link->bound_to_links, i) {
r = link_put_carrier(carrier, link, &carrier->bound_by_links);
if (r < 0)
return r;
- link_save(carrier);
+ link_dirty(carrier);
}
return 0;
@@ -1531,7 +1597,7 @@ static void link_free_bound_to_list(Link *link) {
hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex));
if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex)))
- link_save(bound_to);
+ link_dirty(bound_to);
}
return;
@@ -1545,7 +1611,7 @@ static void link_free_bound_by_list(Link *link) {
hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex));
if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) {
- link_save(bound_by);
+ link_dirty(bound_by);
link_handle_bound_to_list(bound_by);
}
}
@@ -1569,7 +1635,7 @@ static void link_free_carrier_maps(Link *link) {
}
if (list_updated)
- link_save(link);
+ link_dirty(link);
return;
}
@@ -1584,6 +1650,7 @@ void link_drop(Link *link) {
log_link_debug(link, "Link removed");
+ (void)unlink(link->state_file);
link_unref(link);
return;
@@ -1653,7 +1720,7 @@ static int link_enter_join_netdev(Link *link) {
link_set_state(link, LINK_STATE_ENSLAVING);
- link_save(link);
+ link_dirty(link);
if (!link->network->bridge &&
!link->network->bond &&
@@ -2297,50 +2364,12 @@ int link_update(Link *link, sd_netlink_message *m) {
return 0;
}
-static void link_update_operstate(Link *link) {
- LinkOperationalState operstate;
- assert(link);
-
- if (link->kernel_operstate == IF_OPER_DORMANT)
- operstate = LINK_OPERSTATE_DORMANT;
- else if (link_has_carrier(link)) {
- Address *address;
- uint8_t scope = RT_SCOPE_NOWHERE;
- Iterator i;
-
- /* if we have carrier, check what addresses we have */
- SET_FOREACH(address, link->addresses, i) {
- if (!address_is_ready(address))
- continue;
-
- if (address->scope < scope)
- scope = address->scope;
- }
-
- if (scope < RT_SCOPE_SITE)
- /* universally accessible addresses found */
- operstate = LINK_OPERSTATE_ROUTABLE;
- else if (scope < RT_SCOPE_HOST)
- /* only link or site local addresses found */
- operstate = LINK_OPERSTATE_DEGRADED;
- else
- /* no useful addresses found */
- operstate = LINK_OPERSTATE_CARRIER;
- } else if (link->flags & IFF_UP)
- operstate = LINK_OPERSTATE_NO_CARRIER;
- else
- operstate = LINK_OPERSTATE_OFF;
-
- if (link->operstate != operstate) {
- link->operstate = operstate;
- link_send_changed(link, "OperationalState", NULL);
- }
-}
-
int link_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *admin_state, *oper_state;
+ Address *a;
+ Iterator i;
int r;
assert(link);
@@ -2348,12 +2377,6 @@ int link_save(Link *link) {
assert(link->lease_file);
assert(link->manager);
- link_update_operstate(link);
-
- r = manager_save(link->manager);
- if (r < 0)
- return r;
-
if (link->state == LINK_STATE_LINGER) {
unlink(link->state_file);
return 0;
@@ -2518,11 +2541,25 @@ int link_save(Link *link) {
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->network->llmnr));
+
+ fprintf(f, "ADDRESSES=");
+ space = false;
+ SET_FOREACH(a, link->addresses, i) {
+ _cleanup_free_ char *address_str = NULL;
+
+ r = in_addr_to_string(a->family, &a->in_addr, &address_str);
+ if (r < 0)
+ goto fail;
+
+ fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
+ space = true;
+ }
+
+ fputs("\n", f);
}
if (!hashmap_isempty(link->bound_to_links)) {
Link *carrier;
- Iterator i;
bool space = false;
fputs("CARRIER_BOUND_TO=", f);
@@ -2538,7 +2575,6 @@ int link_save(Link *link) {
if (!hashmap_isempty(link->bound_by_links)) {
Link *carrier;
- Iterator i;
bool space = false;
fputs("CARRIER_BOUND_BY=", f);
@@ -2605,6 +2641,34 @@ fail:
return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
}
+/* The serialized state in /run is no longer up-to-date. */
+void link_dirty(Link *link) {
+ int r;
+
+ assert(link);
+
+ r = set_ensure_allocated(&link->manager->dirty_links, NULL);
+ if (r < 0)
+ /* allocation errors are ignored */
+ return;
+
+ r = set_put(link->manager->dirty_links, link);
+ if (r < 0)
+ /* allocation errors are ignored */
+ return;
+
+ link_ref(link);
+}
+
+/* The serialized state in /run is up-to-date */
+void link_clean(Link *link) {
+ assert(link);
+ assert(link->manager);
+
+ set_remove(link->manager->dirty_links, link);
+ link_unref(link);
+}
+
static const char* const link_state_table[_LINK_STATE_MAX] = {
[LINK_STATE_PENDING] = "pending",
[LINK_STATE_ENSLAVING] = "configuring",