]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-manager.c
network: read link specific sysctl value
[thirdparty/systemd.git] / src / network / networkd-manager.c
index 9075b0a14bd400546e76c10a3538510e1008a6d5..92e3b0a0f12cd3182c94ac4d6aaf348818cd8efb 100644 (file)
@@ -1,10 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <netinet/in.h>
 #include <sys/socket.h>
+#include <unistd.h>
 #include <linux/if.h>
 #include <linux/fib_rules.h>
-#include <stdio_ext.h>
-#include <unistd.h>
 
 #include "sd-daemon.h"
 #include "sd-netlink.h"
@@ -22,6 +22,7 @@
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "networkd-manager.h"
+#include "networkd-speed-meter.h"
 #include "ordered-set.h"
 #include "path-util.h"
 #include "set.h"
@@ -267,7 +268,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
         unsigned char protocol, scope, tos, table, rt_type;
         int family;
         unsigned char dst_prefixlen, src_prefixlen;
-        union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
+        union in_addr_union dst = IN_ADDR_NULL, gw = IN_ADDR_NULL, src = IN_ADDR_NULL, prefsrc = IN_ADDR_NULL;
         Route *route = NULL;
         int r;
 
@@ -478,19 +479,17 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
 }
 
 int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+        _cleanup_free_ char *buf = NULL;
         Manager *m = userdata;
         Link *link = NULL;
         uint16_t type;
-        unsigned char flags;
-        int family;
-        unsigned char prefixlen;
-        unsigned char scope;
-        union in_addr_union in_addr;
+        unsigned char flags, prefixlen, scope;
+        union in_addr_union in_addr = IN_ADDR_NULL;
         struct ifa_cacheinfo cinfo;
         Address *address = NULL;
-        char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
+        char valid_buf[FORMAT_TIMESPAN_MAX];
         const char *valid_str = NULL;
-        int r, ifindex;
+        int ifindex, family, r;
 
         assert(rtnl);
         assert(message);
@@ -578,8 +577,9 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 assert_not_reached("Received unsupported address family");
         }
 
-        if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
-                log_link_warning(link, "Could not print address, ignoring");
+        r = in_addr_to_string(family, &in_addr, &buf);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "Could not print address, ignoring: %m");
                 return 0;
         }
 
@@ -587,12 +587,10 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
         if (r < 0 && r != -ENODATA) {
                 log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
                 return 0;
-        } else if (r >= 0) {
-                if (cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
-                        valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
-                                                    cinfo.ifa_valid * USEC_PER_SEC,
-                                                    USEC_PER_SEC);
-        }
+        } else if (r >= 0 && cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
+                valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
+                                            cinfo.ifa_valid * USEC_PER_SEC,
+                                            USEC_PER_SEC);
 
         (void) address_get(link, family, &in_addr, prefixlen, &address);
 
@@ -729,7 +727,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa
 int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
         uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0, protocol = 0;
         struct fib_rule_port_range sport = {}, dport = {};
-        union in_addr_union to = {}, from = {};
+        union in_addr_union to = IN_ADDR_NULL, from = IN_ADDR_NULL;
         RoutingPolicyRule *rule = NULL;
         uint32_t fwmark = 0, table = 0;
         const char *iif = NULL, *oif = NULL;
@@ -1189,7 +1187,6 @@ static int manager_save(Manager *m) {
         if (r < 0)
                 return r;
 
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
         (void) fchmod(fileno(f), 0644);
 
         fprintf(f,
@@ -1268,20 +1265,10 @@ static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *
         return 0;
 }
 
-static void dhcp6_prefixes_hash_func(const struct in6_addr *addr, struct siphash *state) {
-        assert(addr);
-
-        siphash24_compress(addr, sizeof(*addr), state);
-}
-
-static int dhcp6_prefixes_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
-        return memcmp(a, b, sizeof(*a));
-}
-
-DEFINE_PRIVATE_HASH_OPS(dhcp6_prefixes_hash_ops, struct in6_addr, dhcp6_prefixes_hash_func, dhcp6_prefixes_compare_func);
-
 int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
+        _cleanup_free_ struct in6_addr *a = NULL;
         _cleanup_free_ char *buf = NULL;
+        Link *assigned_link;
         Route *route;
         int r;
 
@@ -1300,11 +1287,27 @@ int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
         (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
         log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
 
-        r = hashmap_ensure_allocated(&m->dhcp6_prefixes, &dhcp6_prefixes_hash_ops);
+        assigned_link = hashmap_get(m->dhcp6_prefixes, addr);
+        if (assigned_link) {
+                assert(assigned_link == link);
+                return 0;
+        }
+
+        a = newdup(struct in6_addr, addr, 1);
+        if (!a)
+                return -ENOMEM;
+
+        r = hashmap_ensure_allocated(&m->dhcp6_prefixes, &in6_addr_hash_ops);
         if (r < 0)
                 return r;
 
-        return hashmap_put(m->dhcp6_prefixes, addr, link);
+        r = hashmap_put(m->dhcp6_prefixes, a, link);
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(a);
+        link_ref(link);
+        return 0;
 }
 
 static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
@@ -1320,21 +1323,21 @@ static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Lin
 }
 
 static int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
+        _cleanup_free_ struct in6_addr *a = NULL;
+        _cleanup_(link_unrefp) Link *l = NULL;
         _cleanup_free_ char *buf = NULL;
         Route *route;
-        Link *l;
         int r;
 
         assert_return(m, -EINVAL);
         assert_return(addr, -EINVAL);
 
-        l = hashmap_remove(m->dhcp6_prefixes, addr);
+        l = hashmap_remove2(m->dhcp6_prefixes, addr, (void **) &a);
         if (!l)
                 return -EINVAL;
 
         (void) sd_radv_remove_prefix(l->radv, addr, 64);
-        r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
-                      0, 0, 0, &route);
+        r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64, 0, 0, 0, &route);
         if (r < 0)
                 return r;
 
@@ -1356,12 +1359,9 @@ int manager_dhcp6_prefix_remove_all(Manager *m, Link *link) {
         assert_return(m, -EINVAL);
         assert_return(link, -EINVAL);
 
-        HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i) {
-                if (l != link)
-                        continue;
-
-                (void) manager_dhcp6_prefix_remove(m, addr);
-        }
+        HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i)
+                if (l == link)
+                        (void) manager_dhcp6_prefix_remove(m, addr);
 
         return 0;
 }
@@ -1370,16 +1370,18 @@ int manager_new(Manager **ret) {
         _cleanup_(manager_freep) Manager *m = NULL;
         int r;
 
-        m = new0(Manager, 1);
+        m = new(Manager, 1);
         if (!m)
                 return -ENOMEM;
 
+        *m = (Manager) {
+                .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
+        };
+
         m->state_file = strdup("/run/systemd/netif/state");
         if (!m->state_file)
                 return -ENOMEM;
 
-        m->sysctl_ipv6_enabled = -1;
-
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -1404,8 +1406,6 @@ int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
-        LIST_HEAD_INIT(m->networks);
-
         r = sd_resolve_default(&m->resolve);
         if (r < 0)
                 return r;
@@ -1428,8 +1428,8 @@ int manager_new(Manager **ret) {
 }
 
 void manager_free(Manager *m) {
+        struct in6_addr *a;
         AddressPool *pool;
-        Network *network;
         Link *link;
 
         if (!m)
@@ -1437,29 +1437,25 @@ void manager_free(Manager *m) {
 
         free(m->state_file);
 
-        sd_netlink_unref(m->rtnl);
-        sd_netlink_unref(m->genl);
-        sd_resolve_unref(m->resolve);
-
-        while ((link = hashmap_first(m->dhcp6_prefixes)))
-                manager_dhcp6_prefix_remove_all(m, link);
+        while ((a = hashmap_first_key(m->dhcp6_prefixes)))
+                (void) manager_dhcp6_prefix_remove(m, a);
         hashmap_free(m->dhcp6_prefixes);
 
         while ((link = hashmap_steal_first(m->links))) {
                 if (link->dhcp6_client)
                         (void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link);
+
+                (void) link_stop_clients(link, true);
+
                 link_unref(link);
         }
 
         m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
-        m->links = hashmap_free(m->links);
-        m->links_requesting_uuid = set_free(m->links_requesting_uuid);
-        set_free(m->duids_requesting_uuid);
+        m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
+        m->links = hashmap_free_with_destructor(m->links, link_unref);
 
-        while ((network = m->networks))
-                network_free(network);
-
-        hashmap_free(m->networks_by_name);
+        m->duids_requesting_uuid = set_free(m->duids_requesting_uuid);
+        m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
 
         m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
 
@@ -1472,6 +1468,11 @@ void manager_free(Manager *m) {
         m->rules_foreign = set_free_with_destructor(m->rules_foreign, routing_policy_rule_free);
         set_free_with_destructor(m->rules_saved, routing_policy_rule_free);
 
+        sd_netlink_unref(m->rtnl);
+        sd_netlink_unref(m->genl);
+        sd_resolve_unref(m->resolve);
+
+        sd_event_source_unref(m->speed_meter_event_source);
         sd_event_unref(m->event);
 
         sd_device_monitor_unref(m->device_monitor);
@@ -1487,9 +1488,14 @@ void manager_free(Manager *m) {
 int manager_start(Manager *m) {
         Link *link;
         Iterator i;
+        int r;
 
         assert(m);
 
+        r = manager_start_speed_meter(m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize speed meter: %m");
+
         /* The dirty handler will deal with future serialization, but the first one
            must be done explicitly. */
 
@@ -1878,18 +1884,3 @@ int manager_request_product_uuid(Manager *m, Link *link) {
 
         return 0;
 }
-
-int manager_sysctl_ipv6_enabled(Manager *manager) {
-        _cleanup_free_ char *value = NULL;
-        int r;
-
-        if (manager->sysctl_ipv6_enabled >= 0)
-                return manager->sysctl_ipv6_enabled;
-
-        r = sysctl_read_ip_property(AF_INET6, "all", "disable_ipv6", &value);
-        if (r < 0)
-                return log_warning_errno(r, "Failed to read net.ipv6.conf.all.disable_ipv6 sysctl property: %m");
-
-        manager->sysctl_ipv6_enabled = value[0] == '0';
-        return manager->sysctl_ipv6_enabled;
-}