]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-link.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / network / networkd-link.c
index 2fb1dd67abec7459910db3cfd0251f45cf51940b..fa72023c16a61847f466b9a628b63aa7f763a6fe 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
@@ -20,6 +21,7 @@
 #include <netinet/ether.h>
 #include <linux/if.h>
 #include <unistd.h>
+#include <stdio_ext.h>
 
 #include "alloc-util.h"
 #include "bus-util.h"
@@ -33,6 +35,7 @@
 #include "networkd-manager.h"
 #include "networkd-ndisc.h"
 #include "networkd-radv.h"
+#include "networkd-routing-policy-rule.h"
 #include "set.h"
 #include "socket-util.h"
 #include "stdio-util.h"
@@ -89,6 +92,9 @@ static bool link_ipv4ll_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (streq_ptr(link->kind, "wireguard"))
+                return false;
+
         return link->network->link_local & ADDRESS_FAMILY_IPV4;
 }
 
@@ -104,6 +110,9 @@ static bool link_ipv6ll_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (streq_ptr(link->kind, "wireguard"))
+                return false;
+
         return link->network->link_local & ADDRESS_FAMILY_IPV6;
 }
 
@@ -126,7 +135,7 @@ static bool link_radv_enabled(Link *link) {
         if (!link_ipv6ll_enabled(link))
                 return false;
 
-        return link->network->router_prefix_delegation;
+        return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE;
 }
 
 static bool link_lldp_rx_enabled(Link *link) {
@@ -225,6 +234,9 @@ static bool link_ipv6_accept_ra_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (!link_ipv6ll_enabled(link))
+                return false;
+
         /* If unset use system default (enabled if local forwarding is disabled.
          * disabled if local forwarding is enabled).
          * If set, ignore or enforce RA independent of local forwarding state.
@@ -489,16 +501,15 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
         if (r < 0)
                 return r;
 
-        *ret = link;
-        link = NULL;
+        *ret = TAKE_PTR(link);
 
         return 0;
 }
 
 static void link_free(Link *link) {
         Address *address;
-        Iterator i;
         Link *carrier;
+        Iterator i;
 
         if (!link)
                 return;
@@ -734,7 +745,10 @@ void link_check_ready(Link *link) {
         if (!link->network)
                 return;
 
-        if (!link->static_configured)
+        if (!link->static_routes_configured)
+                return;
+
+        if (!link->routing_policy_rules_configured)
                 return;
 
         if (link_ipv4ll_enabled(link))
@@ -742,20 +756,23 @@ void link_check_ready(Link *link) {
                     !link->ipv4ll_route)
                         return;
 
-        if (link_ipv6ll_enabled(link))
-                if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
-                        return;
+        if (!link->network->bridge) {
 
-        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_ipv6ll_enabled(link))
+                        if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
+                                return;
 
-        if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
-                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))
@@ -767,16 +784,51 @@ void link_check_ready(Link *link) {
         return;
 }
 
+static int link_set_routing_policy_rule(Link *link) {
+        RoutingPolicyRule *rule, *rrule = NULL;
+        int r;
+
+        assert(link);
+        assert(link->network);
+
+        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, &rrule);
+                if (r == 1) {
+                        (void) routing_policy_rule_make_local(link->manager, rrule);
+                        continue;
+                }
+
+                r = routing_policy_rule_configure(rule, link, link_routing_policy_rule_handler, false);
+                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++;
+        }
+
+        routing_policy_rule_purge(link->manager, link);
+        if (link->routing_policy_rule_messages == 0) {
+                link->routing_policy_rules_configured = true;
+                link_check_ready(link);
+        } else
+                log_link_debug(link, "Setting routing policy rules");
+
+        return 0;
+}
+
 static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
-        assert(link->link_messages > 0);
+        assert(link->route_messages > 0);
         assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
                       LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
                       LINK_STATE_LINGER));
 
-        link->link_messages--;
+        link->route_messages--;
 
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
@@ -785,9 +837,9 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
         if (r < 0 && r != -EEXIST)
                 log_link_warning_errno(link, r, "Could not set route: %m");
 
-        if (link->link_messages == 0) {
+        if (link->route_messages == 0) {
                 log_link_debug(link, "Routes set");
-                link->static_configured = true;
+                link->static_routes_configured = true;
                 link_check_ready(link);
         }
 
@@ -802,6 +854,8 @@ static int link_enter_set_routes(Link *link) {
         assert(link->network);
         assert(link->state == LINK_STATE_SETTING_ADDRESSES);
 
+        (void) link_set_routing_policy_rule(link);
+
         link_set_state(link, LINK_STATE_SETTING_ROUTES);
 
         LIST_FOREACH(routes, rt, link->network->static_routes) {
@@ -812,11 +866,11 @@ static int link_enter_set_routes(Link *link) {
                         return r;
                 }
 
-                link->link_messages++;
+                link->route_messages++;
         }
 
-        if (link->link_messages == 0) {
-                link->static_configured = true;
+        if (link->route_messages == 0) {
+                link->static_routes_configured = true;
                 link_check_ready(link);
         } else
                 log_link_debug(link, "Setting routes");
@@ -850,11 +904,11 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
         assert(m);
         assert(link);
         assert(link->ifname);
-        assert(link->link_messages > 0);
+        assert(link->address_messages > 0);
         assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
                LINK_STATE_FAILED, LINK_STATE_LINGER));
 
-        link->link_messages--;
+        link->address_messages--;
 
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
@@ -865,7 +919,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
         else if (r >= 0)
                 manager_rtnl_process_address(rtnl, m, link->manager);
 
-        if (link->link_messages == 0) {
+        if (link->address_messages == 0) {
                 log_link_debug(link, "Addresses set");
                 link_enter_set_routes(link);
         }
@@ -881,9 +935,9 @@ static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, void *
         assert(m);
         assert(link);
         assert(link->ifname);
-        assert(link->link_messages > 0);
+        assert(link->address_label_messages > 0);
 
-        link->link_messages--;
+        link->address_label_messages--;
 
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
@@ -894,10 +948,8 @@ static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, void *
         else if (r >= 0)
                 manager_rtnl_process_address(rtnl, m, link->manager);
 
-        if (link->link_messages == 0) {
+        if (link->address_label_messages == 0)
                 log_link_debug(link, "Addresses label set");
-                link_enter_set_routes(link);
-        }
 
         return 1;
 }
@@ -1036,7 +1088,7 @@ static int link_enter_set_addresses(Link *link) {
                         return r;
                 }
 
-                link->link_messages++;
+                link->address_messages++;
         }
 
         LIST_FOREACH(labels, label, link->network->address_labels) {
@@ -1047,7 +1099,7 @@ static int link_enter_set_addresses(Link *link) {
                         return r;
                 }
 
-                link->link_messages++;
+                link->address_label_messages++;
         }
 
         /* now that we can figure out a default address for the dhcp server,
@@ -1170,7 +1222,7 @@ static int link_enter_set_addresses(Link *link) {
                 log_link_debug(link, "Offering DHCPv4 leases");
         }
 
-        if (link->link_messages == 0)
+        if (link->address_messages == 0)
                 link_enter_set_routes(link);
         else
                 log_link_debug(link, "Setting addresses");
@@ -1278,6 +1330,8 @@ int link_set_mtu(Link *link, uint32_t mtu) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
+        link->setting_mtu = true;
+
         link_ref(link);
 
         return 0;
@@ -1624,6 +1678,11 @@ static int link_acquire_conf(Link *link) {
 
         assert(link);
 
+        if (link->setting_mtu) {
+                link->setting_mtu = false;
+                return 0;
+        }
+
         r = link_acquire_ipv4_conf(link);
         if (r < 0)
                 return r;
@@ -2254,6 +2313,11 @@ static int link_enter_join_netdev(Link *link) {
 
         HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
 
+                if (netdev->ifindex > 0) {
+                        link_joined(link);
+                        continue;
+                }
+
                 log_struct(LOG_DEBUG,
                            LOG_LINK_INTERFACE(link),
                            LOG_NETDEV_INTERFACE(netdev),
@@ -2580,6 +2644,10 @@ static int link_configure(Link *link) {
         }
 
         if (link_dhcp4_enabled(link)) {
+                r = dhcp4_set_promote_secondaries(link);
+                if (r < 0)
+                        return r;
+
                 r = dhcp4_configure(link);
                 if (r < 0)
                         return r;
@@ -2748,7 +2816,7 @@ int link_initialized(Link *link, struct udev_device *device) {
                 return r;
 
         r = sd_netlink_call_async(link->manager->rtnl, req,
-                               link_initialized_and_synced, link, 0, NULL);
+                                  link_initialized_and_synced, link, 0, NULL);
         if (r < 0)
                 return r;
 
@@ -2895,7 +2963,7 @@ network_file_fail:
                         if (r < 0)
                                 return log_link_error_errno(link, r, "Failed to add route: %m");
 
-                        if (lifetime != USEC_INFINITY) {
+                        if (lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
                                 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
                                                       0, route_expire_handler, route);
                                 if (r < 0)
@@ -2904,8 +2972,7 @@ network_file_fail:
 
                         route->lifetime = lifetime;
                         sd_event_source_unref(route->expire);
-                        route->expire = expire;
-                        expire = NULL;
+                        route->expire = TAKE_PTR(expire);
                 }
         }
 
@@ -3054,13 +3121,20 @@ static int link_carrier_lost(Link *link) {
 
         assert(link);
 
+        /* Some devices reset itself while setting the MTU. This causes the DHCP client fall into a loop.
+           setting_mtu keep track whether the device got reset because of setting MTU and does not drop the
+           configuration and stop the clients as well. */
+        if (link->setting_mtu)
+                return 0;
+
         r = link_stop_clients(link);
         if (r < 0) {
                 link_enter_failed(link);
                 return r;
         }
 
-        (void) sd_dhcp_server_stop(link->dhcp_server);
+        if (link_dhcp4_server_enabled(link))
+                (void) sd_dhcp_server_stop(link->dhcp_server);
 
         r = link_drop_config(link);
         if (r < 0)
@@ -3123,7 +3197,7 @@ int link_update(Link *link, sd_netlink_message *m) {
 
         r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname);
         if (r >= 0 && !streq(ifname, link->ifname)) {
-                log_link_info(link, "Renamed to %s", ifname);
+                log_link_info(link, "Interface name change detected, %s has been renamed to %s.", link->ifname, ifname);
 
                 link_free_carrier_maps(link);
 
@@ -3206,12 +3280,23 @@ int link_update(Link *link, sd_netlink_message *m) {
                                                 return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
                                         break;
                                 }
+                                case DHCP_CLIENT_ID_DUID_ONLY: {
+                                        const DUID *duid = link_duid(link);
+
+                                        r = sd_dhcp_client_set_duid(link->dhcp_client,
+                                                                    duid->type,
+                                                                    duid->raw_data_len > 0 ? duid->raw_data : NULL,
+                                                                    duid->raw_data_len);
+                                        if (r < 0)
+                                                return log_link_warning_errno(link, r, "Could not update DUID in DHCP client: %m");
+                                        break;
+                                }
                                 case DHCP_CLIENT_ID_MAC:
                                         r = sd_dhcp_client_set_client_id(link->dhcp_client,
                                                                          ARPHRD_ETHER,
                                                                          (const uint8_t *)&link->mac,
                                                                          sizeof(link->mac));
-                                        if(r < 0)
+                                        if (r < 0)
                                                 return log_link_warning_errno(link, r, "Could not update MAC client id in DHCP client: %m");
                                         break;
                                 default:
@@ -3247,6 +3332,12 @@ int link_update(Link *link, sd_netlink_message *m) {
                                 if (r < 0)
                                         return log_link_warning_errno(link, r, "Could not update MAC for Router Advertisement: %m");
                         }
+
+                        if (link->ndisc) {
+                                r = sd_ndisc_set_mac(link->ndisc, &link->mac);
+                                if (r < 0)
+                                        return log_link_warning_errno(link, r, "Could not update MAC for ndisc: %m");
+                        }
                 }
         }
 
@@ -3291,16 +3382,16 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
         if (hashmap_isempty(h))
                 return;
 
-        fputs_unlocked(prefix, f);
+        fputs(prefix, f);
         HASHMAP_FOREACH(link, h, i) {
                 if (space)
-                        fputc_unlocked(' ', f);
+                        fputc(' ', f);
 
                 fprintf(f, "%i", link->ifindex);
                 space = true;
         }
 
-        fputc_unlocked('\n', f);
+        fputc('\n', f);
 }
 
 int link_save(Link *link) {
@@ -3334,6 +3425,7 @@ int link_save(Link *link) {
         if (r < 0)
                 goto fail;
 
+        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
         (void) fchmod(fileno(f), 0644);
 
         fprintf(f,
@@ -3350,6 +3442,9 @@ int link_save(Link *link) {
                 char **dhcp_domains = NULL;
                 unsigned j;
 
+                fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
+                        yes_no(link->network->required_for_online));
+
                 if (link->dhcp6_client) {
                         r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
                         if (r < 0 && r != -ENOMSG)
@@ -3358,7 +3453,7 @@ int link_save(Link *link) {
 
                 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
 
-                fputs_unlocked("DNS=", f);
+                fputs("DNS=", f);
                 space = false;
 
                 for (j = 0; j < link->network->n_dns; j++) {
@@ -3372,8 +3467,8 @@ int link_save(Link *link) {
                         }
 
                         if (space)
-                                fputc_unlocked(' ', f);
-                        fputs_unlocked(b, f);
+                                fputc(' ', f);
+                        fputs(b, f);
                         space = true;
                 }
 
@@ -3384,7 +3479,7 @@ int link_save(Link *link) {
                         r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
                         if (r > 0) {
                                 if (space)
-                                        fputc_unlocked(' ', f);
+                                        fputc(' ', f);
                                 serialize_in_addrs(f, addresses, r);
                                 space = true;
                         }
@@ -3396,7 +3491,7 @@ int link_save(Link *link) {
                         r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
                         if (r > 0) {
                                 if (space)
-                                        fputc_unlocked(' ', f);
+                                        fputc(' ', f);
                                 serialize_in6_addrs(f, in6_addrs, r);
                                 space = true;
                         }
@@ -3410,16 +3505,16 @@ int link_save(Link *link) {
 
                         SET_FOREACH(dd, link->ndisc_rdnss, i) {
                                 if (space)
-                                        fputc_unlocked(' ', f);
+                                        fputc(' ', f);
 
                                 serialize_in6_addrs(f, &dd->address, 1);
                                 space = true;
                         }
                 }
 
-                fputc_unlocked('\n', f);
+                fputc('\n', f);
 
-                fputs_unlocked("NTP=", f);
+                fputs("NTP=", f);
                 space = false;
                 fputstrv(f, link->network->ntp, NULL, &space);
 
@@ -3430,7 +3525,7 @@ int link_save(Link *link) {
                         r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
                         if (r > 0) {
                                 if (space)
-                                        fputc_unlocked(' ', f);
+                                        fputc(' ', f);
                                 serialize_in_addrs(f, addresses, r);
                                 space = true;
                         }
@@ -3444,7 +3539,7 @@ int link_save(Link *link) {
                                                          &in6_addrs);
                         if (r > 0) {
                                 if (space)
-                                        fputc_unlocked(' ', f);
+                                        fputc(' ', f);
                                 serialize_in6_addrs(f, in6_addrs, r);
                                 space = true;
                         }
@@ -3454,7 +3549,7 @@ int link_save(Link *link) {
                                 fputstrv(f, hosts, NULL, &space);
                 }
 
-                fputc_unlocked('\n', f);
+                fputc('\n', f);
 
                 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
                         if (link->dhcp_lease) {
@@ -3465,7 +3560,7 @@ int link_save(Link *link) {
                                 (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
                 }
 
-                fputs_unlocked("DOMAINS=", f);
+                fputs("DOMAINS=", f);
                 space = false;
                 fputstrv(f, link->network->search_domains, NULL, &space);
 
@@ -3483,9 +3578,9 @@ int link_save(Link *link) {
                                 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
                 }
 
-                fputc_unlocked('\n', f);
+                fputc('\n', f);
 
-                fputs_unlocked("ROUTE_DOMAINS=", f);
+                fputs("ROUTE_DOMAINS=", f);
                 space = false;
                 fputstrv(f, link->network->route_domains, NULL, &space);
 
@@ -3503,7 +3598,7 @@ int link_save(Link *link) {
                                 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
                 }
 
-                fputc_unlocked('\n', f);
+                fputc('\n', f);
 
                 fprintf(f, "LLMNR=%s\n",
                         resolve_support_to_string(link->network->llmnr));
@@ -3517,14 +3612,14 @@ int link_save(Link *link) {
                 if (!set_isempty(link->network->dnssec_negative_trust_anchors)) {
                         const char *n;
 
-                        fputs_unlocked("DNSSEC_NTA=", f);
+                        fputs("DNSSEC_NTA=", f);
                         space = false;
                         SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i)
                                 fputs_with_space(f, n, NULL, &space);
-                        fputc_unlocked('\n', f);
+                        fputc('\n', f);
                 }
 
-                fputs_unlocked("ADDRESSES=", f);
+                fputs("ADDRESSES=", f);
                 space = false;
                 SET_FOREACH(a, link->addresses, i) {
                         _cleanup_free_ char *address_str = NULL;
@@ -3536,9 +3631,9 @@ int link_save(Link *link) {
                         fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
                         space = true;
                 }
-                fputc_unlocked('\n', f);
+                fputc('\n', f);
 
-                fputs_unlocked("ROUTES=", f);
+                fputs("ROUTES=", f);
                 space = false;
                 SET_FOREACH(route, link->routes, i) {
                         _cleanup_free_ char *route_str = NULL;
@@ -3547,12 +3642,13 @@ int link_save(Link *link) {
                         if (r < 0)
                                 goto fail;
 
-                        fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str,
+                        fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT,
+                                space ? " " : "", route_str,
                                 route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
                         space = true;
                 }
 
-                fputc_unlocked('\n', f);
+                fputc('\n', f);
         }
 
         print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
@@ -3570,9 +3666,9 @@ int link_save(Link *link) {
 
                 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
                 if (r >= 0) {
-                        fputs_unlocked("DHCP4_ADDRESS=", f);
+                        fputs("DHCP4_ADDRESS=", f);
                         serialize_in_addrs(f, &address, 1);
-                        fputc_unlocked('\n', f);
+                        fputc('\n', f);
                 }
 
                 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
@@ -3590,9 +3686,9 @@ int link_save(Link *link) {
 
                 r = sd_ipv4ll_get_address(link->ipv4ll, &address);
                 if (r >= 0) {
-                        fputs_unlocked("IPV4LL_ADDRESS=", f);
+                        fputs("IPV4LL_ADDRESS=", f);
                         serialize_in_addrs(f, &address, 1);
-                        fputc_unlocked('\n', f);
+                        fputc('\n', f);
                 }
         }