]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-manager.c
Merge pull request #12762 from yuwata/network-introduce-carrier-and-network-state...
[thirdparty/systemd.git] / src / network / networkd-manager.c
index de177e6d1abfa9e80d72a4eed5f519fbc97ec3c1..d80f93b3d22c822fa32516ebe8191a5c191b37e2 100644 (file)
@@ -21,7 +21,9 @@
 #include "local-addresses.h"
 #include "netlink-util.h"
 #include "network-internal.h"
+#include "networkd-link-bus.h"
 #include "networkd-manager.h"
+#include "networkd-speed-meter.h"
 #include "ordered-set.h"
 #include "path-util.h"
 #include "set.h"
@@ -724,15 +726,12 @@ 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 = IN_ADDR_NULL, from = IN_ADDR_NULL;
+        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
         RoutingPolicyRule *rule = NULL;
-        uint32_t fwmark = 0, table = 0;
         const char *iif = NULL, *oif = NULL;
         Manager *m = userdata;
+        unsigned flags;
         uint16_t type;
-        int family;
         int r;
 
         assert(rtnl);
@@ -756,35 +755,41 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
                 return 0;
         }
 
-        r = sd_rtnl_message_get_family(message, &family);
+        r = routing_policy_rule_new(&tmp);
+        if (r < 0) {
+                log_oom();
+                return 0;
+        }
+
+        r = sd_rtnl_message_get_family(message, &tmp->family);
         if (r < 0) {
                 log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
                 return 0;
-        } else if (!IN_SET(family, AF_INET, AF_INET6)) {
-                log_debug("rtnl: received address with invalid family %u, ignoring", family);
+        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
+                log_debug("rtnl: received address with invalid family %u, ignoring", tmp->family);
                 return 0;
         }
 
-        switch (family) {
+        switch (tmp->family) {
         case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, FRA_SRC, &from.in);
+                r = sd_netlink_message_read_in_addr(message, FRA_SRC, &tmp->from.in);
                 if (r < 0 && r != -ENODATA) {
                         log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
                         return 0;
                 } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
                         if (r < 0) {
                                 log_warning_errno(r, "rtnl: failed to retrieve rule from prefix length, ignoring: %m");
                                 return 0;
                         }
                 }
 
-                r = sd_netlink_message_read_in_addr(message, FRA_DST, &to.in);
+                r = sd_netlink_message_read_in_addr(message, FRA_DST, &tmp->to.in);
                 if (r < 0 && r != -ENODATA) {
                         log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
                         return 0;
                 } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
                         if (r < 0) {
                                 log_warning_errno(r, "rtnl: failed to retrieve rule to prefix length, ignoring: %m");
                                 return 0;
@@ -794,24 +799,24 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
                 break;
 
         case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &from.in6);
+                r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &tmp->from.in6);
                 if (r < 0 && r != -ENODATA) {
                         log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
                         return 0;
                 } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
                         if (r < 0) {
                                 log_warning_errno(r, "rtnl: failed to retrieve rule from prefix length, ignoring: %m");
                                 return 0;
                         }
                 }
 
-                r = sd_netlink_message_read_in6_addr(message, FRA_DST, &to.in6);
+                r = sd_netlink_message_read_in6_addr(message, FRA_DST, &tmp->to.in6);
                 if (r < 0 && r != -ENODATA) {
                         log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
                         return 0;
                 } else if (r >= 0) {
-                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
+                        r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
                         if (r < 0) {
                                 log_warning_errno(r, "rtnl: failed to retrieve rule to prefix length, ignoring: %m");
                                 return 0;
@@ -824,22 +829,41 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
                 assert_not_reached("Received unsupported address family");
         }
 
-        if (from_prefixlen == 0 && to_prefixlen == 0)
+        if (tmp->from_prefixlen == 0 && tmp->to_prefixlen == 0)
                 return 0;
 
-        r = sd_netlink_message_read_u32(message, FRA_FWMARK, &fwmark);
+        r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get flag, ignoring: %m");
+                return 0;
+        }
+        tmp->invert_rule = flags & FIB_RULE_INVERT;
+
+        r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
         if (r < 0 && r != -ENODATA) {
                 log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
                 return 0;
         }
 
-        r = sd_netlink_message_read_u32(message, FRA_TABLE, &table);
+        r = sd_netlink_message_read_u32(message, FRA_FWMASK, &tmp->fwmask);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_FWMASK attribute, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, FRA_PRIORITY, &tmp->priority);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_PRIORITY attribute, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, FRA_TABLE, &tmp->table);
         if (r < 0 && r != -ENODATA) {
                 log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
                 return 0;
         }
 
-        r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tos);
+        r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos);
         if (r < 0 && r != -ENODATA) {
                 log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
                 return 0;
@@ -850,37 +874,43 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
                 log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
                 return 0;
         }
+        r = free_and_strdup(&tmp->iif, iif);
+        if (r < 0)
+                return log_oom();
 
         r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif);
         if (r < 0 && r != -ENODATA) {
                 log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
                 return 0;
         }
+        r = free_and_strdup(&tmp->oif, oif);
+        if (r < 0)
+                return log_oom();
 
-        r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &protocol);
+        r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol);
         if (r < 0 && r != -ENODATA) {
                 log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m");
                 return 0;
         }
 
-        r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(sport), (void *) &sport);
+        r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport);
         if (r < 0 && r != -ENODATA) {
                 log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m");
                 return 0;
         }
 
-        r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(dport), (void *) &dport);
+        r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(tmp->dport), &tmp->dport);
         if (r < 0 && r != -ENODATA) {
                 log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m");
                 return 0;
         }
 
-        (void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &rule);
+        (void) routing_policy_rule_get(m, tmp, &rule);
 
         switch (type) {
         case RTM_NEWRULE:
                 if (!rule) {
-                        r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &rule);
+                        r = routing_policy_rule_add_foreign(m, tmp, &rule);
                         if (r < 0) {
                                 log_warning_errno(r, "Could not add rule, ignoring: %m");
                                 return 0;
@@ -1076,9 +1106,12 @@ static int manager_save(Manager *m) {
         Link *link;
         Iterator i;
         _cleanup_free_ char *temp_path = NULL;
+        _cleanup_strv_free_ char **p = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         LinkOperationalState operstate = LINK_OPERSTATE_OFF;
-        const char *operstate_str;
+        LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
+        LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
+        const char *operstate_str, *carrier_state_str, *address_state_str;
         int r;
 
         assert(m);
@@ -1108,6 +1141,12 @@ static int manager_save(Manager *m) {
                 if (link->operstate > operstate)
                         operstate = link->operstate;
 
+                if (link->carrier_state > carrier_state)
+                        carrier_state = link->carrier_state;
+
+                if (link->address_state > address_state)
+                        address_state = link->address_state;
+
                 if (!link->network)
                         continue;
 
@@ -1179,9 +1218,18 @@ static int manager_save(Manager *m) {
                 }
         }
 
+        if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
+                carrier_state = LINK_CARRIER_STATE_CARRIER;
+
         operstate_str = link_operstate_to_string(operstate);
         assert(operstate_str);
 
+        carrier_state_str = link_carrier_state_to_string(carrier_state);
+        assert(carrier_state_str);
+
+        address_state_str = link_address_state_to_string(address_state);
+        assert(address_state_str);
+
         r = fopen_temporary(m->state_file, &f, &temp_path);
         if (r < 0)
                 return r;
@@ -1190,7 +1238,10 @@ static int manager_save(Manager *m) {
 
         fprintf(f,
                 "# This is private data. Do not parse.\n"
-                "OPER_STATE=%s\n", operstate_str);
+                "OPER_STATE=%s\n"
+                "CARRIER_STATE=%s\n"
+                "ADDRESS_STATE=%s\n",
+                operstate_str, carrier_state_str, address_state_str);
 
         ordered_set_print(f, "DNS=", dns);
         ordered_set_print(f, "NTP=", ntp);
@@ -1212,9 +1263,26 @@ static int manager_save(Manager *m) {
 
         if (m->operational_state != operstate) {
                 m->operational_state = operstate;
-                r = manager_send_changed(m, "OperationalState", NULL);
+                if (strv_extend(&p, "OperationalState") < 0)
+                        log_oom();
+        }
+
+        if (m->carrier_state != carrier_state) {
+                m->carrier_state = carrier_state;
+                if (strv_extend(&p, "CarrierState") < 0)
+                        log_oom();
+        }
+
+        if (m->address_state != address_state) {
+                m->address_state = address_state;
+                if (strv_extend(&p, "AddressState") < 0)
+                        log_oom();
+        }
+
+        if (p) {
+                r = manager_send_changed_strv(m, p);
                 if (r < 0)
-                        log_error_errno(r, "Could not emit changed OperationalState: %m");
+                        log_error_errno(r, "Could not emit changed properties: %m");
         }
 
         m->dirty = false;
@@ -1369,16 +1437,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;
@@ -1442,7 +1512,7 @@ void manager_free(Manager *m) {
                 if (link->dhcp6_client)
                         (void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link);
 
-                link_stop_clients(link);
+                (void) link_stop_clients(link, true);
 
                 link_unref(link);
         }
@@ -1469,6 +1539,7 @@ void manager_free(Manager *m) {
         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);
@@ -1484,9 +1555,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. */
 
@@ -1875,18 +1951,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;
-}