]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-address.c
tree-wide: define iterator inside of the macro
[thirdparty/systemd.git] / src / network / networkd-address.c
index aeadb7b01bf3992508497f923d1b3c958e888751..76c91ef9dd2f2fb1b4d15ff5be47715e5a3d3956 100644 (file)
@@ -10,6 +10,7 @@
 #include "netlink-util.h"
 #include "networkd-address.h"
 #include "networkd-manager.h"
+#include "networkd-ndisc.h"
 #include "parse-util.h"
 #include "set.h"
 #include "socket-util.h"
@@ -123,8 +124,22 @@ void address_free(Address *address) {
         }
 
         if (address->link && !address->acd) {
+                NDiscAddress *n;
+
                 set_remove(address->link->addresses, address);
                 set_remove(address->link->addresses_foreign, address);
+                set_remove(address->link->static_addresses, address);
+                if (address->link->dhcp_address == address)
+                        address->link->dhcp_address = NULL;
+                if (address->link->dhcp_address_old == address)
+                        address->link->dhcp_address_old = NULL;
+                set_remove(address->link->dhcp6_addresses, address);
+                set_remove(address->link->dhcp6_addresses_old, address);
+                set_remove(address->link->dhcp6_pd_addresses, address);
+                set_remove(address->link->dhcp6_pd_addresses_old, address);
+                SET_FOREACH(n, address->link->ndisc_addresses)
+                        if (n->address == address)
+                                free(set_remove(address->link->ndisc_addresses, n));
 
                 if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
                         memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
@@ -151,7 +166,7 @@ static uint32_t address_prefix(const Address *a) {
                 return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
 }
 
-static void address_hash_func(const Address *a, struct siphash *state) {
+void address_hash_func(const Address *a, struct siphash *state) {
         assert(a);
 
         siphash24_compress(&a->family, sizeof(a->family), state);
@@ -176,7 +191,7 @@ static void address_hash_func(const Address *a, struct siphash *state) {
         }
 }
 
-static int address_compare_func(const Address *a1, const Address *a2) {
+int address_compare_func(const Address *a1, const Address *a2) {
         int r;
 
         r = CMP(a1->family, a2->family);
@@ -205,7 +220,7 @@ static int address_compare_func(const Address *a1, const Address *a2) {
         }
 }
 
-DEFINE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
 
 bool address_equal(Address *a1, Address *a2) {
         if (a1 == a2)
@@ -344,11 +359,8 @@ int address_update(
         int r;
 
         assert(address);
+        assert(address->link);
         assert(cinfo);
-        assert_return(address->link, 1);
-
-        if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return 1;
 
         ready = address_is_ready(address);
 
@@ -356,18 +368,27 @@ int address_update(
         address->scope = scope;
         address->cinfo = *cinfo;
 
+        if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 0;
+
         link_update_operstate(address->link, true);
         link_check_ready(address->link);
 
-        if (!ready &&
-            address_is_ready(address) &&
-            address->family == AF_INET6 &&
-            in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
-            in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
+        if (!ready && address_is_ready(address)) {
+                if (address->callback) {
+                        r = address->callback(address);
+                        if (r < 0)
+                                return r;
+                }
 
-                r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
-                if (r < 0)
-                        return r;
+                if (address->family == AF_INET6 &&
+                    in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
+                    IN6_IS_ADDR_UNSPECIFIED(&address->link->ipv6ll_address) > 0) {
+
+                        r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         return 0;
@@ -431,6 +452,31 @@ int address_get(Link *link,
         return -ENOENT;
 }
 
+static bool address_exists_internal(Set *addresses, int family, const union in_addr_union *in_addr) {
+        Address *address;
+
+        SET_FOREACH(address, addresses) {
+                if (address->family != family)
+                        continue;
+                if (in_addr_equal(address->family, &address->in_addr, in_addr))
+                        return true;
+        }
+
+        return false;
+}
+
+bool address_exists(Link *link, int family, const union in_addr_union *in_addr) {
+        assert(link);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(in_addr);
+
+        if (address_exists_internal(link->addresses, family, in_addr))
+                return true;
+        if (address_exists_internal(link->addresses_foreign, family, in_addr))
+                return true;
+        return false;
+}
+
 static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
@@ -444,7 +490,7 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
         r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EADDRNOTAVAIL)
                 log_link_message_warning_errno(link, m, r, "Could not drop address");
-        else
+        else if (r >= 0)
                 (void) manager_rtnl_process_address(rtnl, m, link->manager);
 
         return 1;
@@ -560,9 +606,11 @@ int address_configure(
                 Address *address,
                 Link *link,
                 link_netlink_message_handler_t callback,
-                bool update) {
+                bool update,
+                Address **ret) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+        Address *a;
         int r;
 
         assert(address);
@@ -583,6 +631,13 @@ int address_configure(
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m");
 
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *str = NULL;
+
+                (void) in_addr_to_string(address->family, &address->in_addr, &str);
+                log_link_debug(link, "%s address: %s", update ? "Updating" : "Configuring", strna(str));
+        }
+
         if (update)
                 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
                                                     link->ifindex, address->family);
@@ -664,9 +719,9 @@ int address_configure(
         link_ref(link);
 
         if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer))
-                r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, NULL);
+                r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, &a);
         else
-                r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
+                r = address_add(link, address->family, &address->in_addr, address->prefixlen, &a);
         if (r < 0) {
                 address_release(address);
                 return log_link_error_errno(link, r, "Could not add address: %m");
@@ -686,6 +741,9 @@ int address_configure(
                         log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
         }
 
+        if (ret)
+                *ret = a;
+
         return 1;
 }
 
@@ -790,18 +848,23 @@ int config_parse_broadcast(
         assert(data);
 
         r = address_new_static(network, filename, section_line, &n);
-        if (r < 0)
-                return r;
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to allocate new address, ignoring assignment: %m");
+                return 0;
+        }
 
         if (n->family == AF_INET6) {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
         r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
+                log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Broadcast is invalid, ignoring assignment: %s", rvalue);
                 return 0;
         }
@@ -841,14 +904,18 @@ int config_parse_address(const char *unit,
                 r = address_new_static(network, NULL, 0, &n);
         } else
                 r = address_new_static(network, filename, section_line, &n);
-
-        if (r < 0)
-                return r;
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to allocate new address, ignoring assignment: %m");
+                return 0;
+        }
 
         /* Address=address/prefixlen */
         r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_REFUSE, &f, &buffer, &prefixlen);
         if (r == -ENOANO) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
+                log_syntax(unit, LOG_WARNING, filename, line, r,
                            "An address '%s' is specified without prefix length. "
                            "The behavior of parsing addresses without prefix length will be changed in the future release. "
                            "Please specify prefix length explicitly.", rvalue);
@@ -856,12 +923,12 @@ int config_parse_address(const char *unit,
                 r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_LEGACY, &f, &buffer, &prefixlen);
         }
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue);
                 return 0;
         }
 
         if (n->family != AF_UNSPEC && f != n->family) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Address is incompatible, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
@@ -871,7 +938,7 @@ int config_parse_address(const char *unit,
                  * let's limit the prefix length to 64 or larger. See RFC4193. */
                 if ((f == AF_INET && prefixlen < 8) ||
                     (f == AF_INET6 && prefixlen < 64)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
                                    "Null address with invalid prefixlen='%u', ignoring assignment: %s",
                                    prefixlen, rvalue);
                         return 0;
@@ -917,11 +984,16 @@ int config_parse_label(
         assert(data);
 
         r = address_new_static(network, filename, section_line, &n);
-        if (r < 0)
-                return r;
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to allocate new address, ignoring assignment: %m");
+                return 0;
+        }
 
         if (!address_label_valid(rvalue)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
                 return 0;
         }
@@ -956,8 +1028,13 @@ int config_parse_lifetime(const char *unit,
         assert(data);
 
         r = address_new_static(network, filename, section_line, &n);
-        if (r < 0)
-                return r;
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to allocate new address, ignoring assignment: %m");
+                return 0;
+        }
 
         /* We accept only "forever", "infinity", empty, or "0". */
         if (STR_IN_SET(rvalue, "forever", "infinity", ""))
@@ -965,7 +1042,7 @@ int config_parse_lifetime(const char *unit,
         else if (streq(rvalue, "0"))
                 k = 0;
         else {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "Invalid PreferredLifetime= value, ignoring: %s", rvalue);
                 return 0;
         }
@@ -997,12 +1074,17 @@ int config_parse_address_flags(const char *unit,
         assert(data);
 
         r = address_new_static(network, filename, section_line, &n);
-        if (r < 0)
-                return r;
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to allocate new address, ignoring assignment: %m");
+                return 0;
+        }
 
         r = parse_boolean(rvalue);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
+                log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
                 return 0;
         }
@@ -1045,8 +1127,13 @@ int config_parse_address_scope(const char *unit,
         assert(data);
 
         r = address_new_static(network, filename, section_line, &n);
-        if (r < 0)
-                return r;
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to allocate new address, ignoring assignment: %m");
+                return 0;
+        }
 
         if (streq(rvalue, "host"))
                 n->scope = RT_SCOPE_HOST;
@@ -1057,7 +1144,7 @@ int config_parse_address_scope(const char *unit,
         else {
                 r = safe_atou8(rvalue , &n->scope);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r,
+                        log_syntax(unit, LOG_WARNING, filename, line, r,
                                    "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
                         return 0;
                 }
@@ -1091,8 +1178,13 @@ int config_parse_duplicate_address_detection(
         assert(data);
 
         r = address_new_static(network, filename, section_line, &n);
-        if (r < 0)
-                return r;
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to allocate new address, ignoring assignment: %m");
+                return 0;
+        }
 
         r = parse_boolean(rvalue);
         if (r >= 0) {
@@ -1107,7 +1199,7 @@ int config_parse_duplicate_address_detection(
 
         a = duplicate_address_detection_address_family_from_string(rvalue);
         if (a < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL),
                            "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
                 return 0;
         }