]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-link.c
network: ignore requested ipv6 routing policy rule when ipv6 is disabled by sysctl
[thirdparty/systemd.git] / src / network / networkd-link.c
index f633a5c7edde9add34d7e68edd780fd5aa732a6e..0c243508a4314ef3f01c1196c13fe748a4f6f280 100644 (file)
@@ -77,7 +77,7 @@ static bool link_dhcp6_enabled(Link *link) {
         if (link->network->bond)
                 return false;
 
-        if (STRPTR_IN_SET(link->kind, "can", "vcan"))
+        if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
                 return false;
 
         if (manager_sysctl_ipv6_enabled(link->manager) == 0)
@@ -98,7 +98,7 @@ static bool link_dhcp4_enabled(Link *link) {
         if (link->network->bond)
                 return false;
 
-        if (STRPTR_IN_SET(link->kind, "can", "vcan"))
+        if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
                 return false;
 
         return link->network->dhcp & ADDRESS_FAMILY_IPV4;
@@ -116,14 +116,15 @@ static bool link_dhcp4_server_enabled(Link *link) {
         if (link->network->bond)
                 return false;
 
-        if (STRPTR_IN_SET(link->kind, "can", "vcan"))
+        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;
@@ -131,7 +132,7 @@ bool link_ipv4ll_enabled(Link *link) {
         if (!link->network)
                 return false;
 
-        if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan"))
+        if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan", "vxcan", "nlmon"))
                 return false;
 
         /* L3 or L3S mode do not support ARP. */
@@ -141,29 +142,10 @@ bool link_ipv4ll_enabled(Link *link) {
         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)
-                return false;
-
-        if (!link->network)
-                return false;
-
-        if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan"))
-                return false;
-
-        /* 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 (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) {
@@ -178,7 +160,7 @@ static bool link_ipv6ll_enabled(Link *link) {
         if (!link->network)
                 return false;
 
-        if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "can", "vcan"))
+        if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "can", "vcan", "vxcan", "nlmon"))
                 return false;
 
         if (link->network->bond)
@@ -202,7 +184,7 @@ 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"))
+        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. */
@@ -337,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;
 }
 
@@ -438,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;
@@ -455,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) {
@@ -598,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;
 
@@ -700,14 +680,17 @@ static void link_enter_unmanaged(Link *link) {
         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");
@@ -751,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);
 }
@@ -849,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);
@@ -930,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) {
@@ -977,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) &&
@@ -985,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;
@@ -1210,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) {
@@ -1601,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");
@@ -2200,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--;
 
@@ -2216,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);
         }
 
@@ -2236,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 &&
@@ -2507,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;
@@ -2518,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)
@@ -2534,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)
@@ -2595,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;
@@ -2646,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;
@@ -3286,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;
@@ -3338,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);
@@ -3464,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;