X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-link.c;h=0c243508a4314ef3f01c1196c13fe748a4f6f280;hp=2b6ff2b6c58d6e1e4f5e97d607934e7317ab6394;hb=7ef7e5509b637e660e89ba8a938930ec01de6e54;hpb=cb367b17853d215ebcf2816118c1f53d003e5088 diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2b6ff2b6c58..0c243508a43 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2,7 +2,6 @@ #include #include -#include #include #include "alloc-util.h" @@ -13,9 +12,13 @@ #include "fd-util.h" #include "fileio.h" #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" +#include "networkd-can.h" #include "networkd-ipv6-proxy-ndp.h" #include "networkd-lldp-tx.h" #include "networkd-manager.h" @@ -74,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; @@ -92,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; } @@ -107,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; @@ -119,31 +132,20 @@ bool link_ipv4ll_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", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan", "vxcan", "nlmon")) return false; - if (link->network->bond) + /* 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; - return link->network->link_local & ADDRESS_FAMILY_IPV4; -} - -bool link_ipv4ll_fallback_enabled(Link *link) { - assert(link); - - if (link->flags & IFF_LOOPBACK) - return false; - - if (!link->network) - 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) { @@ -158,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) @@ -182,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); } @@ -195,42 +200,6 @@ static bool link_radv_enabled(Link *link) { return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE; } -static bool link_lldp_rx_enabled(Link *link) { - assert(link); - - if (link->flags & IFF_LOOPBACK) - return false; - - if (link->iftype != ARPHRD_ETHER) - return false; - - if (!link->network) - return false; - - /* LLDP should be handled on bridge slaves as those have a direct - * connection to their peers not on the bridge master. Linux doesn't - * even (by default) forward lldp packets to the bridge master.*/ - if (streq_ptr("bridge", link->kind)) - return false; - - return link->network->lldp_mode != LLDP_MODE_NO; -} - -static bool link_lldp_emit_enabled(Link *link) { - assert(link); - - if (link->flags & IFF_LOOPBACK) - return false; - - if (link->iftype != ARPHRD_ETHER) - return false; - - if (!link->network) - return false; - - return link->network->lldp_emit != LLDP_EMIT_NO; -} - static bool link_ipv4_forward_enabled(Link *link) { assert(link); @@ -350,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; } @@ -451,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; @@ -468,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) { @@ -611,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; @@ -690,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) @@ -708,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"); @@ -766,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); } @@ -864,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); @@ -945,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) { @@ -983,6 +951,7 @@ void link_check_ready(Link *link) { if (!link->addresses_ready) { link->addresses_ready = true; link_request_set_routes(link); + return; } if (!link->static_routes_configured) @@ -991,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) && @@ -999,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; @@ -1224,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) { @@ -1367,7 +1337,7 @@ static int link_request_set_addresses(Link *link) { } static int link_set_bridge_vlan(Link *link) { - int r = 0; + int r; r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap); if (r < 0) @@ -1389,22 +1359,6 @@ static int link_set_proxy_arp(Link *link) { return 0; } -static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - int r; - - assert(link); - - log_link_debug(link, "Set link"); - - r = sd_netlink_message_get_errno(m); - if (r < 0 && r != -EEXIST) { - log_link_error_errno(link, r, "Could not join netdev: %m"); - link_enter_failed(link); - } - - return 1; -} - static int link_configure_after_setting_mtu(Link *link); static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { @@ -1433,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; @@ -1444,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); @@ -1482,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; @@ -1551,285 +1547,6 @@ static int link_set_flags(Link *link) { return 0; } -static int link_set_bridge(Link *link) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; - int r; - - assert(link); - assert(link->network); - - 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_rtnl_message_link_set_family(req, PF_BRIDGE); - if (r < 0) - return log_link_error_errno(link, r, "Could not set message family: %m"); - - r = sd_netlink_message_open_container(req, IFLA_PROTINFO); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m"); - - if (link->network->use_bpdu >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->use_bpdu); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m"); - } - - if (link->network->hairpin >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m"); - } - - if (link->network->fast_leave >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m"); - } - - if (link->network->allow_port_to_be_root >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m"); - } - - if (link->network->unicast_flood >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m"); - } - - if (link->network->multicast_flood >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_FLOOD, link->network->multicast_flood); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_FLOOD attribute: %m"); - } - - if (link->network->multicast_to_unicast >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m"); - } - - if (link->network->neighbor_suppression >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_NEIGH_SUPPRESS, link->network->neighbor_suppression); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_NEIGH_SUPPRESS attribute: %m"); - } - - if (link->network->learning >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_LEARNING, link->network->learning); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_LEARNING attribute: %m"); - } - - if (link->network->bridge_proxy_arp >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP, link->network->bridge_proxy_arp); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP attribute: %m"); - } - - if (link->network->bridge_proxy_arp_wifi >= 0) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP_WIFI, link->network->bridge_proxy_arp_wifi); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP_WIFI attribute: %m"); - } - - if (link->network->cost != 0) { - r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m"); - } - - if (link->network->priority != LINK_BRIDGE_PORT_PRIORITY_INVALID) { - r = sd_netlink_message_append_u16(req, IFLA_BRPORT_PRIORITY, link->network->priority); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PRIORITY attribute: %m"); - } - - if (link->network->multicast_router != _MULTICAST_ROUTER_INVALID) { - r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MULTICAST_ROUTER, link->network->multicast_router); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MULTICAST_ROUTER attribute: %m"); - } - - r = sd_netlink_message_close_container(req); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m"); - - r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_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 r; -} - -static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - int r; - - assert(m); - assert(link); - assert(link->ifname); - - 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 bonding interface: %m"); - return 1; - } - - return 1; -} - -static int link_set_bond(Link *link) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; - int r; - - assert(link); - assert(link->network); - - r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->network->bond->ifindex); - if (r < 0) - return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); - - r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK); - if (r < 0) - return log_link_error_errno(link, r, "Could not set netlink flags: %m"); - - r = sd_netlink_message_open_container(req, IFLA_LINKINFO); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m"); - - r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, "bond"); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m"); - - if (link->network->active_slave) { - r = sd_netlink_message_append_u32(req, IFLA_BOND_ACTIVE_SLAVE, link->ifindex); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BOND_ACTIVE_SLAVE attribute: %m"); - } - - if (link->network->primary_slave) { - r = sd_netlink_message_append_u32(req, IFLA_BOND_PRIMARY, link->ifindex); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_BOND_PRIMARY attribute: %m"); - } - - r = sd_netlink_message_close_container(req); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m"); - - r = sd_netlink_message_close_container(req); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m"); - - r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bond_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 r; -} - -static int link_lldp_save(Link *link) { - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - sd_lldp_neighbor **l = NULL; - int n = 0, r, i; - - assert(link); - assert(link->lldp_file); - - if (!link->lldp) { - (void) unlink(link->lldp_file); - return 0; - } - - r = sd_lldp_get_neighbors(link->lldp, &l); - if (r < 0) - goto finish; - if (r == 0) { - (void) unlink(link->lldp_file); - goto finish; - } - - n = r; - - r = fopen_temporary(link->lldp_file, &f, &temp_path); - if (r < 0) - goto finish; - - fchmod(fileno(f), 0644); - - for (i = 0; i < n; i++) { - const void *p; - le64_t u; - size_t sz; - - r = sd_lldp_neighbor_get_raw(l[i], &p, &sz); - if (r < 0) - goto finish; - - u = htole64(sz); - (void) fwrite(&u, 1, sizeof(u), f); - (void) fwrite(p, 1, sz, f); - } - - r = fflush_and_check(f); - if (r < 0) - goto finish; - - if (rename(temp_path, link->lldp_file) < 0) { - r = -errno; - goto finish; - } - -finish: - if (r < 0) { - (void) unlink(link->lldp_file); - if (temp_path) - (void) unlink(temp_path); - - log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file); - } - - if (l) { - for (i = 0; i < n; i++) - sd_lldp_neighbor_unref(l[i]); - free(l); - } - - return r; -} - -static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { - Link *link = userdata; - int r; - - assert(link); - - (void) link_lldp_save(link); - - if (link_lldp_emit_enabled(link) && event == SD_LLDP_EVENT_ADDED) { - /* If we received information about a new neighbor, restart the LLDP "fast" logic */ - - log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission."); - - r = link_lldp_emit_start(link); - if (r < 0) - log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m"); - } -} - static int link_acquire_ipv6_conf(Link *link) { int r; @@ -1868,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"); @@ -1923,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; @@ -1954,6 +1672,9 @@ static int link_configure_addrgen_mode(Link *link) { assert(link->manager); assert(link->manager->rtnl); + if (!socket_ipv6_is_supported()) + return 0; + log_link_debug(link, "Setting address genmode for link"); r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); @@ -2047,72 +1768,6 @@ static int link_up(Link *link) { return log_link_error_errno(link, r, "Could not set MAC address: %m"); } - if (link_ipv6_enabled(link)) { - uint8_t ipv6ll_mode; - - 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 (!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) - return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m"); - } - - if (!link_ipv6ll_enabled(link)) - ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE; - else if (sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL) < 0) - /* The file may not exist. And event if it exists, when stable_secret is unset, - * reading the file fails with EIO. */ - 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_up_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_can(Link *link) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; - int r; - - assert(link); - - log_link_debug(link, "Bringing CAN link up"); - - 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_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP); - if (r < 0) - return log_link_error_errno(link, r, "Could not set link flags: %m"); - r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler, link_netlink_destroy_callback, link); if (r < 0) @@ -2123,119 +1778,6 @@ static int link_up_can(Link *link) { return 0; } -static int link_set_can(Link *link) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - int r; - - assert(link); - assert(link->network); - assert(link->manager); - assert(link->manager->rtnl); - - log_link_debug(link, "link_set_can"); - - r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex); - if (r < 0) - return log_link_error_errno(link, r, "Failed to allocate netlink message: %m"); - - r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK); - if (r < 0) - return log_link_error_errno(link, r, "Could not set netlink flags: %m"); - - r = sd_netlink_message_open_container(m, IFLA_LINKINFO); - if (r < 0) - return log_link_error_errno(link, r, "Failed to open netlink container: %m"); - - r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, link->kind); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m"); - - if (link->network->can_bitrate > 0 || link->network->can_sample_point > 0) { - struct can_bittiming bt = { - .bitrate = link->network->can_bitrate, - .sample_point = link->network->can_sample_point, - }; - - if (link->network->can_bitrate > UINT32_MAX) { - log_link_error(link, "bitrate (%zu) too big.", link->network->can_bitrate); - return -ERANGE; - } - - log_link_debug(link, "Setting bitrate = %d bit/s", bt.bitrate); - if (link->network->can_sample_point > 0) - log_link_debug(link, "Setting sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10); - else - log_link_debug(link, "Using default sample point"); - - r = sd_netlink_message_append_data(m, IFLA_CAN_BITTIMING, &bt, sizeof(bt)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_CAN_BITTIMING attribute: %m"); - } - - if (link->network->can_restart_us > 0) { - char time_string[FORMAT_TIMESPAN_MAX]; - uint64_t restart_ms; - - if (link->network->can_restart_us == USEC_INFINITY) - restart_ms = 0; - else - restart_ms = DIV_ROUND_UP(link->network->can_restart_us, USEC_PER_MSEC); - - format_timespan(time_string, FORMAT_TIMESPAN_MAX, restart_ms * 1000, MSEC_PER_SEC); - - if (restart_ms > UINT32_MAX) { - log_link_error(link, "restart timeout (%s) too big.", time_string); - return -ERANGE; - } - - log_link_debug(link, "Setting restart = %s", time_string); - - r = sd_netlink_message_append_u32(m, IFLA_CAN_RESTART_MS, restart_ms); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_CAN_RESTART_MS attribute: %m"); - } - - if (link->network->can_triple_sampling >= 0) { - struct can_ctrlmode cm = { - .mask = CAN_CTRLMODE_3_SAMPLES, - .flags = link->network->can_triple_sampling ? CAN_CTRLMODE_3_SAMPLES : 0, - }; - - log_link_debug(link, "%sabling triple-sampling", link->network->can_triple_sampling ? "En" : "Dis"); - - r = sd_netlink_message_append_data(m, IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_CAN_CTRLMODE attribute: %m"); - } - - r = sd_netlink_message_close_container(m); - if (r < 0) - return log_link_error_errno(link, r, "Failed to close netlink container: %m"); - - r = sd_netlink_message_close_container(m); - if (r < 0) - return log_link_error_errno(link, r, "Failed to close netlink container: %m"); - - r = netlink_call_async(link->manager->rtnl, NULL, m, link_set_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); - - if (!(link->flags & IFF_UP)) { - r = link_up_can(link); - if (r < 0) { - link_enter_failed(link); - return r; - } - } - - log_link_debug(link, "link_set_can done"); - - return r; -} - static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -2248,13 +1790,10 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link if (r < 0) log_link_warning_errno(link, r, "Could not bring down interface: %m"); - if (streq_ptr(link->kind, "can")) - link_set_can(link); - return 1; } -int link_down(Link *link) { +int link_down(Link *link, link_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -2273,7 +1812,8 @@ int link_down(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not set link flags: %m"); - r = netlink_call_async(link->manager->rtnl, NULL, req, link_down_handler, + r = netlink_call_async(link->manager->rtnl, NULL, req, + callback ?: link_down_handler, link_netlink_destroy_callback, link); if (r < 0) return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); @@ -2305,7 +1845,7 @@ static int link_handle_bound_to_list(Link *link) { } if (!required_up && link_is_up) { - r = link_down(link); + r = link_down(link, NULL); if (r < 0) return r; } else if (required_up && !link_is_up) { @@ -2644,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--; @@ -2660,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); } @@ -2680,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 && @@ -2951,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; @@ -2962,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) @@ -2978,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) @@ -3032,60 +2610,6 @@ static int link_drop_config(Link *link) { return 0; } -static int link_update_lldp(Link *link) { - int r; - - assert(link); - - if (!link->lldp) - return 0; - - if (link->flags & IFF_UP) { - r = sd_lldp_start(link->lldp); - if (r > 0) - log_link_debug(link, "Started LLDP."); - else - log_link_warning_errno(link, r, "Failed to start LLDP: %m"); - } else { - r = sd_lldp_stop(link->lldp); - if (r > 0) - log_link_debug(link, "Stopped LLDP."); - else - log_link_warning_errno(link, r, "Failed to stop LLDP: %m"); - } - - return r; -} - -static int link_configure_can(Link *link) { - int r; - - if (streq_ptr(link->kind, "can")) { - /* The CAN interface must be down to configure bitrate, etc... */ - if ((link->flags & IFF_UP)) { - r = link_down(link); - if (r < 0) { - link_enter_failed(link); - return r; - } - - return 0; - } - - return link_set_can(link); - } - - if (!(link->flags & IFF_UP)) { - r = link_up_can(link); - if (r < 0) { - link_enter_failed(link); - return r; - } - } - - return 0; -} - static int link_configure(Link *link) { int r; @@ -3093,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; @@ -3144,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; @@ -3190,47 +2715,18 @@ static int link_configure(Link *link) { } if (link_lldp_rx_enabled(link)) { - r = sd_lldp_new(&link->lldp); - if (r < 0) - return r; - - r = sd_lldp_set_ifindex(link->lldp, link->ifindex); - if (r < 0) - return r; - - r = sd_lldp_match_capabilities(link->lldp, - link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ? - SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS : - SD_LLDP_SYSTEM_CAPABILITIES_ALL); - if (r < 0) - return r; - - r = sd_lldp_set_filter_address(link->lldp, &link->mac); - if (r < 0) - return r; - - r = sd_lldp_attach_event(link->lldp, NULL, 0); - if (r < 0) - return r; - - r = sd_lldp_set_callback(link->lldp, lldp_handler, link); - if (r < 0) - return r; - - r = link_update_lldp(link); + r = link_lldp_rx_configure(link); if (r < 0) 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; - if (socket_ipv6_is_supported()) { - r = link_configure_addrgen_mode(link); - if (r < 0) - return r; - } + r = link_configure_addrgen_mode(link); + if (r < 0) + return r; return link_configure_after_setting_mtu(link); } @@ -3813,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; @@ -3865,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); @@ -3991,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; @@ -4084,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)); @@ -4206,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; @@ -4224,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;