diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/netdev/bridge.c | 2 | ||||
-rw-r--r-- | src/network/netdev/netdev.c | 11 | ||||
-rw-r--r-- | src/network/netdev/netdev.h | 1 | ||||
-rw-r--r-- | src/network/netdev/wireguard.c | 233 | ||||
-rw-r--r-- | src/network/networkd-address.c | 53 | ||||
-rw-r--r-- | src/network/networkd-brvlan.c | 3 | ||||
-rw-r--r-- | src/network/networkd-dhcp4.c | 2 | ||||
-rw-r--r-- | src/network/networkd-dhcp6.c | 2 | ||||
-rw-r--r-- | src/network/networkd-link.c | 291 | ||||
-rw-r--r-- | src/network/networkd-link.h | 2 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 2 | ||||
-rw-r--r-- | src/network/networkd-ndisc.c | 1 | ||||
-rw-r--r-- | src/network/networkd-network.c | 50 | ||||
-rw-r--r-- | src/network/wait-online/manager.c | 31 |
14 files changed, 412 insertions, 272 deletions
diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c index 0c804adb2e..aadb3ab905 100644 --- a/src/network/netdev/bridge.c +++ b/src/network/netdev/bridge.c @@ -47,7 +47,7 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess r = sd_netlink_message_open_container(req, IFLA_LINKINFO); if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not append IFLA_PROTINFO attribute: %m"); + return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind)); if (r < 0) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index f0e9d00246..0263917468 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -148,11 +148,16 @@ static void netdev_callbacks_clear(NetDev *netdev) { } } +bool netdev_is_managed(NetDev *netdev) { + if (!netdev || !netdev->manager || !netdev->ifname) + return false; + + return hashmap_get(netdev->manager->netdevs, netdev->ifname) == netdev; +} + static void netdev_detach_from_manager(NetDev *netdev) { if (netdev->ifname && netdev->manager) hashmap_remove(netdev->manager->netdevs, netdev->ifname); - - netdev->manager = NULL; } static NetDev *netdev_free(NetDev *netdev) { @@ -476,7 +481,7 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) { l = strlen(ifname); sz = sizeof(sd_id128_t) + l; - v = alloca(sz); + v = newa(uint8_t, sz); /* fetch some persistent data unique to the machine */ r = sd_id128_get_machine((sd_id128_t*) v); diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index bfe1094181..d6524da0f3 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -156,6 +156,7 @@ NetDev *netdev_ref(NetDev *netdev); DEFINE_TRIVIAL_DESTRUCTOR(netdev_destroy_callback, NetDev, netdev_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref); +bool netdev_is_managed(NetDev *netdev); int netdev_get(Manager *manager, const char *name, NetDev **ret); int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink); int netdev_get_mac(const char *ifname, struct ether_addr **ret); diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index 167cf65046..0c0b16d1da 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -45,22 +45,137 @@ static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) { return peer; } -static int set_wireguard_interface(NetDev *netdev) { +static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message, const WireguardIPmask *mask, uint16_t index) { int r; - unsigned i, j; - WireguardPeer *peer, *peer_start; - WireguardIPmask *mask, *mask_start = NULL; + + assert(message); + assert(mask); + assert(index > 0); + + /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */ + + r = sd_netlink_message_open_array(message, index); + if (r < 0) + return 0; + + r = sd_netlink_message_append_u16(message, WGALLOWEDIP_A_FAMILY, mask->family); + if (r < 0) + goto cancel; + + if (mask->family == AF_INET) + r = sd_netlink_message_append_in_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in); + else if (mask->family == AF_INET6) + r = sd_netlink_message_append_in6_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in6); + if (r < 0) + goto cancel; + + r = sd_netlink_message_append_u8(message, WGALLOWEDIP_A_CIDR_MASK, mask->cidr); + if (r < 0) + goto cancel; + + r = sd_netlink_message_close_container(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); + + return 1; + +cancel: + r = sd_netlink_message_cancel_array(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not cancel wireguard allowed ip message attribute: %m"); + + return 0; +} + +static int wireguard_set_peer_one(NetDev *netdev, sd_netlink_message *message, const WireguardPeer *peer, uint16_t index, WireguardIPmask **mask_start) { + WireguardIPmask *mask, *start; + uint16_t j = 0; + int r; + + assert(message); + assert(peer); + assert(index > 0); + assert(mask_start); + + /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */ + + start = *mask_start ?: peer->ipmasks; + + r = sd_netlink_message_open_array(message, index); + if (r < 0) + return 0; + + r = sd_netlink_message_append_data(message, WGPEER_A_PUBLIC_KEY, &peer->public_key, sizeof(peer->public_key)); + if (r < 0) + goto cancel; + + if (!*mask_start) { + r = sd_netlink_message_append_data(message, WGPEER_A_PRESHARED_KEY, &peer->preshared_key, WG_KEY_LEN); + if (r < 0) + goto cancel; + + r = sd_netlink_message_append_u32(message, WGPEER_A_FLAGS, peer->flags); + if (r < 0) + goto cancel; + + r = sd_netlink_message_append_u16(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval); + if (r < 0) + goto cancel; + + if (peer->endpoint.sa.sa_family == AF_INET) + r = sd_netlink_message_append_sockaddr_in(message, WGPEER_A_ENDPOINT, &peer->endpoint.in); + else if (peer->endpoint.sa.sa_family == AF_INET6) + r = sd_netlink_message_append_sockaddr_in6(message, WGPEER_A_ENDPOINT, &peer->endpoint.in6); + if (r < 0) + goto cancel; + } + + r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS); + if (r < 0) + goto cancel; + + LIST_FOREACH(ipmasks, mask, start) { + r = wireguard_set_ipmask_one(netdev, message, mask, ++j); + if (r < 0) + return r; + if (r == 0) + break; + } + + r = sd_netlink_message_close_container(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); + + r = sd_netlink_message_close_container(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not add wireguard peer: %m"); + + *mask_start = mask; /* Start next cycle from this mask. */ + return !mask; + +cancel: + r = sd_netlink_message_cancel_array(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not cancel wireguard peers: %m"); + + return 0; +} + +static int wireguard_set_interface(NetDev *netdev) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; - Wireguard *w; + WireguardIPmask *mask_start = NULL; + WireguardPeer *peer, *peer_start; uint32_t serial; + Wireguard *w; + int r; assert(netdev); w = WIREGUARD(netdev); assert(w); - peer_start = w->peers; + for (peer_start = w->peers; peer_start; ) { + uint16_t i = 0; - do { message = sd_netlink_message_unref(message); r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message); @@ -93,97 +208,14 @@ static int set_wireguard_interface(NetDev *netdev) { if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append wireguard peer attributes: %m"); - i = 0; - LIST_FOREACH(peers, peer, peer_start) { - r = sd_netlink_message_open_array(message, ++i); - if (r < 0) - break; - - r = sd_netlink_message_append_data(message, WGPEER_A_PUBLIC_KEY, &peer->public_key, sizeof(peer->public_key)); + r = wireguard_set_peer_one(netdev, message, peer, ++i, &mask_start); if (r < 0) + return r; + if (r == 0) break; - - if (!mask_start) { - r = sd_netlink_message_append_data(message, WGPEER_A_PRESHARED_KEY, &peer->preshared_key, WG_KEY_LEN); - if (r < 0) - break; - - r = sd_netlink_message_append_u32(message, WGPEER_A_FLAGS, peer->flags); - if (r < 0) - break; - - r = sd_netlink_message_append_u16(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval); - if (r < 0) - break; - - if (peer->endpoint.sa.sa_family == AF_INET) { - r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in, sizeof(peer->endpoint.in)); - if (r < 0) - break; - } else if (peer->endpoint.sa.sa_family == AF_INET6) { - r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in6, sizeof(peer->endpoint.in6)); - if (r < 0) - break; - } - - mask_start = peer->ipmasks; - } - - r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS); - if (r < 0) { - mask_start = NULL; - break; - } - j = 0; - LIST_FOREACH(ipmasks, mask, mask_start) { - r = sd_netlink_message_open_array(message, ++j); - if (r < 0) - break; - - r = sd_netlink_message_append_u16(message, WGALLOWEDIP_A_FAMILY, mask->family); - if (r < 0) - break; - - if (mask->family == AF_INET) { - r = sd_netlink_message_append_in_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in); - if (r < 0) - break; - } else if (mask->family == AF_INET6) { - r = sd_netlink_message_append_in6_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in6); - if (r < 0) - break; - } - - r = sd_netlink_message_append_u8(message, WGALLOWEDIP_A_CIDR_MASK, mask->cidr); - if (r < 0) - break; - - r = sd_netlink_message_close_container(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); - } - mask_start = mask; - if (mask_start) { - r = sd_netlink_message_cancel_array(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not cancel wireguard allowed ip message attribute: %m"); - } - r = sd_netlink_message_close_container(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); - - r = sd_netlink_message_close_container(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not add wireguard peer: %m"); - } - - peer_start = peer; - if (peer_start && !mask_start) { - r = sd_netlink_message_cancel_array(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not cancel wireguard peers: %m"); } + peer_start = peer; /* Start next cycle from this peer. */ r = sd_netlink_message_close_container(message); if (r < 0) @@ -192,8 +224,7 @@ static int set_wireguard_interface(NetDev *netdev) { r = sd_netlink_send(netdev->manager->genl, message, &serial); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not set wireguard device: %m"); - - } while (peer || mask_start); + } return 0; } @@ -224,8 +255,7 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) { w = WIREGUARD(netdev); assert(w); - if (!netdev->manager) - /* The netdev is detached. */ + if (!netdev_is_managed(netdev)) return 0; assert(!w->unresolved_endpoints); @@ -260,8 +290,7 @@ static int wireguard_resolve_handler(sd_resolve_query *q, w = WIREGUARD(netdev); assert(w); - if (!netdev->manager) - /* The netdev is detached. */ + if (!netdev_is_managed(netdev)) return 0; if (ret != 0) { @@ -280,7 +309,7 @@ static int wireguard_resolve_handler(sd_resolve_query *q, return 0; } - set_wireguard_interface(netdev); + (void) wireguard_set_interface(netdev); if (w->failed_endpoints) { _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; @@ -355,7 +384,7 @@ static int netdev_wireguard_post_create(NetDev *netdev, Link *link, sd_netlink_m w = WIREGUARD(netdev); assert(w); - set_wireguard_interface(netdev); + (void) wireguard_set_interface(netdev); resolve_endpoints(netdev); return 0; } diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 9f0a22b827..3cdbd9e37e 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "conf-parser.h" #include "firewall-util.h" +#include "missing_network.h" #include "netlink-util.h" #include "networkd-address.h" #include "networkd-manager.h" @@ -351,18 +352,17 @@ int address_update( address->cinfo = *cinfo; link_update_operstate(address->link); + link_check_ready(address->link); - if (!ready && address_is_ready(address)) { - link_check_ready(address->link); + if (!ready && + address_is_ready(address) && + address->family == AF_INET6 && + in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && + in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { - if (address->family == AF_INET6 && - in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && - in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { - - r = link_ipv6ll_gained(address->link, &address->in_addr.in6); - if (r < 0) - return r; - } + r = link_ipv6ll_gained(address->link, &address->in_addr.in6); + if (r < 0) + return r; } return 0; @@ -632,14 +632,10 @@ int address_configure( r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6); if (r < 0) return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m"); - } else { - if (address->family == AF_INET) { - if (address->prefixlen <= 30) { - r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); - if (r < 0) - return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m"); - } - } + } else if (address->family == AF_INET && address->prefixlen <= 30) { + r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); + if (r < 0) + return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m"); } if (address->label) { @@ -648,8 +644,7 @@ int address_configure( return log_error_errno(r, "Could not append IFA_LABEL attribute: %m"); } - r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, - &address->cinfo); + r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo); if (r < 0) return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m"); @@ -657,8 +652,7 @@ int address_configure( if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, req, callback, - link_netlink_destroy_callback, link); + r = netlink_call_async(link->manager->rtnl, NULL, req, callback, link_netlink_destroy_callback, link); if (r < 0) { address_release(address); return log_error_errno(r, "Could not send rtnetlink message: %m"); @@ -666,7 +660,10 @@ int address_configure( link_ref(link); - r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); + if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer)) + r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, NULL); + else + r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); if (r < 0) { address_release(address); return log_error_errno(r, "Could not add address: %m"); @@ -752,7 +749,15 @@ int config_parse_address(const char *unit, return r; /* Address=address/prefixlen */ - r = in_addr_default_prefix_from_string_auto(rvalue, &f, &buffer, &prefixlen); + r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_REFUSE, &f, &buffer, &prefixlen); + if (r == -ENOANO) { + log_syntax(unit, LOG_ERR, filename, line, r, + "An address '%s' is specified without prefix length. " + "The behavior of parsing addresses without prefix length will be changed in the future release. " + "Please specify prefix length explicitly.", rvalue); + + r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_LEGACY, &f, &buffer, &prefixlen); + } if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue); return 0; diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c index 1d18e29b7c..8377623da4 100644 --- a/src/network/networkd-brvlan.c +++ b/src/network/networkd-brvlan.c @@ -9,6 +9,7 @@ #include "alloc-util.h" #include "conf-parser.h" +#include "missing_if_bridge.h" #include "netlink-util.h" #include "networkd-brvlan.h" #include "networkd-link.h" @@ -22,7 +23,7 @@ static bool is_bit_set(unsigned bit, uint32_t scope) { return scope & (1 << bit); } -static inline void set_bit(unsigned nr, uint32_t *addr) { +static void set_bit(unsigned nr, uint32_t *addr) { if (nr < BRIDGE_VLAN_BITMAP_MAX) addr[nr / 32] |= (((uint32_t) 1) << (nr % 32)); } diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 980d49e4ff..d8ac4552f4 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -690,7 +690,7 @@ int dhcp4_set_client_identifier(Link *link) { if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) r = sd_dhcp_client_set_duid_llt(link->dhcp_client, - duid->llt_time); + duid->llt_time); else r = sd_dhcp_client_set_duid(link->dhcp_client, duid->type, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index ed6b9df72b..c1fba03f9f 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -11,6 +11,7 @@ #include "hashmap.h" #include "hostname-util.h" +#include "missing_network.h" #include "network-internal.h" #include "networkd-link.h" #include "networkd-manager.h" @@ -254,7 +255,6 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link return 1; } - static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { int r; sd_dhcp6_lease *lease; 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); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 00e68fdfaa..dcb1ea68dd 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -82,6 +82,7 @@ typedef struct Link { Set *routes_foreign; bool addresses_configured; + bool addresses_ready; sd_dhcp_client *dhcp_client; sd_dhcp_lease *dhcp_lease; @@ -142,7 +143,6 @@ int link_get(Manager *m, int ifindex, Link **ret); int link_add(Manager *manager, sd_netlink_message *message, Link **ret); void link_drop(Link *link); -int link_up(Link *link); int link_down(Link *link); void link_enter_failed(Link *link); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 81c81f18af..c8d369e2a0 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1456,7 +1456,7 @@ void manager_free(Manager *m) { sd_device_monitor_unref(m->device_monitor); - sd_bus_unref(m->bus); + sd_bus_flush_close_unref(m->bus); free(m->dynamic_timezone); free(m->dynamic_hostname); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 80bfd2cba1..e5b8d11555 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -8,6 +8,7 @@ #include "sd-ndisc.h" +#include "missing_network.h" #include "networkd-ndisc.h" #include "networkd-route.h" #include "strv.h" diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index ccc1c3ce89..12344ec695 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -98,12 +98,13 @@ void network_apply_anonymize_if_set(Network *network) { } int network_load_one(Manager *manager, const char *filename) { + _cleanup_free_ char *fname = NULL, *name = NULL; _cleanup_(network_freep) Network *network = NULL; _cleanup_fclose_ FILE *file = NULL; - char *d; const char *dropin_dirname; - Route *route; Address *address; + Route *route; + char *d; int r; assert(manager); @@ -122,12 +123,30 @@ int network_load_one(Manager *manager, const char *filename) { return 0; } + fname = strdup(filename); + if (!fname) + return log_oom(); + + name = strdup(basename(filename)); + if (!name) + return log_oom(); + + d = strrchr(name, '.'); + if (!d) + return -EINVAL; + + *d = '\0'; + + dropin_dirname = strjoina(name, ".network.d"); + network = new(Network, 1); if (!network) return log_oom(); *network = (Network) { .manager = manager, + .filename = TAKE_PTR(fname), + .name = TAKE_PTR(name), .required_for_online = true, .dhcp = ADDRESS_FAMILY_NO, @@ -190,22 +209,6 @@ int network_load_one(Manager *manager, const char *filename) { .ipv6_accept_ra_route_table = RT_TABLE_MAIN, }; - network->filename = strdup(filename); - if (!network->filename) - return log_oom(); - - network->name = strdup(basename(filename)); - if (!network->name) - return log_oom(); - - d = strrchr(network->name, '.'); - if (!d) - return -EINVAL; - - *d = '\0'; - - dropin_dirname = strjoina(network->name, ".network.d"); - r = config_parse_many(filename, network_dirs, dropin_dirname, "Match\0" "Link\0" @@ -228,8 +231,11 @@ int network_load_one(Manager *manager, const char *filename) { "CAN\0", config_item_perf_lookup, network_network_gperf_lookup, CONFIG_PARSE_WARN, network); - if (r < 0) + if (r < 0) { + /* Unset manager here. Otherwise, LIST_REMOVE() in network_free() fails. */ + network->manager = NULL; return r; + } network_apply_anonymize_if_set(network); @@ -253,21 +259,19 @@ int network_load_one(Manager *manager, const char *filename) { if (r < 0) return r; - LIST_FOREACH(routes, route, network->static_routes) { + LIST_FOREACH(routes, route, network->static_routes) if (!route->family) { log_warning("Route section without Gateway field configured in %s. " "Ignoring", filename); return 0; } - } - LIST_FOREACH(addresses, address, network->static_addresses) { + LIST_FOREACH(addresses, address, network->static_addresses) if (!address->family) { log_warning("Address section without Address field configured in %s. " "Ignoring", filename); return 0; } - } network = NULL; diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index e1ccc9ff67..67218b6db3 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -89,16 +89,25 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * assert(mm); r = sd_netlink_message_get_type(mm, &type); - if (r < 0) - goto fail; + if (r < 0) { + log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m"); + return 0; + } r = sd_rtnl_message_link_get_ifindex(mm, &ifindex); - if (r < 0) - goto fail; + if (r < 0) { + log_warning_errno(r, "rtnl: Could not get ifindex from link, ignoring: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received link message with invalid ifindex %d, ignoring", ifindex); + return 0; + } r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname); - if (r < 0) - goto fail; + if (r < 0) { + log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m"); + return 0; + } l = hashmap_get(m->links, INT_TO_PTR(ifindex)); @@ -110,16 +119,16 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * r = link_new(m, &l, ifindex, ifname); if (r < 0) - goto fail; + return log_error_errno(r, "Failed to create link object: %m"); r = link_update_monitor(l); if (r < 0) - goto fail; + return log_error_errno(r, "Failed to initialize link object: %m"); } r = link_update_rtnl(l, mm); if (r < 0) - goto fail; + return log_warning_errno(r, "Failed to process RTNL link message: %m");; break; @@ -133,10 +142,6 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * } return 0; - -fail: - log_warning_errno(r, "Failed to process RTNL link message: %m"); - return 0; } static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) { |