]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-link.c
Merge pull request #7388 from keszybz/doc-tweak
[thirdparty/systemd.git] / src / network / networkd-link.c
index 0c1229336b87c8d4b8db7e106ef504e2d68f0af1..9cd221eb427406669e0fd2bc2f6fff4610c84736 100644 (file)
@@ -32,6 +32,8 @@
 #include "networkd-lldp-tx.h"
 #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"
@@ -119,6 +121,15 @@ static bool link_ipv6_enabled(Link *link) {
         return link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network);
 }
 
+static bool link_radv_enabled(Link *link) {
+        assert(link);
+
+        if (!link_ipv6ll_enabled(link))
+                return false;
+
+        return link->network->router_prefix_delegation;
+}
+
 static bool link_lldp_rx_enabled(Link *link) {
         assert(link);
 
@@ -131,7 +142,10 @@ static bool link_lldp_rx_enabled(Link *link) {
         if (!link->network)
                 return false;
 
-        if (link->network->bridge)
+        /* 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;
@@ -212,6 +226,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.
@@ -484,8 +501,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
 
 static void link_free(Link *link) {
         Address *address;
-        Iterator i;
         Link *carrier;
+        Iterator i;
 
         if (!link)
                 return;
@@ -521,6 +538,7 @@ static void link_free(Link *link) {
         sd_ipv4ll_unref(link->ipv4ll);
         sd_dhcp6_client_unref(link->dhcp6_client);
         sd_ndisc_unref(link->ndisc);
+        sd_radv_unref(link->radv);
 
         if (link->manager)
                 hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
@@ -640,6 +658,12 @@ static int link_stop_clients(Link *link) {
                         r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
         }
 
+        if (link->radv) {
+                k = sd_radv_stop(link->radv);
+                if (k < 0)
+                        r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
+        }
+
         link_lldp_emit_stop(link);
         return r;
 }
@@ -853,6 +877,35 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
         return 1;
 }
 
+static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        _cleanup_link_unref_ Link *link = userdata;
+        int r;
+
+        assert(rtnl);
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+        assert(link->link_messages > 0);
+
+        link->link_messages--;
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -EEXIST)
+                log_link_warning_errno(link, r, "could not set address label: %m");
+        else if (r >= 0)
+                manager_rtnl_process_address(rtnl, m, link->manager);
+
+        if (link->link_messages == 0) {
+                log_link_debug(link, "Addresses label set");
+                link_enter_set_routes(link);
+        }
+
+        return 1;
+}
+
 static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
         _cleanup_free_ struct in_addr *addresses = NULL;
         size_t n_addresses = 0, n_allocated = 0;
@@ -965,6 +1018,8 @@ static int link_set_bridge_fdb(Link *link) {
 }
 
 static int link_enter_set_addresses(Link *link) {
+        RoutingPolicyRule *rule, *rrule = NULL;
+        AddressLabel *label;
         Address *ad;
         int r;
 
@@ -989,6 +1044,37 @@ static int link_enter_set_addresses(Link *link) {
                 link->link_messages++;
         }
 
+        LIST_FOREACH(labels, label, link->network->address_labels) {
+                r = address_label_configure(label, link, address_label_handler, false);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "Could not set address label: %m");
+                        link_enter_failed(link);
+                        return r;
+                }
+
+                link->link_messages++;
+        }
+
+        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, &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->link_messages++;
+        }
+
+        routing_policy_rule_purge(link->manager, link);
+
         /* now that we can figure out a default address for the dhcp server,
            start it */
         if (link_dhcp4_server_enabled(link)) {
@@ -1325,6 +1411,11 @@ static int link_set_bridge(Link *link) {
                 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");
+        }
 
         r = sd_netlink_message_close_container(req);
         if (r < 0)
@@ -1508,6 +1599,17 @@ static int link_acquire_ipv6_conf(Link *link) {
                         return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
         }
 
+        if (link_radv_enabled(link)) {
+                assert(link->radv);
+                assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
+
+                log_link_debug(link, "Starting IPv6 Router Advertisements");
+
+                r = sd_radv_start(link->radv);
+                if (r < 0 && r != -EBUSY)
+                        return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m");
+        }
+
         return 0;
 }
 
@@ -1598,7 +1700,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
         return 1;
 }
 
-static int link_up(Link *link) {
+int link_up(Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         uint8_t ipv6ll_mode;
         int r;
@@ -1719,7 +1821,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user
         return 1;
 }
 
-static int link_down(Link *link) {
+int link_down(Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -2058,6 +2160,12 @@ static int link_joined(Link *link) {
                         log_link_error_errno(link, r, "Could not set bridge vlan: %m");
         }
 
+        /* Skip setting up addresses until it gets carrier,
+           or it would try to set addresses twice,
+           which is bad for non-idempotent steps. */
+        if (!link_has_carrier(link) && !link->network->configure_without_carrier)
+                return 0;
+
         return link_enter_set_addresses(link);
 }
 
@@ -2366,7 +2474,7 @@ static int link_drop_foreign_config(Link *link) {
 }
 
 static int link_drop_config(Link *link) {
-        Address *address;
+        Address *address, *pool_address;
         Route *route;
         Iterator i;
         int r;
@@ -2379,6 +2487,15 @@ static int link_drop_config(Link *link) {
                 r = address_remove(address, link, link_address_remove_handler);
                 if (r < 0)
                         return r;
+
+                /* If this address came from an address pool, clean up the pool */
+                LIST_FOREACH(addresses, pool_address, link->pool_addresses) {
+                        if (address_equal(address, pool_address)) {
+                                LIST_REMOVE(addresses, link->pool_addresses, pool_address);
+                                address_free(pool_address);
+                                break;
+                        }
+                }
         }
 
         SET_FOREACH(route, link->routes, i) {
@@ -2516,6 +2633,12 @@ static int link_configure(Link *link) {
                         return r;
         }
 
+        if (link_radv_enabled(link)) {
+                r = radv_configure(link);
+                if (r < 0)
+                        return r;
+        }
+
         if (link_lldp_rx_enabled(link)) {
                 r = sd_lldp_new(&link->lldp);
                 if (r < 0)
@@ -2549,7 +2672,7 @@ static int link_configure(Link *link) {
                         return r;
         }
 
-        if (link_has_carrier(link)) {
+        if (link_has_carrier(link) || link->network->configure_without_carrier) {
                 r = link_acquire_conf(link);
                 if (r < 0)
                         return r;
@@ -2818,7 +2941,7 @@ network_file_fail:
                         goto dhcp4_address_fail;
                 }
 
-                r = sd_dhcp_client_new(&link->dhcp_client);
+                r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Failed to create DHCPv4 client: %m");
 
@@ -2962,6 +3085,9 @@ static int link_carrier_lost(Link *link) {
                 return r;
         }
 
+        if (link_dhcp4_server_enabled(link))
+                (void) sd_dhcp_server_stop(link->dhcp_server);
+
         r = link_drop_config(link);
         if (r < 0)
                 return r;
@@ -3023,7 +3149,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);
 
@@ -3052,6 +3178,12 @@ int link_update(Link *link, sd_netlink_message *m) {
                                 return r;
                         }
                 }
+
+                if (link->radv) {
+                        r = sd_radv_set_mtu(link->radv, link->mtu);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not set MTU for Router Advertisement: %m");
+                }
         }
 
         /* The kernel may broadcast NEWLINK messages without the MAC address
@@ -3080,8 +3212,6 @@ int link_update(Link *link, sd_netlink_message *m) {
                         }
 
                         if (link->dhcp_client) {
-                                const DUID *duid = link_duid(link);
-
                                 r = sd_dhcp_client_set_mac(link->dhcp_client,
                                                            (const uint8_t *) &link->mac,
                                                            sizeof (link->mac),
@@ -3089,13 +3219,30 @@ int link_update(Link *link, sd_netlink_message *m) {
                                 if (r < 0)
                                         return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
 
-                                r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
-                                                                 link->network->iaid,
-                                                                 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/IAID in DHCP client: %m");
+                                switch (link->network->dhcp_client_identifier) {
+                                case DHCP_CLIENT_ID_DUID: {
+                                        const DUID *duid = link_duid(link);
+
+                                        r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+                                                                         link->network->iaid,
+                                                                         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/IAID 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)
+                                                return log_link_warning_errno(link, r, "Could not update MAC client id in DHCP client: %m");
+                                        break;
+                                default:
+                                        assert_not_reached("Unknown client identifier type.");
+                                }
                         }
 
                         if (link->dhcp6_client) {
@@ -3120,6 +3267,12 @@ int link_update(Link *link, sd_netlink_message *m) {
                                 if (r < 0)
                                         return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
                         }
+
+                        if (link->radv) {
+                                r = sd_radv_set_mac(link->radv, &link->mac);
+                                if (r < 0)
+                                        return log_link_warning_errno(link, r, "Could not update MAC for Router Advertisement: %m");
+                        }
                 }
         }
 
@@ -3164,16 +3317,16 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
         if (hashmap_isempty(h))
                 return;
 
-        fputs(prefix, f);
+        fputs_unlocked(prefix, f);
         HASHMAP_FOREACH(link, h, i) {
                 if (space)
-                        fputc(' ', f);
+                        fputc_unlocked(' ', f);
 
                 fprintf(f, "%i", link->ifindex);
                 space = true;
         }
 
-        fputc('\n', f);
+        fputc_unlocked('\n', f);
 }
 
 int link_save(Link *link) {
@@ -3220,6 +3373,7 @@ int link_save(Link *link) {
                 sd_dhcp6_lease *dhcp6_lease = NULL;
                 const char *dhcp_domainname = NULL;
                 char **dhcp6_domains = NULL;
+                char **dhcp_domains = NULL;
                 unsigned j;
 
                 if (link->dhcp6_client) {
@@ -3230,7 +3384,7 @@ int link_save(Link *link) {
 
                 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
 
-                fputs("DNS=", f);
+                fputs_unlocked("DNS=", f);
                 space = false;
 
                 for (j = 0; j < link->network->n_dns; j++) {
@@ -3244,8 +3398,8 @@ int link_save(Link *link) {
                         }
 
                         if (space)
-                                fputc(' ', f);
-                        fputs(b, f);
+                                fputc_unlocked(' ', f);
+                        fputs_unlocked(b, f);
                         space = true;
                 }
 
@@ -3256,7 +3410,7 @@ int link_save(Link *link) {
                         r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
                         if (r > 0) {
                                 if (space)
-                                        fputc(' ', f);
+                                        fputc_unlocked(' ', f);
                                 serialize_in_addrs(f, addresses, r);
                                 space = true;
                         }
@@ -3268,7 +3422,7 @@ int link_save(Link *link) {
                         r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
                         if (r > 0) {
                                 if (space)
-                                        fputc(' ', f);
+                                        fputc_unlocked(' ', f);
                                 serialize_in6_addrs(f, in6_addrs, r);
                                 space = true;
                         }
@@ -3282,16 +3436,16 @@ int link_save(Link *link) {
 
                         SET_FOREACH(dd, link->ndisc_rdnss, i) {
                                 if (space)
-                                        fputc(' ', f);
+                                        fputc_unlocked(' ', f);
 
                                 serialize_in6_addrs(f, &dd->address, 1);
                                 space = true;
                         }
                 }
 
-                fputc('\n', f);
+                fputc_unlocked('\n', f);
 
-                fputs("NTP=", f);
+                fputs_unlocked("NTP=", f);
                 space = false;
                 fputstrv(f, link->network->ntp, NULL, &space);
 
@@ -3302,7 +3456,7 @@ int link_save(Link *link) {
                         r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
                         if (r > 0) {
                                 if (space)
-                                        fputc(' ', f);
+                                        fputc_unlocked(' ', f);
                                 serialize_in_addrs(f, addresses, r);
                                 space = true;
                         }
@@ -3316,7 +3470,7 @@ int link_save(Link *link) {
                                                          &in6_addrs);
                         if (r > 0) {
                                 if (space)
-                                        fputc(' ', f);
+                                        fputc_unlocked(' ', f);
                                 serialize_in6_addrs(f, in6_addrs, r);
                                 space = true;
                         }
@@ -3326,16 +3480,19 @@ int link_save(Link *link) {
                                 fputstrv(f, hosts, NULL, &space);
                 }
 
-                fputc('\n', f);
+                fputc_unlocked('\n', f);
 
                 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
-                        if (link->dhcp_lease)
+                        if (link->dhcp_lease) {
                                 (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
+                                (void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
+                        }
                         if (dhcp6_lease)
                                 (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
                 }
 
-                fputs("DOMAINS=", f);
+                fputs_unlocked("DOMAINS=", f);
+                space = false;
                 fputstrv(f, link->network->search_domains, NULL, &space);
 
                 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
@@ -3343,6 +3500,8 @@ int link_save(Link *link) {
 
                         if (dhcp_domainname)
                                 fputs_with_space(f, dhcp_domainname, NULL, &space);
+                        if (dhcp_domains)
+                                fputstrv(f, dhcp_domains, NULL, &space);
                         if (dhcp6_domains)
                                 fputstrv(f, dhcp6_domains, NULL, &space);
 
@@ -3350,16 +3509,19 @@ int link_save(Link *link) {
                                 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
                 }
 
-                fputc('\n', f);
+                fputc_unlocked('\n', f);
 
-                fputs("ROUTE_DOMAINS=", f);
-                fputstrv(f, link->network->route_domains, NULL, NULL);
+                fputs_unlocked("ROUTE_DOMAINS=", f);
+                space = false;
+                fputstrv(f, link->network->route_domains, NULL, &space);
 
                 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
                         NDiscDNSSL *dd;
 
                         if (dhcp_domainname)
                                 fputs_with_space(f, dhcp_domainname, NULL, &space);
+                        if (dhcp_domains)
+                                fputstrv(f, dhcp_domains, NULL, &space);
                         if (dhcp6_domains)
                                 fputstrv(f, dhcp6_domains, NULL, &space);
 
@@ -3367,7 +3529,7 @@ int link_save(Link *link) {
                                 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
                 }
 
-                fputc('\n', f);
+                fputc_unlocked('\n', f);
 
                 fprintf(f, "LLMNR=%s\n",
                         resolve_support_to_string(link->network->llmnr));
@@ -3381,14 +3543,14 @@ int link_save(Link *link) {
                 if (!set_isempty(link->network->dnssec_negative_trust_anchors)) {
                         const char *n;
 
-                        fputs("DNSSEC_NTA=", f);
+                        fputs_unlocked("DNSSEC_NTA=", f);
                         space = false;
                         SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i)
                                 fputs_with_space(f, n, NULL, &space);
-                        fputc('\n', f);
+                        fputc_unlocked('\n', f);
                 }
 
-                fputs("ADDRESSES=", f);
+                fputs_unlocked("ADDRESSES=", f);
                 space = false;
                 SET_FOREACH(a, link->addresses, i) {
                         _cleanup_free_ char *address_str = NULL;
@@ -3400,9 +3562,9 @@ int link_save(Link *link) {
                         fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
                         space = true;
                 }
-                fputc('\n', f);
+                fputc_unlocked('\n', f);
 
-                fputs("ROUTES=", f);
+                fputs_unlocked("ROUTES=", f);
                 space = false;
                 SET_FOREACH(route, link->routes, i) {
                         _cleanup_free_ char *route_str = NULL;
@@ -3411,12 +3573,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('\n', f);
+                fputc_unlocked('\n', f);
         }
 
         print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
@@ -3434,9 +3597,9 @@ int link_save(Link *link) {
 
                 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
                 if (r >= 0) {
-                        fputs("DHCP4_ADDRESS=", f);
+                        fputs_unlocked("DHCP4_ADDRESS=", f);
                         serialize_in_addrs(f, &address, 1);
-                        fputc('\n', f);
+                        fputc_unlocked('\n', f);
                 }
 
                 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
@@ -3454,9 +3617,9 @@ int link_save(Link *link) {
 
                 r = sd_ipv4ll_get_address(link->ipv4ll, &address);
                 if (r >= 0) {
-                        fputs("IPV4LL_ADDRESS=", f);
+                        fputs_unlocked("IPV4LL_ADDRESS=", f);
                         serialize_in_addrs(f, &address, 1);
-                        fputc('\n', f);
+                        fputc_unlocked('\n', f);
                 }
         }