X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-link.c;h=0c243508a4314ef3f01c1196c13fe748a4f6f280;hp=2398ef79366f00760af3dd841e744506e945d0a8;hb=7ef7e5509b637e660e89ba8a938930ec01de6e54;hpb=710ce9e53740bb55f8a37539425a674e1f103d65 diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2398ef79366..0c243508a43 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -14,6 +14,7 @@ #include "missing_network.h" #include "netdev/bond.h" #include "netdev/bridge.h" +#include "netdev/ipvlan.h" #include "netdev/vrf.h" #include "netlink-util.h" #include "network-internal.h" @@ -76,6 +77,9 @@ static bool link_dhcp6_enabled(Link *link) { if (link->network->bond) return false; + if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan")) + return false; + if (manager_sysctl_ipv6_enabled(link->manager) == 0) return false; @@ -94,6 +98,9 @@ static bool link_dhcp4_enabled(Link *link) { if (link->network->bond) return false; + if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan")) + return false; + return link->network->dhcp & ADDRESS_FAMILY_IPV4; } @@ -109,11 +116,15 @@ static bool link_dhcp4_server_enabled(Link *link) { if (link->network->bond) return false; + if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan")) + return false; + return link->network->dhcp_server; } -bool link_ipv4ll_enabled(Link *link) { +bool link_ipv4ll_enabled(Link *link, AddressFamilyBoolean mask) { assert(link); + assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0); if (link->flags & IFF_LOOPBACK) return false; @@ -121,31 +132,20 @@ bool link_ipv4ll_enabled(Link *link) { if (!link->network) return false; - if (STRPTR_IN_SET(link->kind, "vrf", "wireguard")) - return false; - - if (link->network->bond) - return false; - - return link->network->link_local & ADDRESS_FAMILY_IPV4; -} - -bool link_ipv4ll_fallback_enabled(Link *link) { - assert(link); - - if (link->flags & IFF_LOOPBACK) + if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan", "vxcan", "nlmon")) return false; - if (!link->network) + /* L3 or L3S mode do not support ARP. */ + if (IN_SET(link_get_ipvlan_mode(link), NETDEV_IPVLAN_MODE_L3, NETDEV_IPVLAN_MODE_L3S)) return false; - if (STRPTR_IN_SET(link->kind, "vrf", "wireguard")) + if (link->network->bond) return false; if (link->network->bond) return false; - return link->network->link_local & ADDRESS_FAMILY_FALLBACK_IPV4; + return link->network->link_local & mask; } static bool link_ipv6ll_enabled(Link *link) { @@ -160,7 +160,7 @@ static bool link_ipv6ll_enabled(Link *link) { if (!link->network) return false; - if (STRPTR_IN_SET(link->kind, "vrf", "wireguard")) + if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "can", "vcan", "vxcan", "nlmon")) return false; if (link->network->bond) @@ -184,6 +184,9 @@ static bool link_ipv6_enabled(Link *link) { if (manager_sysctl_ipv6_enabled(link->manager) == 0) return false; + if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan")) + return false; + /* DHCPv6 client will not be started if no IPv6 link-local address is configured. */ return link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network); } @@ -316,16 +319,14 @@ static bool link_is_enslaved(Link *link) { /* Even if the link is not managed by networkd, honor IFF_SLAVE flag. */ return true; - if (!link->enslaved_raw) - return false; - if (!link->network) return false; - if (link->network->bridge) - /* TODO: support the case when link is not managed by networkd. */ + if (link->master_ifindex > 0 && link->network->bridge) return true; + /* TODO: add conditions for other netdevs. */ + return false; } @@ -417,7 +418,7 @@ void link_update_operstate(Link *link, bool also_update_master) { ? ((old & flag) ? (" -" string) : (" +" string)) \ : "") -static int link_update_flags(Link *link, sd_netlink_message *m) { +static int link_update_flags(Link *link, sd_netlink_message *m, bool force_update_operstate) { unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags; uint8_t operstate; int r; @@ -434,7 +435,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) { the state was unchanged */ operstate = link->kernel_operstate; - if ((link->flags == flags) && (link->kernel_operstate == operstate)) + if (!force_update_operstate && (link->flags == flags) && (link->kernel_operstate == operstate)) return 0; if (link->flags != flags) { @@ -577,7 +578,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { if (r < 0) return r; - r = link_update_flags(link, message); + r = link_update_flags(link, message, false); if (r < 0) return r; @@ -656,7 +657,7 @@ int link_get(Manager *m, int ifindex, Link **ret) { return 0; } -static void link_set_state(Link *link, LinkState state) { +void link_set_state(Link *link, LinkState state) { assert(link); if (link->state == state) @@ -674,21 +675,22 @@ static void link_set_state(Link *link, LinkState state) { static void link_enter_unmanaged(Link *link) { assert(link); - log_link_debug(link, "Unmanaged"); - link_set_state(link, LINK_STATE_UNMANAGED); link_dirty(link); } -int link_stop_clients(Link *link) { +int link_stop_clients(Link *link, bool may_keep_dhcp) { int r = 0, k; assert(link); assert(link->manager); assert(link->manager->event); - if (link->dhcp_client) { + dhcp4_release_old_lease(link); + + if (link->dhcp_client && (!may_keep_dhcp || !link->network || + !FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP))) { k = sd_dhcp_client_stop(link->dhcp_client); if (k < 0) r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m"); @@ -732,7 +734,7 @@ void link_enter_failed(Link *link) { link_set_state(link, LINK_STATE_FAILED); - link_stop_clients(link); + link_stop_clients(link, false); link_dirty(link); } @@ -830,14 +832,14 @@ static int link_request_set_routing_policy_rule(Link *link) { continue; } - r = routing_policy_rule_configure(rule, link, NULL, false); + r = routing_policy_rule_configure(rule, link, NULL); if (r < 0) { log_link_warning_errno(link, r, "Could not set routing policy rules: %m"); link_enter_failed(link); return r; } - - link->routing_policy_rule_messages++; + if (r > 0) + link->routing_policy_rule_messages++; } routing_policy_rule_purge(link->manager, link); @@ -911,8 +913,8 @@ int link_request_set_routes(Link *link) { link_enter_failed(link); return r; } - - link->route_messages++; + if (r > 0) + link->route_messages++; } if (link->route_messages == 0) { @@ -958,7 +960,7 @@ void link_check_ready(Link *link) { if (!link->routing_policy_rules_configured) return; - if (link_ipv4ll_enabled(link) && !(link->ipv4ll_address && link->ipv4ll_route)) + if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !(link->ipv4ll_address && link->ipv4ll_route)) return; if (link_ipv6ll_enabled(link) && @@ -966,8 +968,9 @@ void link_check_ready(Link *link) { return; if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && - !(link->dhcp4_configured || link->dhcp6_configured) && - !(link_ipv4ll_fallback_enabled(link) && link->ipv4ll_address && link->ipv4ll_route)) + !link->dhcp4_configured && + !link->dhcp6_configured && + !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address && link->ipv4ll_route)) /* When DHCP is enabled, at least one protocol must provide an address, or * an IPv4ll fallback address must be configured. */ return; @@ -1191,8 +1194,8 @@ static int link_request_set_addresses(Link *link) { link_enter_failed(link); return r; } - - link->address_messages++; + if (r > 0) + link->address_messages++; } LIST_FOREACH(labels, label, link->network->address_labels) { @@ -1384,7 +1387,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) return 1; } -int link_set_mtu(Link *link, uint32_t mtu, bool force) { +int link_set_mtu(Link *link, uint32_t mtu) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -1395,7 +1398,7 @@ int link_set_mtu(Link *link, uint32_t mtu, bool force) { if (mtu == 0 || link->setting_mtu) return 0; - if (force ? link->mtu == mtu : link->mtu >= mtu) + if (link->mtu == mtu) return 0; log_link_debug(link, "Setting MTU: %" PRIu32, mtu); @@ -1433,6 +1436,48 @@ int link_set_mtu(Link *link, uint32_t mtu, bool force) { return 0; } +static bool link_reduces_vlan_mtu(Link *link) { + /* See netif_reduces_vlan_mtu() in kernel. */ + return streq_ptr(link->kind, "macsec"); +} + +static uint32_t link_get_requested_mtu_by_stacked_netdevs(Link *link) { + uint32_t mtu = 0; + NetDev *dev; + Iterator i; + + HASHMAP_FOREACH(dev, link->network->stacked_netdevs, i) + if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0) + /* See vlan_dev_change_mtu() in kernel. */ + mtu = MAX(mtu, link_reduces_vlan_mtu(link) ? dev->mtu + 4 : dev->mtu); + + else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu) + /* See macvlan_change_mtu() in kernel. */ + mtu = dev->mtu; + + return mtu; +} + +static int link_configure_mtu(Link *link) { + uint32_t mtu; + + assert(link); + assert(link->network); + + if (link->network->mtu > 0) + return link_set_mtu(link, link->network->mtu); + + mtu = link_get_requested_mtu_by_stacked_netdevs(link); + if (link->mtu >= mtu) + return 0; + + log_link_notice(link, "Bumping MTU bytes from %"PRIu32" to %"PRIu32" because of stacked device. " + "If it is not desired, then please explicitly specify MTUBytes= setting.", + link->mtu, mtu); + + return link_set_mtu(link, mtu); +} + static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -1540,7 +1585,7 @@ static int link_acquire_ipv4_conf(Link *link) { assert(link->manager); assert(link->manager->event); - if (link_ipv4ll_enabled(link)) { + if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4)) { assert(link->ipv4ll); log_link_debug(link, "Acquiring IPv4 link-local address"); @@ -1595,7 +1640,8 @@ bool link_has_carrier(Link *link) { if (link->kernel_operstate == IF_OPER_UNKNOWN) /* operstate may not be implemented, so fall back to flags */ - if ((link->flags & IFF_LOWER_UP) && !(link->flags & IFF_DORMANT)) + if (FLAGS_SET(link->flags, IFF_LOWER_UP | IFF_RUNNING) && + !FLAGS_SET(link->flags, IFF_DORMANT)) return true; return false; @@ -2138,7 +2184,6 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li assert(link); assert(link->network); assert(link->enslaving > 0); - assert(!link->enslaved_raw); link->enslaving--; @@ -2154,7 +2199,6 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li log_link_debug(link, "Joined netdev"); if (link->enslaving == 0) { - link->enslaved_raw = true; link_joined(link); } @@ -2174,7 +2218,6 @@ static int link_enter_join_netdev(Link *link) { link_dirty(link); link->enslaving = 0; - link->enslaved_raw = false; if (link->network->bond) { if (link->network->bond->state == NETDEV_STATE_READY && @@ -2445,6 +2488,33 @@ static bool link_is_static_route_configured(Link *link, Route *route) { return false; } +static bool link_address_is_dynamic(Link *link, Address *address) { + Route *route; + Iterator i; + + assert(link); + assert(address); + + if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME) + return true; + + /* Even when the address is leased from a DHCP server, networkd assign the address + * without lifetime when KeepConfiguration=dhcp. So, let's check that we have + * corresponding routes with RTPROT_DHCP. */ + SET_FOREACH(route, link->routes_foreign, i) { + if (route->protocol != RTPROT_DHCP) + continue; + + if (address->family != route->family) + continue; + + if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc)) + return true; + } + + return false; +} + static int link_drop_foreign_config(Link *link) { Address *address; Route *route; @@ -2456,6 +2526,12 @@ static int link_drop_foreign_config(Link *link) { if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1) continue; + if (link_address_is_dynamic(link, address)) { + if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) + continue; + } else if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC)) + continue; + if (link_is_static_address_configured(link, address)) { r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); if (r < 0) @@ -2472,6 +2548,14 @@ static int link_drop_foreign_config(Link *link) { if (route->protocol == RTPROT_KERNEL) continue; + if (route->protocol == RTPROT_STATIC && + FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC)) + continue; + + if (route->protocol == RTPROT_DHCP && + FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) + continue; + if (link_is_static_route_configured(link, route)) { r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL); if (r < 0) @@ -2533,12 +2617,13 @@ static int link_configure(Link *link) { assert(link->network); assert(link->state == LINK_STATE_INITIALIZED); - if (STRPTR_IN_SET(link->kind, "can", "vcan")) + if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan")) 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->dhcp_critical)) { + if (!(link->flags & IFF_LOOPBACK) && + link->network->keep_configuration != KEEP_CONFIGURATION_YES) { r = link_drop_foreign_config(link); if (r < 0) return r; @@ -2584,7 +2669,7 @@ static int link_configure(Link *link) { if (r < 0) return r; - if (link_ipv4ll_enabled(link) || link_ipv4ll_fallback_enabled(link)) { + if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) { r = ipv4ll_configure(link); if (r < 0) return r; @@ -2635,7 +2720,7 @@ static int link_configure(Link *link) { return r; } - r = link_set_mtu(link, link->network->mtu, link->network->mtu_is_set); + r = link_configure_mtu(link); if (r < 0) return r; @@ -3224,7 +3309,7 @@ static int link_carrier_lost(Link *link) { if (link->setting_mtu) return 0; - r = link_stop_clients(link); + r = link_stop_clients(link, false); if (r < 0) { link_enter_failed(link); return r; @@ -3276,7 +3361,7 @@ int link_update(Link *link, sd_netlink_message *m) { const char *ifname; uint32_t mtu; bool had_carrier, carrier_gained, carrier_lost; - int r; + int old_master, r; assert(link); assert(link->ifname); @@ -3402,9 +3487,12 @@ int link_update(Link *link, sd_netlink_message *m) { } } + old_master = link->master_ifindex; + (void) sd_netlink_message_read_u32(m, IFLA_MASTER, (uint32_t *) &link->master_ifindex); + had_carrier = link_has_carrier(link); - r = link_update_flags(link, m); + r = link_update_flags(link, m, old_master != link->master_ifindex); if (r < 0) return r; @@ -3495,12 +3583,11 @@ int link_save(Link *link) { admin_state, oper_state); if (link->network) { - bool space; + char **dhcp6_domains = NULL, **dhcp_domains = NULL; + const char *dhcp_domainname = NULL, *p; sd_dhcp6_lease *dhcp6_lease = NULL; - const char *dhcp_domainname = NULL; - char **dhcp6_domains = NULL; - char **dhcp_domains = NULL; unsigned j; + bool space; fprintf(f, "REQUIRED_FOR_ONLINE=%s\n", yes_no(link->network->required_for_online)); @@ -3617,7 +3704,10 @@ int link_save(Link *link) { (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains); } - ordered_set_print(f, "DOMAINS=", link->network->search_domains); + fputs("DOMAINS=", f); + space = false; + ORDERED_SET_FOREACH(p, link->network->search_domains, i) + fputs_with_space(f, p, NULL, &space); if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) { NDiscDNSSL *dd; @@ -3635,7 +3725,10 @@ int link_save(Link *link) { fputc('\n', f); - ordered_set_print(f, "ROUTE_DOMAINS=", link->network->route_domains); + fputs("ROUTE_DOMAINS=", f); + space = false; + ORDERED_SET_FOREACH(p, link->network->route_domains, i) + fputs_with_space(f, p, NULL, &space); if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) { NDiscDNSSL *dd;