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.c291
1 files changed, 190 insertions, 101 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index e2851df31a..22392d70bc 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -517,8 +517,6 @@ static void link_detach_from_manager(Link *link) {
hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
set_remove(link->manager->links_requesting_uuid, link);
link_clean(link);
-
- link->manager = NULL;
}
static Link *link_free(Link *link) {
@@ -730,70 +728,16 @@ static void link_enter_configured(Link *link) {
link_dirty(link);
}
-void link_check_ready(Link *link) {
- Address *a;
- Iterator i;
-
- assert(link);
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return;
-
- if (!link->network)
- return;
-
- if (!link->addresses_configured)
- return;
-
- if (!link->neighbors_configured)
- return;
-
- if (!link->static_routes_configured)
- return;
-
- if (!link->routing_policy_rules_configured)
- return;
-
- if (link_ipv4ll_enabled(link))
- if (!link->ipv4ll_address ||
- !link->ipv4ll_route)
- return;
-
- if (!link->network->bridge) {
-
- if (link_ipv6ll_enabled(link))
- if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
- return;
-
- if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
- !link->dhcp4_configured) ||
- (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
- !link->dhcp6_configured) ||
- (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
- !link->dhcp4_configured && !link->dhcp6_configured))
- return;
-
- if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
- return;
- }
-
- SET_FOREACH(a, link->addresses, i)
- if (!address_is_ready(a))
- return;
-
- if (link->state != LINK_STATE_CONFIGURED)
- link_enter_configured(link);
-
- return;
-}
-
-static int link_set_routing_policy_rule(Link *link) {
+static int link_request_set_routing_policy_rule(Link *link) {
RoutingPolicyRule *rule, *rrule = NULL;
int r;
assert(link);
assert(link->network);
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ link->routing_policy_rules_configured = false;
+
LIST_FOREACH(rules, rule, link->network->rules) {
r = routing_policy_rule_get(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif,
@@ -865,8 +809,11 @@ static int link_request_set_routes(Link *link) {
assert(link->state != _LINK_STATE_INVALID);
link_set_state(link, LINK_STATE_CONFIGURING);
+ link->static_routes_configured = false;
- (void) link_set_routing_policy_rule(link);
+ r = link_request_set_routing_policy_rule(link);
+ if (r < 0)
+ return r;
/* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
for (phase = 0; phase < _PHASE_MAX; phase++)
@@ -894,6 +841,68 @@ static int link_request_set_routes(Link *link) {
return 0;
}
+void link_check_ready(Link *link) {
+ Address *a;
+ Iterator i;
+
+ assert(link);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
+ if (!link->network)
+ return;
+
+ if (!link->addresses_configured)
+ return;
+
+ if (!link->neighbors_configured)
+ return;
+
+ SET_FOREACH(a, link->addresses, i)
+ if (!address_is_ready(a))
+ return;
+
+ if (!link->addresses_ready) {
+ link->addresses_ready = true;
+ link_request_set_routes(link);
+ }
+
+ if (!link->static_routes_configured)
+ return;
+
+ if (!link->routing_policy_rules_configured)
+ return;
+
+ if (link_ipv4ll_enabled(link))
+ if (!link->ipv4ll_address ||
+ !link->ipv4ll_route)
+ return;
+
+ if (!link->network->bridge) {
+
+ if (link_ipv6ll_enabled(link))
+ if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
+ return;
+
+ if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured) ||
+ (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
+ !link->dhcp6_configured) ||
+ (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured && !link->dhcp6_configured))
+ return;
+
+ if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
+ return;
+ }
+
+ if (link->state != LINK_STATE_CONFIGURED)
+ link_enter_configured(link);
+
+ return;
+}
+
static int link_request_set_neighbors(Link *link) {
Neighbor *neighbor;
int r;
@@ -903,6 +912,7 @@ static int link_request_set_neighbors(Link *link) {
assert(link->state != _LINK_STATE_INVALID);
link_set_state(link, LINK_STATE_CONFIGURING);
+ link->neighbors_configured = false;
LIST_FOREACH(neighbors, neighbor, link->network->neighbors) {
r = neighbor_configure(neighbor, link, NULL);
@@ -947,7 +957,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
if (link->address_messages == 0) {
log_link_debug(link, "Addresses set");
link->addresses_configured = true;
- link_request_set_routes(link);
+ link_check_ready(link);
}
return 1;
@@ -1073,16 +1083,29 @@ static int link_request_set_addresses(Link *link) {
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
+ link_set_state(link, LINK_STATE_CONFIGURING);
+
+ /* Reset all *_configured flags we are configuring. */
+ link->addresses_configured = false;
+ link->addresses_ready = false;
+ link->neighbors_configured = false;
+ link->static_routes_configured = false;
+ link->routing_policy_rules_configured = false;
+
r = link_set_bridge_fdb(link);
if (r < 0)
return r;
- link_set_state(link, LINK_STATE_CONFIGURING);
-
- link_request_set_neighbors(link);
+ r = link_request_set_neighbors(link);
+ if (r < 0)
+ return r;
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
- r = address_configure(ad, link, address_handler, false);
+ bool update;
+
+ update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
+
+ r = address_configure(ad, link, address_handler, update);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set addresses: %m");
link_enter_failed(link);
@@ -1207,14 +1230,15 @@ static int link_request_set_addresses(Link *link) {
return r;
}
}
+ if (!sd_dhcp_server_is_running(link->dhcp_server)) {
+ r = sd_dhcp_server_start(link->dhcp_server);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m");
- r = sd_dhcp_server_start(link->dhcp_server);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m");
-
- link_enter_failed(link);
+ link_enter_failed(link);
- return 0;
+ return 0;
+ }
}
log_link_debug(link, "Offering DHCPv4 leases");
@@ -1222,7 +1246,7 @@ static int link_request_set_addresses(Link *link) {
if (link->address_messages == 0) {
link->addresses_configured = true;
- link_request_set_routes(link);
+ link_check_ready(link);
} else
log_link_debug(link, "Setting addresses");
@@ -1739,6 +1763,84 @@ 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(link);
+
+ 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_warning_errno(link, r, "Could not set address genmode for interface: %m");
+
+ return 1;
+}
+
+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);
+
+ log_link_debug(link, "Setting address genmode 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 {
+ const char *p = NULL;
+ _cleanup_free_ char *stable_secret = NULL;
+
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret");
+
+ /* The file may not exist. And event if it exists, when stable_secret is unset,
+ * then reading the file fails and EIO is returned. */
+ r = read_one_line_file(p, &stable_secret);
+ if (r < 0)
+ ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
+ else
+ ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
+ }
+
+ 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: %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;
@@ -1755,9 +1857,8 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
return 1;
}
-int link_up(Link *link) {
+static int link_up(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
- uint8_t ipv6ll_mode;
int r;
assert(link);
@@ -1788,34 +1889,16 @@ int link_up(Link *link) {
return log_link_error_errno(link, r, "Could not set MAC address: %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");
-
if (link_ipv6_enabled(link)) {
+ 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");
+
/* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
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 {
- const char *p = NULL;
- _cleanup_free_ char *stable_secret = NULL;
-
- p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret");
- r = read_one_line_file(p, &stable_secret);
-
- if (r < 0)
- ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
- else
- ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
- }
- 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: %m");
-
if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
r = sd_netlink_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
if (r < 0)
@@ -1825,11 +1908,11 @@ int link_up(Link *link) {
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 = 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_up_handler,
link_netlink_destroy_callback, link);
@@ -2918,6 +3001,12 @@ static int link_configure(Link *link) {
return r;
}
+ if (socket_ipv6_is_supported()) {
+ r = link_configure_addrgen_mode(link);
+ if (r < 0)
+ return r;
+ }
+
return link_configure_after_setting_mtu(link);
}