]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #32181 from YHNdnzj/open-file
authorLuca Boccassi <bluca@debian.org>
Wed, 10 Apr 2024 22:15:56 +0000 (23:15 +0100)
committerGitHub <noreply@github.com>
Wed, 10 Apr 2024 22:15:56 +0000 (23:15 +0100)
Some fixes/improvements for OpenFile=

66 files changed:
docs/HACKING.md
pkg/centos
pkg/fedora
src/boot/bless-boot-generator.c
src/core/manager.c
src/core/target.c
src/core/transaction.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-ipv4acd.c
src/libsystemd-network/sd-ipv4ll.c
src/libsystemd-network/sd-radv.c
src/network/networkd-address-generation.c
src/network/networkd-address-generation.h
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-dhcp-prefix-delegation.c
src/network/networkd-dhcp-prefix-delegation.h
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-ndisc.c
src/network/networkd-ndisc.h
src/network/networkd-radv.c
src/network/networkd-radv.h
src/network/networkd-setlink.c
src/network/networkd-sysctl.c
src/network/networkd-sysctl.h
src/shared/tests.h
src/test/test-cgroup-util.c
src/test/test-cgroup.c
src/test/test-conf-parser.c
src/test/test-core-unit.c
src/test/test-creds.c
src/test/test-env-file.c
src/test/test-env-util.c
src/test/test-extract-word.c
src/test/test-fileio.c
src/test/test-glob-util.c
src/test/test-hashmap-plain.c
src/test/test-hashmap.c
src/test/test-json.c
src/test/test-list.c
src/test/test-load-fragment.c
src/test/test-loop-block.c
src/test/test-macro.c
src/test/test-mount-util.c
src/test/test-netlink-manual.c
src/test/test-openssl.c
src/test/test-parse-argument.c
src/test/test-path-util.c
src/test/test-prioq.c
src/test/test-process-util.c
src/test/test-rlimit-util.c
src/test/test-secure-bits.c
src/test/test-socket-bind.c
src/test/test-strbuf.c
src/test/test-string-util.c
src/test/test-strv.c
src/test/test-tpm2.c
src/test/test-watch-pid.c
test/test-network/conf/25-ipv6-prefix-veth-token-prefixstable.network
test/test-network/conf/25-veth-peer-no-address.network [new file with mode: 0644]
test/test-network/systemd-networkd-tests.py
tools/check-version-history.py
tools/git-post-rewrite-hook.sh [new file with mode: 0755]
tools/git-setup.sh
units/systemd-boot-check-no-failures.service.in

index 33d32c91197ea8c87da7638220d3fac93aab3be8..2a58780fbf513003b7df2ca7133374fb8af81d4d 100644 (file)
@@ -21,6 +21,8 @@ git correctly (running `meson` will run these commands for you automatically):
 $ git config submodule.recurse true
 $ git config fetch.recurseSubmodules on-demand
 $ git config push.recurseSubmodules no
+$ cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
+$ cp tools/git-post-rewrite-hook.sh .git/hooks/post-rewrite
 ```
 
 When adding new functionality, tests should be added. For shared functionality
index 282d1f30a64204630e96bcf048597f6afbe4a8bf..ad880b10ee6bbfbe266c518fc87b8c7a3df962da 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 282d1f30a64204630e96bcf048597f6afbe4a8bf
+Subproject commit ad880b10ee6bbfbe266c518fc87b8c7a3df962da
index 3f8c38e5d6481fa01e766516cbdf7779c4a2825b..2822a03dded26b9453bddbba7c6a152de8204aec 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3f8c38e5d6481fa01e766516cbdf7779c4a2825b
+Subproject commit 2822a03dded26b9453bddbba7c6a152de8204aec
index 38b2c3ad7cd87ec3375b37270c29c78b393a0581..cf645e2416cecaa7226dcd4a064147dcd88be614 100644 (file)
@@ -7,7 +7,6 @@
 #include "generator.h"
 #include "initrd-util.h"
 #include "log.h"
-#include "mkdir.h"
 #include "special.h"
 #include "string-util.h"
 #include "virt.h"
@@ -17,6 +16,7 @@
  * boot as "good" if we manage to boot up far enough. */
 
 static int run(const char *dest, const char *dest_early, const char *dest_late) {
+        assert(dest_early);
 
         if (in_initrd()) {
                 log_debug("Skipping generator, running in the initrd.");
@@ -34,7 +34,6 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
         }
 
         if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderBootCountPath)), F_OK) < 0) {
-
                 if (errno == ENOENT) {
                         log_debug_errno(errno, "Skipping generator, not booted with boot counting in effect.");
                         return 0;
@@ -45,12 +44,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
 
         /* We pull this in from basic.target so that it ends up in all "regular" boot ups, but not in
          * rescue.target or even emergency.target. */
-        const char *p = strjoina(dest_early, "/" SPECIAL_BASIC_TARGET ".wants/systemd-bless-boot.service");
-        (void) mkdir_parents(p, 0755);
-        if (symlink(SYSTEM_DATA_UNIT_DIR "/systemd-bless-boot.service", p) < 0)
-                return log_error_errno(errno, "Failed to create symlink '%s': %m", p);
-
-        return 0;
+        return generator_add_symlink(dest_early, SPECIAL_BASIC_TARGET, "wants", "systemd-bless-boot.service");
 }
 
 DEFINE_MAIN_GENERATOR_FUNCTION(run);
index fe7dc19672ae899ca529a75fe7637cc6b04c8fb2..6ac97e76609d334d08a30a3c3cd9b132d656bb2f 100644 (file)
@@ -2203,8 +2203,8 @@ static int manager_dispatch_target_deps_queue(Manager *m) {
                 if (n_targets < 0)
                         return n_targets;
 
-                for (int i = 0; i < n_targets; i++) {
-                        r = unit_add_default_target_dependency(u, targets[i]);
+                FOREACH_ARRAY(i, targets, n_targets) {
+                        r = unit_add_default_target_dependency(u, *i);
                         if (r < 0)
                                 return r;
                 }
index d9362b8b16436829dcc95a6d085339836508ea0f..15866e9b1e87b3534e03a6b519dc0bb15016fef3 100644 (file)
@@ -55,8 +55,8 @@ static int target_add_default_dependencies(Target *t) {
         if (n_others < 0)
                 return n_others;
 
-        for (int i = 0; i < n_others; i++) {
-                r = unit_add_default_target_dependency(others[i], UNIT(t));
+        FOREACH_ARRAY(i, others, n_others) {
+                r = unit_add_default_target_dependency(*i, UNIT(t));
                 if (r < 0)
                         return r;
         }
index a81c40fb062a3a14dbb46502d89eb358654bc32f..b5c6348b6fcbc7bef2e7f5a6f94c05f788759174 100644 (file)
@@ -446,10 +446,10 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
          * the graph over 'before' edges in the actual job execution order. We traverse over both unit
          * ordering dependencies and we test with job_compare() whether it is the 'before' edge in the job
          * execution ordering. */
-        for (size_t d = 0; d < ELEMENTSOF(directions); d++) {
+        FOREACH_ARRAY(d, directions, ELEMENTSOF(directions)) {
                 Unit *u;
 
-                UNIT_FOREACH_DEPENDENCY(u, j->unit, directions[d]) {
+                UNIT_FOREACH_DEPENDENCY(u, j->unit, *d) {
                         Job *o;
 
                         /* Is there a job for this unit? */
@@ -463,7 +463,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
                         }
 
                         /* Cut traversing if the job j is not really *before* o. */
-                        if (job_compare(j, o, directions[d]) >= 0)
+                        if (job_compare(j, o, *d) >= 0)
                                 continue;
 
                         r = transaction_verify_order_one(tr, o, j, generation, e);
index 5a26102e232b0fe4567fd906c19cd2ea5f8b714a..229ceef78362bf4f08fb5498f5bddd3d04ede8df 100644 (file)
@@ -1417,7 +1417,8 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
 }
 
 int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
-        assert_return(client, -EINVAL);
+        if (!client)
+                return false;
 
         return client->state != DHCP6_STATE_STOPPED;
 }
index 1a9a8f10ab61008d6629d2033de0e4aff0e6c660..51d2b2219dd7b35a7326c6bd9922b3e36c5a09e3 100644 (file)
@@ -564,7 +564,8 @@ int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address) {
 }
 
 int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
-        assert_return(acd, false);
+        if (!acd)
+                return false;
 
         return acd->state != IPV4ACD_STATE_INIT;
 }
index a29279e6afc5210337ce19bfa9323e13ddceb890..5bf98332a9f184e6968ace16bd96b5c08a7a5fdf 100644 (file)
@@ -206,7 +206,8 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed) {
 }
 
 int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
-        assert_return(ll, false);
+        if (!ll)
+                return false;
 
         return sd_ipv4acd_is_running(ll->acd);
 }
index 71e7a71897024b6abc63588133c7ba7b4c1769b2..cde45388b7ce763f6caf34136ab8a395abf58568 100644 (file)
@@ -81,7 +81,8 @@ sd_event *sd_radv_get_event(sd_radv *ra) {
 }
 
 int sd_radv_is_running(sd_radv *ra) {
-        assert_return(ra, false);
+        if (!ra)
+                return false;
 
         return ra->state != RADV_STATE_IDLE;
 }
index 9a5e2c217393ddfbf03534133ad8a3843298f8fd..816cdf713ac5d650376efd2207c8066365ad4320 100644 (file)
@@ -34,11 +34,125 @@ typedef enum AddressGenerationType {
         _ADDRESS_GENERATION_TYPE_INVALID = -EINVAL,
 } AddressGenerationType;
 
-typedef struct IPv6Token {
+struct IPv6Token {
+        unsigned n_ref;
         AddressGenerationType type;
         struct in6_addr address;
         sd_id128_t secret_key;
-} IPv6Token;
+};
+
+DEFINE_TRIVIAL_REF_UNREF_FUNC(IPv6Token, ipv6_token, mfree);
+DEFINE_TRIVIAL_CLEANUP_FUNC(IPv6Token*, ipv6_token_unref);
+
+static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) {
+        siphash24_compress_typesafe(p->type, state);
+        siphash24_compress_typesafe(p->address, state);
+        id128_hash_func(&p->secret_key, state);
+}
+
+static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
+        int r;
+
+        r = CMP(a->type, b->type);
+        if (r != 0)
+                return r;
+
+        r = memcmp(&a->address, &b->address, sizeof(struct in6_addr));
+        if (r != 0)
+                return r;
+
+        return id128_compare_func(&a->secret_key, &b->secret_key);
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+                ipv6_token_hash_ops,
+                IPv6Token,
+                ipv6_token_hash_func,
+                ipv6_token_compare_func,
+                ipv6_token_unref);
+
+DEFINE_PRIVATE_HASH_OPS_FULL(
+                ipv6_token_by_addr_hash_ops,
+                struct in6_addr,
+                in6_addr_hash_func,
+                in6_addr_compare_func,
+                free,
+                IPv6Token,
+                ipv6_token_unref);
+
+static int ipv6_token_new(AddressGenerationType type, const struct in6_addr *addr, const sd_id128_t *secret_key, IPv6Token **ret) {
+        IPv6Token *p;
+
+        assert(type >= 0 && type < _ADDRESS_GENERATION_TYPE_MAX);
+        assert(addr);
+        assert(secret_key);
+        assert(ret);
+
+        p = new(IPv6Token, 1);
+        if (!p)
+                return -ENOMEM;
+
+        *p = (IPv6Token) {
+                .n_ref = 1,
+                .type = type,
+                .address = *addr,
+                .secret_key = *secret_key,
+        };
+
+        *ret = p;
+        return 0;
+}
+
+static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct in6_addr *addr, const sd_id128_t *secret_key) {
+        IPv6Token *p;
+        int r;
+
+        assert(tokens);
+
+        r = ipv6_token_new(type, addr, secret_key, &p);
+        if (r < 0)
+                return r;
+
+        return set_ensure_consume(tokens, &ipv6_token_hash_ops, p);
+}
+
+static int ipv6_token_put_by_addr(Hashmap **tokens_by_address, const struct in6_addr *addr, IPv6Token *token) {
+        _cleanup_free_ struct in6_addr *copy = NULL;
+        int r;
+
+        assert(tokens_by_address);
+        assert(addr);
+        assert(token);
+
+        copy = newdup(struct in6_addr, addr, 1);
+        if (!copy)
+                return -ENOMEM;
+
+        r = hashmap_ensure_put(tokens_by_address, &ipv6_token_by_addr_hash_ops, copy, token);
+        if (r == -EEXIST)
+                return 0;
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(copy);
+        ipv6_token_ref(token);
+        return 1;
+}
+
+static int ipv6_token_type_put_by_addr(Hashmap **tokens_by_addr, const struct in6_addr *addr, AddressGenerationType type) {
+        _cleanup_(ipv6_token_unrefp) IPv6Token *token = NULL;
+        int r;
+
+        assert(tokens_by_addr);
+        assert(addr);
+
+        r = ipv6_token_new(type, &(struct in6_addr) {}, &SD_ID128_NULL, &token);
+        if (r < 0)
+                return r;
+
+        return ipv6_token_put_by_addr(tokens_by_addr, addr, token);
+}
+
 
 static int generate_eui64_address(const Link *link, const struct in6_addr *prefix, struct in6_addr *ret) {
         assert(link);
@@ -134,10 +248,12 @@ static int generate_stable_private_address(
                 const sd_id128_t *app_id,
                 const sd_id128_t *secret_key,
                 const struct in6_addr *prefix,
+                const struct in6_addr *previous,
                 struct in6_addr *ret) {
 
         sd_id128_t secret_machine_key;
         struct in6_addr addr;
+        bool found = false;
         uint8_t i;
         int r;
 
@@ -162,16 +278,29 @@ static int generate_stable_private_address(
         for (i = 0; i < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; i++) {
                 generate_stable_private_address_one(link, secret_key, prefix, i, &addr);
 
-                if (stable_private_address_is_valid(&addr))
-                        break;
+                if (!stable_private_address_is_valid(&addr))
+                        continue;
+
+                /* When 'previous' is non-NULL, then this is called after DAD in the kernel triggered.
+                 * Let's increment the counter and provide the next address. */
+                if (previous && !found) {
+                        found = in6_addr_equal(previous, &addr);
+                        continue;
+                }
+
+                break;
         }
-        if (i >= DAD_CONFLICTS_IDGEN_RETRIES_RFC7217)
+        if (i >= DAD_CONFLICTS_IDGEN_RETRIES_RFC7217) {
                 /* propagate recognizable errors. */
-                return log_link_debug_errno(link, SYNTHETIC_ERRNO(ENOANO),
+                if (previous && !found)
+                        return -EADDRNOTAVAIL;
+
+                return log_link_debug_errno(link, SYNTHETIC_ERRNO(EADDRINUSE),
                                             "Failed to generate stable private address.");
+        }
 
         *ret = addr;
-        return 0;
+        return 1;
 }
 
 static int generate_addresses(
@@ -180,10 +309,10 @@ static int generate_addresses(
                 const sd_id128_t *app_id,
                 const struct in6_addr *prefix,
                 uint8_t prefixlen,
-                Set **ret) {
+                Hashmap **ret) {
 
-        _cleanup_set_free_ Set *addresses = NULL;
-        struct in6_addr masked;
+        _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL;
+        struct in6_addr masked, addr;
         IPv6Token *j;
         int r;
 
@@ -197,8 +326,6 @@ static int generate_addresses(
         in6_addr_mask(&masked, prefixlen);
 
         SET_FOREACH(j, tokens) {
-                struct in6_addr addr, *copy;
-
                 switch (j->type) {
                 case ADDRESS_GENERATION_EUI64:
                         if (generate_eui64_address(link, &masked, &addr) < 0)
@@ -214,7 +341,7 @@ static int generate_addresses(
                         if (in6_addr_is_set(&j->address) && !in6_addr_equal(&j->address, &masked))
                                 continue;
 
-                        if (generate_stable_private_address(link, app_id, &j->secret_key, &masked, &addr) < 0)
+                        if (generate_stable_private_address(link, app_id, &j->secret_key, &masked, /* previous = */ NULL, &addr) < 0)
                                 continue;
 
                         break;
@@ -223,97 +350,77 @@ static int generate_addresses(
                         assert_not_reached();
                 }
 
-                copy = newdup(struct in6_addr, &addr, 1);
-                if (!copy)
-                        return -ENOMEM;
-
-                r = set_ensure_consume(&addresses, &in6_addr_hash_ops_free, copy);
+                r = ipv6_token_put_by_addr(&tokens_by_address, &addr, j);
                 if (r < 0)
                         return r;
         }
 
         /* fall back to EUI-64 if no token is provided */
-        if (set_isempty(addresses)) {
-                _cleanup_free_ struct in6_addr *addr = NULL;
+        if (hashmap_isempty(tokens_by_address)) {
+                AddressGenerationType type;
 
-                addr = new(struct in6_addr, 1);
-                if (!addr)
-                        return -ENOMEM;
-
-                if (IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
-                        r = generate_eui64_address(link, &masked, addr);
-                else
-                        r = generate_stable_private_address(link, app_id, &SD_ID128_NULL, &masked, addr);
+                if (IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND)) {
+                        type = ADDRESS_GENERATION_EUI64;
+                        r = generate_eui64_address(link, &masked, &addr);
+                } else {
+                        type = ADDRESS_GENERATION_PREFIXSTABLE;
+                        r = generate_stable_private_address(link, app_id, &SD_ID128_NULL, &masked, /* previous = */ NULL, &addr);
+                }
                 if (r < 0)
                         return r;
 
-                r = set_ensure_consume(&addresses, &in6_addr_hash_ops_free, TAKE_PTR(addr));
+                r = ipv6_token_type_put_by_addr(&tokens_by_address, &addr, type);
                 if (r < 0)
                         return r;
         }
 
-        *ret = TAKE_PTR(addresses);
+        *ret = TAKE_PTR(tokens_by_address);
         return 0;
 }
 
-int dhcp_pd_generate_addresses(Link *link, const struct in6_addr *prefix, Set **ret) {
+int dhcp_pd_generate_addresses(Link *link, const struct in6_addr *prefix, Hashmap **ret) {
         return generate_addresses(link, link->network->dhcp_pd_tokens, &DHCP_PD_APP_ID, prefix, 64, ret);
 }
 
-int ndisc_generate_addresses(Link *link, const struct in6_addr *prefix, uint8_t prefixlen, Set **ret) {
+int ndisc_generate_addresses(Link *link, const struct in6_addr *prefix, uint8_t prefixlen, Hashmap **ret) {
         return generate_addresses(link, link->network->ndisc_tokens, &NDISC_APP_ID, prefix, prefixlen, ret);
 }
 
-int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *prefix, uint8_t prefixlen, Set **ret) {
+int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *prefix, uint8_t prefixlen, Hashmap **ret) {
         return generate_addresses(link, tokens, &RADV_APP_ID, prefix, prefixlen, ret);
 }
 
-static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) {
-        siphash24_compress_typesafe(p->type, state);
-        siphash24_compress_typesafe(p->address, state);
-        id128_hash_func(&p->secret_key, state);
-}
-
-static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
-        int r;
-
-        r = CMP(a->type, b->type);
-        if (r != 0)
-                return r;
-
-        r = memcmp(&a->address, &b->address, sizeof(struct in6_addr));
-        if (r != 0)
-                return r;
-
-        return id128_compare_func(&a->secret_key, &b->secret_key);
-}
-
-DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
-                ipv6_token_hash_ops,
-                IPv6Token,
-                ipv6_token_hash_func,
-                ipv6_token_compare_func,
-                free);
+int regenerate_address(Address *address, Link *link) {
+        struct in6_addr masked;
+        sd_id128_t app_id;
 
-static int ipv6_token_add(Set **tokens, AddressGenerationType type, const struct in6_addr *addr, const sd_id128_t *secret_key) {
-        IPv6Token *p;
+        assert(link);
+        assert(address);
+        assert(address->family == AF_INET6);
+        assert(!address->link && !address->network);
 
-        assert(tokens);
-        assert(type >= 0 && type < _ADDRESS_GENERATION_TYPE_MAX);
-        assert(addr);
-        assert(secret_key);
+        if (!address->token ||
+            address->token->type != ADDRESS_GENERATION_PREFIXSTABLE)
+                return 0;
 
-        p = new(IPv6Token, 1);
-        if (!p)
-                return -ENOMEM;
+        switch (address->source) {
+        case NETWORK_CONFIG_SOURCE_STATIC:
+                app_id = RADV_APP_ID;
+                break;
+        case NETWORK_CONFIG_SOURCE_DHCP_PD:
+                app_id = DHCP_PD_APP_ID;
+                break;
+        case NETWORK_CONFIG_SOURCE_NDISC:
+                app_id = NDISC_APP_ID;
+                break;
+        default:
+                assert_not_reached();
+        }
 
-        *p = (IPv6Token) {
-                 .type = type,
-                 .address = *addr,
-                 .secret_key = *secret_key,
-        };
+        masked = address->in_addr.in6;
+        in6_addr_mask(&masked, address->prefixlen);
 
-        return set_ensure_consume(tokens, &ipv6_token_hash_ops, p);
+        return generate_stable_private_address(link, &app_id, &address->token->secret_key, &masked, &address->in_addr.in6, &address->in_addr.in6);
 }
 
 int config_parse_address_generation_type(
index 901b2ec4bf32d8332983bbd30220331e04513f65..2c6091321aeb6bc727ef32ef5390ed983ff8f028 100644 (file)
@@ -2,13 +2,20 @@
 #pragma once
 
 #include "conf-parser.h"
+#include "hashmap.h"
 #include "in-addr-util.h"
-#include "set.h"
 
+typedef struct Address Address;
+typedef struct IPv6Token IPv6Token;
 typedef struct Link Link;
 
-int dhcp_pd_generate_addresses(Link *link, const struct in6_addr *prefix, Set **ret);
-int ndisc_generate_addresses(Link *link, const struct in6_addr *prefix, uint8_t prefixlen, Set **ret);
-int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *prefix, uint8_t prefixlen, Set **ret);
+IPv6Token* ipv6_token_ref(IPv6Token *token);
+IPv6Token* ipv6_token_unref(IPv6Token *token);
+
+int dhcp_pd_generate_addresses(Link *link, const struct in6_addr *prefix, Hashmap **ret);
+int ndisc_generate_addresses(Link *link, const struct in6_addr *prefix, uint8_t prefixlen, Hashmap **ret);
+int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *prefix, uint8_t prefixlen, Hashmap **ret);
+
+int regenerate_address(Address *address, Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
index 41d75bdf841554ec5eec8ab8baebf25b457422f6..b4ac0bc41b6e3e576ba44de824488a6917432e4d 100644 (file)
 #include "netlink-util.h"
 #include "networkd-address-pool.h"
 #include "networkd-address.h"
+#include "networkd-dhcp-prefix-delegation.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-ipv4acd.h"
 #include "networkd-manager.h"
+#include "networkd-ndisc.h"
 #include "networkd-netlabel.h"
 #include "networkd-network.h"
 #include "networkd-queue.h"
@@ -260,6 +262,7 @@ static Address* address_free(Address *address) {
         config_section_free(address->section);
         free(address->label);
         free(address->netlabel);
+        ipv6_token_unref(address->token);
         nft_set_context_clear(&address->nft_set_context);
         return mfree(address);
 }
@@ -608,6 +611,7 @@ int address_dup(const Address *src, Address **ret) {
         dest->section = NULL;
         dest->link = NULL;
         dest->label = NULL;
+        dest->token = ipv6_token_ref(src->token);
         dest->netlabel = NULL;
         dest->nft_set_context.sets = NULL;
         dest->nft_set_context.n_sets = 0;
@@ -800,8 +804,49 @@ static int address_update(Address *address) {
         return 0;
 }
 
-static int address_drop(Address *address) {
-        Link *link = ASSERT_PTR(ASSERT_PTR(address)->link);
+static int address_removed_maybe_kernel_dad(Link *link, Address *address) {
+        int r;
+
+        assert(link);
+        assert(address);
+
+        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+                return 0;
+
+        if (address->family != AF_INET6)
+                return 0;
+
+        if (!FLAGS_SET(address->flags, IFA_F_TENTATIVE))
+                return 0;
+
+        log_link_info(link, "Address %s with tentative flag is removed, maybe a duplicated address is assigned on another node or link?",
+                      IN6_ADDR_TO_STRING(&address->in_addr.in6));
+
+        /* Reset the address state, as the object may be reused in the below. */
+        address->state = 0;
+
+        switch (address->source) {
+        case NETWORK_CONFIG_SOURCE_STATIC:
+                r = link_reconfigure_radv_address(address, link);
+                break;
+        case NETWORK_CONFIG_SOURCE_DHCP_PD:
+                r = dhcp_pd_reconfigure_address(address, link);
+                break;
+        case NETWORK_CONFIG_SOURCE_NDISC:
+                r = ndisc_reconfigure_address(address, link);
+                break;
+        default:
+                r = 0;
+        }
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to configure an alternative address: %m");
+
+        return 0;
+}
+
+static int address_drop(Address *in, bool removed_by_us) {
+        _cleanup_(address_unrefp) Address *address = address_ref(ASSERT_PTR(in));
+        Link *link = ASSERT_PTR(address->link);
         int r;
 
         r = address_set_masquerade(address, /* add = */ false);
@@ -821,6 +866,14 @@ static int address_drop(Address *address) {
 
         address_detach(address);
 
+        if (!removed_by_us) {
+                r = address_removed_maybe_kernel_dad(link, address);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return r;
+                }
+        }
+
         link_update_operstate(link, /* also_update_master = */ true);
         link_check_ready(link);
         return 0;
@@ -1135,7 +1188,7 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Remov
                         if (address_get_request(link, address, &req) >= 0)
                                 address_enter_removed(req->userdata);
 
-                        (void) address_drop(address);
+                        (void) address_drop(address, /* removed_by_us = */ true);
                 }
         }
 
@@ -1845,9 +1898,11 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
 
         if (type == RTM_DELADDR) {
                 if (address) {
+                        bool removed_by_us = FLAGS_SET(address->state, NETWORK_CONFIG_STATE_REMOVING);
+
                         address_enter_removed(address);
                         log_address_debug(address, "Forgetting removed", link);
-                        (void) address_drop(address);
+                        (void) address_drop(address, removed_by_us);
                 } else
                         log_address_debug(tmp, "Kernel removed unknown", link);
 
@@ -1886,6 +1941,10 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 (void) nft_set_context_dup(&a->nft_set_context, &address->nft_set_context);
                 address->requested_as_null = a->requested_as_null;
                 address->callback = a->callback;
+
+                ipv6_token_ref(a->token);
+                ipv6_token_unref(address->token);
+                address->token = a->token;
         }
 
         /* Then, update miscellaneous info. */
index ac6179a9248f4770ae9d3e270497937842afb7dc..e09551ecda4c2bf4f120e16d224c3eb35d5fd4fc 100644 (file)
@@ -10,6 +10,7 @@
 #include "hash-funcs.h"
 #include "in-addr-util.h"
 #include "network-util.h"
+#include "networkd-address-generation.h"
 #include "networkd-link.h"
 #include "networkd-util.h"
 #include "time-util.h"
@@ -63,6 +64,9 @@ struct Address {
          * To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
         AddressFamily duplicate_address_detection;
 
+        /* Used by address generator. */
+        IPv6Token *token;
+
         /* Called when address become ready */
         address_ready_callback_t callback;
 
index 61295d9ce6458b7c57a847d7b4482cd096232918..2e660b77631a5efacc36df7911425eb556c95534 100644 (file)
@@ -353,14 +353,50 @@ static void log_dhcp_pd_address(Link *link, const Address *address) {
                       FORMAT_LIFETIME(address->lifetime_preferred_usec));
 }
 
+static int dhcp_pd_request_address_one(Address *address, Link *link) {
+        Address *existing;
+
+        assert(address);
+        assert(link);
+
+        log_dhcp_pd_address(link, address);
+
+        if (address_get(link, address, &existing) < 0)
+                link->dhcp_pd_configured = false;
+        else
+                address_unmark(existing);
+
+        return link_request_address(link, address, &link->dhcp_pd_messages, dhcp_pd_address_handler, NULL);
+}
+
+int dhcp_pd_reconfigure_address(Address *address, Link *link) {
+        int r;
+
+        assert(address);
+        assert(address->source == NETWORK_CONFIG_SOURCE_DHCP_PD);
+        assert(link);
+
+        r = regenerate_address(address, link);
+        if (r <= 0)
+                return r;
+
+        r = dhcp_pd_request_address_one(address, link);
+        if (r < 0)
+                return r;
+
+        if (!link->dhcp_pd_configured)
+                link_set_state(link, LINK_STATE_CONFIGURING);
+
+        link_check_ready(link);
+        return 0;
+}
+
 static int dhcp_pd_request_address(
                 Link *link,
                 const struct in6_addr *prefix,
                 usec_t lifetime_preferred_usec,
                 usec_t lifetime_valid_usec) {
 
-        _cleanup_set_free_ Set *addresses = NULL;
-        struct in6_addr *a;
         int r;
 
         assert(link);
@@ -370,13 +406,15 @@ static int dhcp_pd_request_address(
         if (!link->network->dhcp_pd_assign)
                 return 0;
 
-        r = dhcp_pd_generate_addresses(link, prefix, &addresses);
+        _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL;
+        r = dhcp_pd_generate_addresses(link, prefix, &tokens_by_address);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Failed to generate addresses for acquired DHCP delegated prefix: %m");
 
-        SET_FOREACH(a, addresses) {
+        IPv6Token *token;
+        struct in6_addr *a;
+        HASHMAP_FOREACH_KEY(token, a, tokens_by_address) {
                 _cleanup_(address_unrefp) Address *address = NULL;
-                Address *existing;
 
                 r = address_new(&address);
                 if (r < 0)
@@ -390,20 +428,13 @@ static int dhcp_pd_request_address(
                 address->lifetime_valid_usec = lifetime_valid_usec;
                 SET_FLAG(address->flags, IFA_F_MANAGETEMPADDR, link->network->dhcp_pd_manage_temporary_address);
                 address->route_metric = link->network->dhcp_pd_route_metric;
-
-                log_dhcp_pd_address(link, address);
+                address->token = ipv6_token_ref(token);
 
                 r = free_and_strdup_warn(&address->netlabel, link->network->dhcp_pd_netlabel);
                 if (r < 0)
                         return r;
 
-                if (address_get(link, address, &existing) < 0)
-                        link->dhcp_pd_configured = false;
-                else
-                        address_unmark(existing);
-
-                r = link_request_address(link, address, &link->dhcp_pd_messages,
-                                         dhcp_pd_address_handler, NULL);
+                r = dhcp_pd_request_address_one(address, link);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Failed to request DHCP delegated prefix address: %m");
         }
index e591b8ae2e0947587abcbeb9ea3d83ee1f3a6a37..4a8cca92b6dfccd745a3688bacaef7ce38b46f31 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "conf-parser.h"
 
+typedef struct Address Address;
 typedef struct Link Link;
 
 bool link_dhcp_pd_is_enabled(Link *link);
@@ -19,5 +20,6 @@ int dhcp4_pd_prefix_acquired(Link *uplink);
 int dhcp6_pd_prefix_acquired(Link *uplink);
 void dhcp_pd_prefix_lost(Link *uplink);
 void dhcp4_pd_prefix_lost(Link *uplink);
+int dhcp_pd_reconfigure_address(Address *address, Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_pd_subnet_id);
index bac44a3858181e2221e20a3f6fe786a4a79b0d7e..61e0e16818e5e3c042529bfddd29b1212446465b 100644 (file)
@@ -1881,7 +1881,7 @@ static int link_admin_state_up(Link *link) {
 
         /* We set the ipv6 mtu after the device mtu, but the kernel resets
          * ipv6 mtu on NETDEV_UP, so we need to reset it. */
-        r = link_set_ipv6_mtu(link);
+        r = link_set_ipv6_mtu(link, LOG_INFO);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
 
@@ -2434,6 +2434,13 @@ static int link_update_mtu(Link *link, sd_netlink_message *message) {
 
         link->mtu = mtu;
 
+        if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
+                /* The kernel resets IPv6 MTU after changing device MTU. So, we need to re-set IPv6 MTU again. */
+                r = link_set_ipv6_mtu(link, LOG_INFO);
+                if (r < 0)
+                        log_link_warning_errno(link, r, "Failed to set IPv6 MTU, ignoring: %m");
+        }
+
         if (link->dhcp_client) {
                 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
                 if (r < 0)
index 9d15b4acce915266a6dca71858279c6020a97aee..e56ee4f41974d8c6825e25bf9f13a8c999bc747e 100644 (file)
@@ -167,6 +167,7 @@ typedef struct Link {
         Set *ndisc_captive_portals;
         Set *ndisc_pref64;
         Set *ndisc_redirects;
+        uint32_t ndisc_mtu;
         unsigned ndisc_messages;
         bool ndisc_configured:1;
 
index e1853bb31ccf6b26437d4aae96c4d2c03354374f..7473a926d43ffd83b167bc2995c3cc57ac9ac30f 100644 (file)
@@ -328,20 +328,19 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Reques
 }
 
 static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *rt) {
-        struct in6_addr router;
         bool is_new;
         int r;
 
         assert(address);
         assert(link);
-        assert(rt);
 
-        r = sd_ndisc_router_get_sender_address(rt, &router);
-        if (r < 0)
-                return r;
+        if (rt) {
+                r = sd_ndisc_router_get_sender_address(rt, &address->provider.in6);
+                if (r < 0)
+                        return r;
 
-        address->source = NETWORK_CONFIG_SOURCE_NDISC;
-        address->provider.in6 = router;
+                address->source = NETWORK_CONFIG_SOURCE_NDISC;
+        }
 
         r = free_and_strdup_warn(&address->netlabel, link->network->ndisc_netlabel);
         if (r < 0)
@@ -378,6 +377,28 @@ static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *
         return 0;
 }
 
+int ndisc_reconfigure_address(Address *address, Link *link) {
+        int r;
+
+        assert(address);
+        assert(address->source == NETWORK_CONFIG_SOURCE_NDISC);
+        assert(link);
+
+        r = regenerate_address(address, link);
+        if (r <= 0)
+                return r;
+
+        r = ndisc_request_address(address, link, NULL);
+        if (r < 0)
+                return r;
+
+        if (!link->ndisc_configured)
+                link_set_state(link, LINK_STATE_CONFIGURING);
+
+        link_check_ready(link);
+        return 0;
+}
+
 static int ndisc_redirect_route_new(sd_ndisc_redirect *rd, Route **ret) {
         _cleanup_(route_unrefp) Route *route = NULL;
         struct in6_addr gateway, destination;
@@ -1027,10 +1048,40 @@ static int ndisc_router_process_hop_limit(Link *link, sd_ndisc_router *rt) {
         return 0;
 }
 
+static int ndisc_router_process_mtu(Link *link, sd_ndisc_router *rt) {
+        uint32_t mtu;
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(rt);
+
+        if (!link->network->ndisc_use_mtu)
+                return 0;
+
+        /* Ignore the MTU option if the lifetime is zero. */
+        r = sd_ndisc_router_get_lifetime(rt, NULL);
+        if (r <= 0)
+                return r;
+
+        r = sd_ndisc_router_get_mtu(rt, &mtu);
+        if (r == -ENODATA)
+                return 0;
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to get MTU from RA: %m");
+
+        link->ndisc_mtu = mtu;
+
+        r = link_set_ipv6_mtu(link, LOG_DEBUG);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Failed to apply IPv6 MTU (%"PRIu32"), ignoring: %m", mtu);
+
+        return 0;
+}
+
 static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
         usec_t lifetime_valid_usec, lifetime_preferred_usec;
-        _cleanup_set_free_ Set *addresses = NULL;
-        struct in6_addr prefix, *a;
+        struct in6_addr prefix;
         uint8_t prefixlen;
         int r;
 
@@ -1068,11 +1119,14 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
         if (lifetime_preferred_usec > lifetime_valid_usec)
                 return 0;
 
-        r = ndisc_generate_addresses(link, &prefix, prefixlen, &addresses);
+        _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL;
+        r = ndisc_generate_addresses(link, &prefix, prefixlen, &tokens_by_address);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Failed to generate SLAAC addresses: %m");
 
-        SET_FOREACH(a, addresses) {
+        IPv6Token *token;
+        struct in6_addr *a;
+        HASHMAP_FOREACH_KEY(token, a, tokens_by_address) {
                 _cleanup_(address_unrefp) Address *address = NULL;
 
                 r = address_new(&address);
@@ -1085,6 +1139,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
                 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
                 address->lifetime_valid_usec = lifetime_valid_usec;
                 address->lifetime_preferred_usec = lifetime_preferred_usec;
+                address->token = ipv6_token_ref(token);
 
                 /* draft-ietf-6man-slaac-renum-07 section 4.2
                  * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
@@ -2098,6 +2153,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 return r;
 
+        r = ndisc_router_process_mtu(link, rt);
+        if (r < 0)
+                return r;
+
         r = ndisc_router_process_options(link, rt);
         if (r < 0)
                 return r;
@@ -2432,6 +2491,7 @@ void ndisc_flush(Link *link) {
         link->ndisc_captive_portals = set_free(link->ndisc_captive_portals);
         link->ndisc_pref64 = set_free(link->ndisc_pref64);
         link->ndisc_redirects = set_free(link->ndisc_redirects);
+        link->ndisc_mtu = 0;
 }
 
 static const char* const ndisc_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
index 2766f5e4350d8ba0569e2d59c65277ca10104dc1..019fe4da425a0a7c2d2ff14ab19bbe3f102e0728 100644 (file)
@@ -4,6 +4,7 @@
 #include "conf-parser.h"
 #include "time-util.h"
 
+typedef struct Address Address;
 typedef struct Link Link;
 typedef struct Network Network;
 
@@ -61,6 +62,7 @@ int ndisc_stop(Link *link);
 void ndisc_flush(Link *link);
 
 int link_request_ndisc(Link *link);
+int ndisc_reconfigure_address(Address *address, Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_start_dhcp6_client);
 CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_use_domains);
index 82c62dad815ef0ef2dfff68c60d47ebf856c9d68..6ff09119e3389f229c90c2c126f2e3c96516e251 100644 (file)
@@ -243,9 +243,6 @@ int link_request_radv_addresses(Link *link) {
                 return 0;
 
         HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
-                _cleanup_set_free_ Set *addresses = NULL;
-                struct in6_addr *a;
-
                 if (!p->assign)
                         continue;
 
@@ -253,11 +250,14 @@ int link_request_radv_addresses(Link *link) {
                 if (p->prefixlen > 64)
                         continue;
 
-                r = radv_generate_addresses(link, p->tokens, &p->prefix, p->prefixlen, &addresses);
+                _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL;
+                r = radv_generate_addresses(link, p->tokens, &p->prefix, p->prefixlen, &tokens_by_address);
                 if (r < 0)
                         return r;
 
-                SET_FOREACH(a, addresses) {
+                IPv6Token *token;
+                struct in6_addr *a;
+                HASHMAP_FOREACH_KEY(token, a, tokens_by_address) {
                         _cleanup_(address_unrefp) Address *address = NULL;
 
                         r = address_new(&address);
@@ -269,6 +269,7 @@ int link_request_radv_addresses(Link *link) {
                         address->in_addr.in6 = *a;
                         address->prefixlen = p->prefixlen;
                         address->route_metric = p->route_metric;
+                        address->token = ipv6_token_ref(token);
 
                         r = link_request_static_address(link, address);
                         if (r < 0)
@@ -279,6 +280,29 @@ int link_request_radv_addresses(Link *link) {
         return 0;
 }
 
+int link_reconfigure_radv_address(Address *address, Link *link) {
+        int r;
+
+        assert(address);
+        assert(address->source == NETWORK_CONFIG_SOURCE_STATIC);
+        assert(link);
+
+        r = regenerate_address(address, link);
+        if (r <= 0)
+                return r;
+
+        r = link_request_static_address(link, address);
+        if (r < 0)
+                return r;
+
+        if (link->static_address_messages != 0) {
+                link->static_addresses_configured = false;
+                link_set_state(link, LINK_STATE_CONFIGURING);
+        }
+
+        return 0;
+}
+
 static int radv_set_prefix(Link *link, Prefix *prefix) {
         _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
         int r;
index 48677b50de4b775829c6debe272d17c8e67fdaab..94834e77a8e0d10a91335ba3f4dc262f31b09233 100644 (file)
@@ -71,6 +71,7 @@ void network_drop_invalid_pref64_prefixes(Network *network);
 void network_adjust_radv(Network *network);
 
 int link_request_radv_addresses(Link *link);
+int link_reconfigure_radv_address(Address *address, Link *link);
 
 bool link_radv_enabled(Link *link);
 int radv_start(Link *link);
index eb65429a783ff0b6d31b5931baf8cbb1dc5d7f78..058bc00ba10b24f78a8d19d3db5beaa429ddc426 100644 (file)
@@ -173,19 +173,7 @@ static int link_unset_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Re
 }
 
 static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
-        int r;
-
-        r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler);
-        if (r <= 0)
-                return r;
-
-        /* The kernel resets ipv6 mtu after changing device mtu;
-         * we must set this here, after we've set device mtu */
-        r = link_set_ipv6_mtu(link);
-        if (r < 0)
-                log_link_warning_errno(link, r, "Failed to set IPv6 MTU, ignoring: %m");
-
-        return 0;
+        return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler);
 }
 
 static int link_configure_fill_message(
@@ -453,6 +441,43 @@ static bool netdev_is_ready(NetDev *netdev) {
         return true;
 }
 
+static uint32_t link_adjust_mtu(Link *link, uint32_t mtu) {
+        const char *origin;
+        uint32_t min_mtu;
+
+        assert(link);
+        assert(link->network);
+
+        min_mtu = link->min_mtu;
+        origin = "the minimum MTU of the interface";
+        if (link_ipv6_enabled(link)) {
+                /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up
+                 * MTU bytes to IPV6_MTU_MIN. */
+                if (min_mtu < IPV6_MIN_MTU) {
+                        min_mtu = IPV6_MIN_MTU;
+                        origin = "the minimum IPv6 MTU";
+                }
+                if (min_mtu < link->network->ipv6_mtu) {
+                        min_mtu = link->network->ipv6_mtu;
+                        origin = "the requested IPv6 MTU in IPv6MTUBytes=";
+                }
+        }
+
+        if (mtu < min_mtu) {
+                log_link_warning(link, "Bumping the requested MTU %"PRIu32" to %s (%"PRIu32")",
+                                 mtu, origin, min_mtu);
+                mtu = min_mtu;
+        }
+
+        if (mtu > link->max_mtu) {
+                log_link_warning(link, "Reducing the requested MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
+                                 mtu, link->max_mtu);
+                mtu = link->max_mtu;
+        }
+
+        return mtu;
+}
+
 static int link_is_ready_to_set_link(Link *link, Request *req) {
         int r;
 
@@ -570,13 +595,24 @@ static int link_is_ready_to_set_link(Link *link, Request *req) {
                                          }))
                         return false;
 
-                /* Changing FD mode may affect MTU. */
+                /* Changing FD mode may affect MTU.
+                 * See https://docs.kernel.org/networking/can.html#can-fd-flexible-data-rate-driver-support
+                 *   MTU = 16 (CAN_MTU)   => Classical CAN device
+                 *   MTU = 72 (CANFD_MTU) => CAN FD capable device */
                 if (ordered_set_contains(link->manager->request_queue,
                                          &(const Request) {
                                                  .link = link,
                                                  .type = REQUEST_TYPE_SET_LINK_CAN,
                                          }))
                         return false;
+
+                /* Now, it is ready to set MTU, but before setting, adjust requested MTU. */
+                uint32_t mtu = link_adjust_mtu(link, PTR_TO_UINT32(req->userdata));
+                if (mtu == link->mtu)
+                        return -EALREADY; /* Not necessary to set the same value. */
+
+                req->userdata = UINT32_TO_PTR(mtu);
+                return true;
         }
         default:
                 break;
@@ -865,51 +901,12 @@ int link_request_to_set_master(Link *link) {
 }
 
 int link_request_to_set_mtu(Link *link, uint32_t mtu) {
-        const char *origin;
-        uint32_t min_mtu, max_mtu;
         Request *req;
         int r;
 
         assert(link);
-        assert(link->network);
-
-        min_mtu = link->min_mtu;
-        origin = "the minimum MTU of the interface";
-        if (link_ipv6_enabled(link)) {
-                /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up
-                 * MTU bytes to IPV6_MTU_MIN. */
-                if (min_mtu < IPV6_MIN_MTU) {
-                        min_mtu = IPV6_MIN_MTU;
-                        origin = "the minimum IPv6 MTU";
-                }
-                if (min_mtu < link->network->ipv6_mtu) {
-                        min_mtu = link->network->ipv6_mtu;
-                        origin = "the requested IPv6 MTU in IPv6MTUBytes=";
-                }
-        }
-
-        if (mtu < min_mtu) {
-                log_link_warning(link, "Bumping the requested MTU %"PRIu32" to %s (%"PRIu32")",
-                                 mtu, origin, min_mtu);
-                mtu = min_mtu;
-        }
-
-        max_mtu = link->max_mtu;
-        if (link->iftype == ARPHRD_CAN)
-                /* The maximum MTU may be changed when FD mode is changed.
-                 * See https://docs.kernel.org/networking/can.html#can-fd-flexible-data-rate-driver-support
-                 *   MTU = 16 (CAN_MTU)   => Classical CAN device
-                 *   MTU = 72 (CANFD_MTU) => CAN FD capable device
-                 * So, even if the current maximum is 16, we should not reduce the requested value now. */
-                max_mtu = MAX(max_mtu, 72u);
-
-        if (mtu > max_mtu) {
-                log_link_warning(link, "Reducing the requested MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
-                                 mtu, max_mtu);
-                mtu = max_mtu;
-        }
 
-        if (link->mtu == mtu)
+        if (mtu == 0)
                 return 0;
 
         r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_MTU,
index f9db1f7f4af16c4c3085231d9f7aa234ebe33708..68c23e0eb7962f51693bb0531c8d46cf7973892a 100644 (file)
@@ -250,22 +250,28 @@ static int link_set_ipv6_proxy_ndp(Link *link) {
         return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
 }
 
-int link_set_ipv6_mtu(Link *link) {
-        uint32_t mtu;
+int link_set_ipv6_mtu(Link *link, int log_level) {
+        uint32_t mtu = 0;
 
         assert(link);
 
         if (!link_is_configured_for_family(link, AF_INET6))
                 return 0;
 
-        if (link->network->ipv6_mtu == 0)
+        assert(link->network);
+
+        if (link->network->ndisc_use_mtu)
+                mtu = link->ndisc_mtu;
+        if (mtu == 0)
+                mtu = link->network->ipv6_mtu;
+        if (mtu == 0)
                 return 0;
 
-        mtu = link->network->ipv6_mtu;
-        if (mtu > link->max_mtu) {
-                log_link_warning(link, "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
-                                 mtu, link->max_mtu);
-                mtu = link->max_mtu;
+        if (mtu > link->mtu) {
+                log_link_full(link, log_level,
+                              "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
+                              mtu, link->mtu);
+                mtu = link->mtu;
         }
 
         return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu);
@@ -355,7 +361,7 @@ int link_set_sysctl(Link *link) {
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
 
-        r = link_set_ipv6_mtu(link);
+        r = link_set_ipv6_mtu(link, LOG_INFO);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
 
index a47dda015defbb86579f2a04e89b63dea05dfbcd..d7a9b1f3201587e4209fb9fe15e445adcca5b691 100644 (file)
@@ -31,7 +31,7 @@ void manager_set_sysctl(Manager *manager);
 
 int link_get_ip_forwarding(Link *link, int family);
 int link_set_sysctl(Link *link);
-int link_set_ipv6_mtu(Link *link);
+int link_set_ipv6_mtu(Link *link, int log_level);
 
 const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
 IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
index 07e05bf2676ae6e93078d317b689a051f1a0e114..1572ca71022f0cc330572d640f59464d55100612 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include <sys/prctl.h>
+#include <unistd.h>
 
 #include "sd-daemon.h"
 
index 13e0dde4b4c7db79eb314c2d5571fdb4ed4cef69..1e09b9e1856a77e69bc5baa1dfe2788133b30a5a 100644 (file)
@@ -402,7 +402,7 @@ TEST(cg_get_keyed_attribute) {
         }
 
         assert_se(r == -ENOENT);
-        assert_se(val == NULL);
+        ASSERT_NULL(val);
 
         if (access("/sys/fs/cgroup/init.scope/cpu.stat", R_OK) < 0) {
                 log_info_errno(errno, "Skipping most of %s, /init.scope/cpu.stat not accessible: %m", __func__);
@@ -411,7 +411,7 @@ TEST(cg_get_keyed_attribute) {
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == -ENXIO);
         assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == 0);
-        assert_se(val == NULL);
+        ASSERT_NULL(val);
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 0);
         val = mfree(val);
index 06cf886729654934ac5021a50b47faccdd749fca..703c8f6c0368f001852067635c5dfcf51e917e19 100644 (file)
@@ -31,13 +31,13 @@ TEST(cg_split_spec) {
         assert_se(cg_split_spec("fo/obar:/", &c, &p) < 0);
 
         assert_se(cg_split_spec("/", &c, &p) >= 0);
-        assert_se(c == NULL);
+        ASSERT_NULL(c);
         assert_se(streq(p, "/"));
         p = mfree(p);
 
         assert_se(cg_split_spec("foo", &c, &p) >= 0);
         assert_se(streq(c, "foo"));
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
         c = mfree(c);
 }
 
index d0d7419eaaf546627a6299d65babb55e38203cfa..ab54107655aea474b17d0f8df73e0d28b990f5e3 100644 (file)
@@ -377,7 +377,7 @@ static void test_config_parse_one(unsigned i, const char *s) {
 
         case 15 ... 16:
                 assert_se(r == -ENOBUFS);
-                assert_se(setting1 == NULL);
+                ASSERT_NULL(setting1);
                 break;
 
         case 17:
index dc108cc2efef4ea55678c13295c7d01fca3292ad..f72a67c60c814ef13a0a20a51e34e44511cbf98a 100644 (file)
@@ -26,7 +26,7 @@ static void test_unit_escape_setting_one(
         assert_se(t = unit_escape_setting(s, 0, &a));
         assert_se(a_esc = cescape(t));
         log_debug("%s: [%s] â†’ [%s]", __func__, s_esc, a_esc);
-        assert_se(a == NULL);
+        ASSERT_NULL(a);
         assert_se(t == s);
 
         assert_se(t = unit_escape_setting(s, UNIT_ESCAPE_EXEC_SYNTAX_ENV, &b));
index b4beafc31d6279ff2ad2e4059cb4083fe451b844..128788c43711ff6a8f38cf1a74da3c573fc28dd0 100644 (file)
@@ -23,28 +23,28 @@ TEST(read_credential_strings) {
                 assert_se(saved = strdup(e));
 
         assert_se(read_credential_strings_many("foo", &x, "bar", &y) == 0);
-        assert_se(x == NULL);
-        assert_se(y == NULL);
+        ASSERT_NULL(x);
+        ASSERT_NULL(y);
 
         assert_se(mkdtemp_malloc(NULL, &tmp) >= 0);
 
         assert_se(setenv("CREDENTIALS_DIRECTORY", tmp, /* override= */ true) >= 0);
 
         assert_se(read_credential_strings_many("foo", &x, "bar", &y) == 0);
-        assert_se(x == NULL);
-        assert_se(y == NULL);
+        ASSERT_NULL(x);
+        ASSERT_NULL(y);
 
         assert_se(p = path_join(tmp, "bar"));
         assert_se(write_string_file(p, "piff", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0);
 
         assert_se(read_credential_strings_many("foo", &x, "bar", &y) == 0);
-        assert_se(x == NULL);
+        ASSERT_NULL(x);
         assert_se(streq(y, "piff"));
 
         assert_se(write_string_file(p, "paff", WRITE_STRING_FILE_TRUNCATE|WRITE_STRING_FILE_AVOID_NEWLINE) >= 0);
 
         assert_se(read_credential_strings_many("foo", &x, "bar", &y) == 0);
-        assert_se(x == NULL);
+        ASSERT_NULL(x);
         assert_se(streq(y, "paff"));
 
         p = mfree(p);
index 3fc6d623fdd460fe38a6b0b8f8d4e69f2ef55177..e2fce7f53d1b2e89328d5ca1edcf4e62cc051b0a 100644 (file)
@@ -71,7 +71,7 @@ TEST(load_env_file_1) {
         assert_se(streq(data[3], "g=g "));
         assert_se(streq(data[4], "h=ąęół Å›Ä‡Å„źżμ"));
         assert_se(streq(data[5], "i=i"));
-        assert_se(data[6] == NULL);
+        ASSERT_NULL(data[6]);
 }
 
 TEST(load_env_file_2) {
@@ -81,7 +81,7 @@ TEST(load_env_file_2) {
         _cleanup_strv_free_ char **data = NULL;
         assert_se(load_env_file(NULL, name, &data) == 0);
         assert_se(streq(data[0], "a=a"));
-        assert_se(data[1] == NULL);
+        ASSERT_NULL(data[1]);
 }
 
 TEST(load_env_file_3) {
@@ -92,7 +92,7 @@ TEST(load_env_file_3) {
         assert_se(load_env_file(NULL, name, &data) == 0);
         assert_se(streq(data[0], "normal1=line111"));
         assert_se(streq(data[1], "normal2=line222"));
-        assert_se(data[2] == NULL);
+        ASSERT_NULL(data[2]);
 }
 
 TEST(load_env_file_4) {
@@ -104,7 +104,7 @@ TEST(load_env_file_4) {
         assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
         assert_se(streq(data[1], "MODULE_0=coretemp"));
         assert_se(streq(data[2], "MODULE_1=f71882fg"));
-        assert_se(data[3] == NULL);
+        ASSERT_NULL(data[3]);
 }
 
 TEST(load_env_file_5) {
@@ -115,7 +115,7 @@ TEST(load_env_file_5) {
         assert_se(load_env_file(NULL, name, &data) == 0);
         assert_se(streq(data[0], "a="));
         assert_se(streq(data[1], "b="));
-        assert_se(data[2] == NULL);
+        ASSERT_NULL(data[2]);
 }
 
 TEST(load_env_file_6) {
@@ -128,7 +128,7 @@ TEST(load_env_file_6) {
         assert_se(streq(data[1], "b=$'"));
         assert_se(streq(data[2], "c= \\n\\t\\$\\`\\\\\n"));
         assert_se(streq(data[3], "d= \\n\\t$`\\\n"));
-        assert_se(data[4] == NULL);
+        ASSERT_NULL(data[4]);
 }
 
 TEST(load_env_file_invalid_utf8) {
index c267c2e34189116acae7c18b1d179e2eaf377151..6b7520bfb0bda20ed9bf33c26e441bbf5eea5472 100644 (file)
@@ -401,7 +401,7 @@ TEST(env_clean) {
         assert_se(streq(e[5], "another=final one"));
         assert_se(streq(e[6], "CRLF=\r\n"));
         assert_se(streq(e[7], "LESS_TERMCAP_mb=\x1b[01;31m"));
-        assert_se(e[8] == NULL);
+        ASSERT_NULL(e[8]);
 }
 
 TEST(env_name_is_valid) {
@@ -576,7 +576,7 @@ TEST(getenv_path_list) {
         assert_se(streq(path_list[2], "/hello/world"));
         assert_se(streq(path_list[3], "/path with spaces"));
         assert_se(streq(path_list[4], "/final"));
-        assert_se(path_list[5] == NULL);
+        ASSERT_NULL(path_list[5]);
 
         assert_se(unsetenv("TEST_GETENV_PATH_LIST") >= 0);
 }
index 0f10fe7e6f5aa37f71df699233009278927da964..beb8f5db2207bf3c94fb6245995a779472b1c337 100644 (file)
@@ -325,7 +325,7 @@ TEST(extract_first_word) {
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
         assert_se(streq(t, ""));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0);
         assert_se(!t);
@@ -335,25 +335,25 @@ TEST(extract_first_word) {
         assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
         assert_se(streq(t, "fooxbar"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "foo\\xbar";
         assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RETAIN_ESCAPE) > 0);
         assert_se(streq(t, "foo\\xbar"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "\\:";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, ":"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "a\\:b";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, "a:b"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "a\\ b:c";
         assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
@@ -362,7 +362,7 @@ TEST(extract_first_word) {
         assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, "c"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "a\\ b:c\\x";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
@@ -374,19 +374,19 @@ TEST(extract_first_word) {
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, "c\\x"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "\\:";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, ":"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "a\\:b";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, "a:b"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "a\\ b:c";
         assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
@@ -395,7 +395,7 @@ TEST(extract_first_word) {
         assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, "c"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "a\\ b:c\\x";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
@@ -407,7 +407,7 @@ TEST(extract_first_word) {
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, "c\\x"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = "\\:";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE) == -EINVAL);
@@ -426,7 +426,7 @@ TEST(extract_first_word) {
         assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_CUNESCAPE) == 1);
         assert_se(streq(t, "c"));
         free(t);
-        assert_se(p == NULL);
+        ASSERT_NULL(p);
 
         p = original = "foobar=\"waldo\"maldo, baldo";
         assert_se(extract_first_word(&p, &t, "=\", ", 0) > 0);
index ad98a920601d613e32da0fddc1dd9dc3a7292ce5..67437ea9d9f00e0234e693acea4be647c8b9e3d0 100644 (file)
@@ -84,7 +84,7 @@ TEST(parse_env_file) {
         assert_se(streq_ptr(a[10], "eleven=value"));
         assert_se(streq_ptr(a[11], "twelve=\\value"));
         assert_se(streq_ptr(a[12], "thirteen=\\value"));
-        assert_se(a[13] == NULL);
+        ASSERT_NULL(a[13]);
 
         strv_env_clean(a);
 
@@ -134,7 +134,7 @@ TEST(parse_env_file) {
         assert_se(streq(seven, "sevenval#nocomment"));
         assert_se(streq(eight, "eightval #nocomment"));
         assert_se(streq(nine, "nineval"));
-        assert_se(ten == NULL);
+        ASSERT_NULL(ten);
         assert_se(streq(eleven, "value"));
         assert_se(streq(twelve, "\\value"));
         assert_se(streq(thirteen, "\\value"));
@@ -201,7 +201,7 @@ TEST(parse_multiline_env_file) {
         assert_se(streq_ptr(a[0], "one=BAR    VAR\tGAR"));
         assert_se(streq_ptr(a[1], "two=bar    var\tgar"));
         assert_se(streq_ptr(a[2], "tri=bar     var \tgar "));
-        assert_se(a[3] == NULL);
+        ASSERT_NULL(a[3]);
 
         {
                 _cleanup_close_ int fd = mkostemp_safe(p);
@@ -256,7 +256,7 @@ TEST(merge_env_file) {
         assert_se(streq(a[7], "zzz=replacement"));
         assert_se(streq(a[8], "zzzz="));
         assert_se(streq(a[9], "zzzzz="));
-        assert_se(a[10] == NULL);
+        ASSERT_NULL(a[10]);
 
         r = merge_env_file(&a, NULL, t);
         assert_se(r >= 0);
@@ -275,7 +275,7 @@ TEST(merge_env_file) {
         assert_se(streq(a[7], "zzz=replacement"));
         assert_se(streq(a[8], "zzzz="));
         assert_se(streq(a[9], "zzzzz="));
-        assert_se(a[10] == NULL);
+        ASSERT_NULL(a[10]);
 }
 
 TEST(merge_env_file_invalid) {
index 9b3e73cce017231ae6ef6a1164619a7daf46738e..4fa47498c3ae077336598a4297eac161c58a4500 100644 (file)
@@ -31,7 +31,7 @@ TEST(glob_first) {
         assert_se(r == 0);
         r = glob_first("/tmp/test-glob_first*", &first);
         assert_se(r == 0);
-        assert_se(first == NULL);
+        ASSERT_NULL(first);
 }
 
 TEST(glob_exists) {
@@ -110,7 +110,7 @@ TEST(safe_glob) {
         assert_se(r == 0);
         assert_se(g.gl_pathc == 1);
         assert_se(streq(g.gl_pathv[0], fname));
-        assert_se(g.gl_pathv[1] == NULL);
+        ASSERT_NULL(g.gl_pathv[1]);
 
         (void) rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL);
 }
index 0d1f84579442f060e3dae5c71f173a1fed2e3a5f..75195887ff79744a4834137042081204b852dbb4 100644 (file)
@@ -231,13 +231,13 @@ TEST(hashmap_remove1) {
         char *r;
 
         r = hashmap_remove(NULL, "key 1");
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         m = hashmap_new(&string_hash_ops);
         assert_se(m);
 
         r = hashmap_remove(m, "no such key");
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         hashmap_put(m, "key 1", (void*) "val 1");
         hashmap_put(m, "key 2", (void*) "val 2");
@@ -259,13 +259,13 @@ TEST(hashmap_remove2) {
         void *r, *r2;
 
         r = hashmap_remove2(NULL, "key 1", &r2);
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         m = hashmap_new(&string_hash_ops);
         assert_se(m);
 
         r = hashmap_remove2(m, "no such key", &r2);
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         hashmap_put(m, strdup(key1), strdup(val1));
         hashmap_put(m, strdup(key2), strdup(val2));
@@ -289,13 +289,13 @@ TEST(hashmap_remove_value) {
         char val2[] = "val 2";
 
         r = hashmap_remove_value(NULL, "key 1", val1);
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         m = hashmap_new(&string_hash_ops);
         assert_se(m);
 
         r = hashmap_remove_value(m, "key 1", val1);
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         hashmap_put(m, "key 1", val1);
         hashmap_put(m, "key 2", val2);
@@ -308,7 +308,7 @@ TEST(hashmap_remove_value) {
         assert_se(!hashmap_get(m, "key 1"));
 
         r = hashmap_remove_value(m, "key 2", val1);
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         r = hashmap_get(m, "key 2");
         assert_se(streq(r, "val 2"));
@@ -599,7 +599,7 @@ TEST(hashmap_get) {
         assert_se(val);
 
         r = hashmap_get(NULL, "Key 1");
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         m = hashmap_new(&string_hash_ops);
 
@@ -609,7 +609,7 @@ TEST(hashmap_get) {
         assert_se(streq(r, val));
 
         r = hashmap_get(m, "no such key");
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         assert_se(m);
 }
@@ -628,7 +628,7 @@ TEST(hashmap_get2) {
         assert_se(key_copy);
 
         r = hashmap_get2(NULL, key_orig, &key_copy);
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         m = hashmap_new(&string_hash_ops);
 
@@ -641,7 +641,7 @@ TEST(hashmap_get2) {
         assert_se(streq(key_orig, key_copy));
 
         r = hashmap_get2(m, "no such key", NULL);
-        assert_se(r == NULL);
+        ASSERT_NULL(r);
 
         assert_se(m);
 }
@@ -801,7 +801,7 @@ TEST(hashmap_first_key) {
         assert_se(hashmap_put(m, "key 2", NULL) == 1);
 #ifdef ORDERED
         assert_se(streq(hashmap_first_key(m), "key 1"));
-        assert_se(hashmap_remove(m, "key 1") == NULL);
+        ASSERT_NULL(hashmap_remove(m, "key 1"));
         assert_se(streq(hashmap_first_key(m), "key 2"));
 #endif
 }
index cf4fca27e3f7aef5b55cf9658004d449eddff689..7ff270c3e08ef64aeae85622e628932d34bacd59 100644 (file)
@@ -98,8 +98,8 @@ TEST(iterated_cache) {
         hashmap_clear(m);
         compare_cache(m, c);
 
-        assert_se(hashmap_free(m) == NULL);
-        assert_se(iterated_cache_free(c) == NULL);
+        ASSERT_NULL(hashmap_free(m));
+        ASSERT_NULL(iterated_cache_free(c));
 }
 
 TEST(hashmap_put_strdup) {
@@ -147,7 +147,7 @@ TEST(hashmap_put_strdup_null) {
         assert_se(hashmap_contains(m, "xxx"));
 
         s = hashmap_get(m, "xxx");
-        assert_se(s == NULL);
+        ASSERT_NULL(s);
 }
 
 /* This file tests in test-hashmap-plain.c, and tests in test-hashmap-ordered.c, which is generated
index cb0adc2643774d90640ff6bdb5168661bacbd765..2762ca64a5c94a51aae5e6b332379b07e533742f 100644 (file)
@@ -362,7 +362,7 @@ TEST(json_parse_file_empty) {
 
         assert_se(fopen_unlocked("/dev/null", "re", &f) >= 0);
         assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -ENODATA);
-        assert_se(v == NULL);
+        ASSERT_NULL(v);
 }
 
 TEST(json_parse_file_invalid) {
@@ -371,7 +371,7 @@ TEST(json_parse_file_invalid) {
 
         assert_se(f = fmemopen_unlocked((void*) "kookoo", 6, "r"));
         assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -EINVAL);
-        assert_se(v == NULL);
+        ASSERT_NULL(v);
 }
 
 TEST(source) {
index 87f7c7b3d466fe4d8afed107bab640502695da38..6c6407028468b09e1779534b9b51ea553d98b987 100644 (file)
@@ -17,8 +17,8 @@ int main(int argc, const char *argv[]) {
 
         LIST_HEAD_INIT(head);
         LIST_HEAD_INIT(head2);
-        assert_se(head == NULL);
-        assert_se(head2 == NULL);
+        ASSERT_NULL(head);
+        ASSERT_NULL(head2);
 
         for (i = 0; i < ELEMENTSOF(items); i++) {
                 LIST_INIT(item_list, &items[i]);
@@ -49,7 +49,7 @@ int main(int argc, const char *argv[]) {
 
         assert_se(!LIST_JUST_US(item_list, head));
 
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[1].item_list_next == &items[0]);
         assert_se(items[2].item_list_next == &items[1]);
         assert_se(items[3].item_list_next == &items[2]);
@@ -57,7 +57,7 @@ int main(int argc, const char *argv[]) {
         assert_se(items[0].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[2]);
         assert_se(items[2].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         list_item *cursor = LIST_FIND_HEAD(item_list, &items[0]);
         assert_se(cursor == &items[3]);
@@ -68,16 +68,16 @@ int main(int argc, const char *argv[]) {
         assert_se(LIST_REMOVE(item_list, head, &items[1]) == &items[1]);
         assert_se(LIST_JUST_US(item_list, &items[1]));
 
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[2].item_list_next == &items[0]);
         assert_se(items[3].item_list_next == &items[2]);
 
         assert_se(items[0].item_list_prev == &items[2]);
         assert_se(items[2].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_INSERT_AFTER(item_list, head, &items[3], &items[1]) == &items[1]);
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[2].item_list_next == &items[0]);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[3].item_list_next == &items[1]);
@@ -85,21 +85,21 @@ int main(int argc, const char *argv[]) {
         assert_se(items[0].item_list_prev == &items[2]);
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_REMOVE(item_list, head, &items[1]) == &items[1]);
         assert_se(LIST_JUST_US(item_list, &items[1]));
 
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[2].item_list_next == &items[0]);
         assert_se(items[3].item_list_next == &items[2]);
 
         assert_se(items[0].item_list_prev == &items[2]);
         assert_se(items[2].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_INSERT_BEFORE(item_list, head, &items[2], &items[1]) == &items[1]);
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[2].item_list_next == &items[0]);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[3].item_list_next == &items[1]);
@@ -107,21 +107,21 @@ int main(int argc, const char *argv[]) {
         assert_se(items[0].item_list_prev == &items[2]);
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_REMOVE(item_list, head, &items[0]) == &items[0]);
         assert_se(LIST_JUST_US(item_list, &items[0]));
 
-        assert_se(items[2].item_list_next == NULL);
+        ASSERT_NULL(items[2].item_list_next);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[3].item_list_next == &items[1]);
 
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_INSERT_BEFORE(item_list, head, &items[3], &items[0]) == &items[0]);
-        assert_se(items[2].item_list_next == NULL);
+        ASSERT_NULL(items[2].item_list_next);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[3].item_list_next == &items[1]);
         assert_se(items[0].item_list_next == &items[3]);
@@ -129,22 +129,22 @@ int main(int argc, const char *argv[]) {
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[3]);
         assert_se(items[3].item_list_prev == &items[0]);
-        assert_se(items[0].item_list_prev == NULL);
+        ASSERT_NULL(items[0].item_list_prev);
         assert_se(head == &items[0]);
 
         assert_se(LIST_REMOVE(item_list, head, &items[0]) == &items[0]);
         assert_se(LIST_JUST_US(item_list, &items[0]));
 
-        assert_se(items[2].item_list_next == NULL);
+        ASSERT_NULL(items[2].item_list_next);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[3].item_list_next == &items[1]);
 
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_INSERT_BEFORE(item_list, head, NULL, &items[0]) == &items[0]);
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[2].item_list_next == &items[0]);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[3].item_list_next == &items[1]);
@@ -152,27 +152,27 @@ int main(int argc, const char *argv[]) {
         assert_se(items[0].item_list_prev == &items[2]);
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_REMOVE(item_list, head, &items[0]) == &items[0]);
         assert_se(LIST_JUST_US(item_list, &items[0]));
 
-        assert_se(items[2].item_list_next == NULL);
+        ASSERT_NULL(items[2].item_list_next);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[3].item_list_next == &items[1]);
 
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_REMOVE(item_list, head, &items[1]) == &items[1]);
         assert_se(LIST_JUST_US(item_list, &items[1]));
 
-        assert_se(items[2].item_list_next == NULL);
+        ASSERT_NULL(items[2].item_list_next);
         assert_se(items[3].item_list_next == &items[2]);
 
         assert_se(items[2].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_REMOVE(item_list, head, &items[2]) == &items[2]);
         assert_se(LIST_JUST_US(item_list, &items[2]));
@@ -181,7 +181,7 @@ int main(int argc, const char *argv[]) {
         assert_se(LIST_REMOVE(item_list, head, &items[3]) == &items[3]);
         assert_se(LIST_JUST_US(item_list, &items[3]));
 
-        assert_se(head == NULL);
+        ASSERT_NULL(head);
 
         for (i = 0; i < ELEMENTSOF(items); i++) {
                 assert_se(LIST_JUST_US(item_list, &items[i]));
@@ -193,9 +193,9 @@ int main(int argc, const char *argv[]) {
         assert_se(items[0].item_list_next == &items[1]);
         assert_se(items[1].item_list_next == &items[2]);
         assert_se(items[2].item_list_next == &items[3]);
-        assert_se(items[3].item_list_next == NULL);
+        ASSERT_NULL(items[3].item_list_next);
 
-        assert_se(items[0].item_list_prev == NULL);
+        ASSERT_NULL(items[0].item_list_prev);
         assert_se(items[1].item_list_prev == &items[0]);
         assert_se(items[2].item_list_prev == &items[1]);
         assert_se(items[3].item_list_prev == &items[2]);
@@ -203,7 +203,7 @@ int main(int argc, const char *argv[]) {
         for (i = 0; i < ELEMENTSOF(items); i++)
                 assert_se(LIST_REMOVE(item_list, head, &items[i]) == &items[i]);
 
-        assert_se(head == NULL);
+        ASSERT_NULL(head);
 
         for (i = 0; i < ELEMENTSOF(items) / 2; i++) {
                 LIST_INIT(item_list, &items[i]);
@@ -217,20 +217,20 @@ int main(int argc, const char *argv[]) {
                 assert_se(LIST_PREPEND(item_list, head2, &items[i]) == &items[i]);
         }
 
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[1].item_list_next == &items[0]);
-        assert_se(items[2].item_list_next == NULL);
+        ASSERT_NULL(items[2].item_list_next);
         assert_se(items[3].item_list_next == &items[2]);
 
         assert_se(items[0].item_list_prev == &items[1]);
-        assert_se(items[1].item_list_prev == NULL);
+        ASSERT_NULL(items[1].item_list_prev);
         assert_se(items[2].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_JOIN(item_list, head2, head) == head2);
-        assert_se(head == NULL);
+        ASSERT_NULL(head);
 
-        assert_se(items[0].item_list_next == NULL);
+        ASSERT_NULL(items[0].item_list_next);
         assert_se(items[1].item_list_next == &items[0]);
         assert_se(items[2].item_list_next == &items[1]);
         assert_se(items[3].item_list_next == &items[2]);
@@ -238,16 +238,16 @@ int main(int argc, const char *argv[]) {
         assert_se(items[0].item_list_prev == &items[1]);
         assert_se(items[1].item_list_prev == &items[2]);
         assert_se(items[2].item_list_prev == &items[3]);
-        assert_se(items[3].item_list_prev == NULL);
+        ASSERT_NULL(items[3].item_list_prev);
 
         assert_se(LIST_JOIN(item_list, head, head2) == head);
-        assert_se(head2 == NULL);
+        ASSERT_NULL(head2);
         assert_se(head);
 
         for (i = 0; i < ELEMENTSOF(items); i++)
                 assert_se(LIST_REMOVE(item_list, head, &items[i]) == &items[i]);
 
-        assert_se(head == NULL);
+        ASSERT_NULL(head);
 
         assert_se(LIST_PREPEND(item_list, head, items + 0) == items + 0);
         assert_se(LIST_PREPEND(item_list, head, items + 1) == items + 1);
@@ -256,7 +256,7 @@ int main(int argc, const char *argv[]) {
         assert_se(LIST_POP(item_list, head) == items + 2);
         assert_se(LIST_POP(item_list, head) == items + 1);
         assert_se(LIST_POP(item_list, head) == items + 0);
-        assert_se(LIST_POP(item_list, head) == NULL);
+        ASSERT_NULL(LIST_POP(item_list, head));
 
         /* No-op on an empty list */
 
@@ -269,7 +269,7 @@ int main(int argc, const char *argv[]) {
 
         LIST_CLEAR(item_list, head, free);
 
-        assert_se(head == NULL);
+        ASSERT_NULL(head);
 
         /* A list can be cleared partially */
 
@@ -280,7 +280,7 @@ int main(int argc, const char *argv[]) {
         LIST_CLEAR(item_list, head->item_list_next, free);
 
         assert_se(head == items + 0);
-        assert_se(head->item_list_next == NULL);
+        ASSERT_NULL(head->item_list_next);
 
         return 0;
 }
index 8d2cec0c01bd6394c980c849cb74db4a0184ebf8..658aa8878ee8d43d53a457e52a3857f3aa841ba3 100644 (file)
@@ -139,7 +139,7 @@ TEST(config_parse_exec) {
                               "LValue", 0, "/RValue/ argv0 r1",
                               &c, u);
         assert_se(r == -ENOEXEC);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* honour_argv0 */");
         r = config_parse_exec(NULL, "fake", 3, "section", 1,
@@ -154,14 +154,14 @@ TEST(config_parse_exec) {
                               "LValue", 0, "@/RValue",
                               &c, u);
         assert_se(r == -ENOEXEC);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* no command, whitespace only, reset */");
         r = config_parse_exec(NULL, "fake", 3, "section", 1,
                               "LValue", 0, "",
                               &c, u);
         assert_se(r == 0);
-        assert_se(c == NULL);
+        ASSERT_NULL(c);
 
         log_info("/* ignore && honour_argv0 */");
         r = config_parse_exec(NULL, "fake", 4, "section", 1,
@@ -184,14 +184,14 @@ TEST(config_parse_exec) {
                               "LValue", 0, "--/RValue argv0 r1",
                               &c, u);
         assert_se(r == 0);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* ignore && ignore (2) */");
         r = config_parse_exec(NULL, "fake", 4, "section", 1,
                               "LValue", 0, "-@-/RValue argv0 r1",
                               &c, u);
         assert_se(r == 0);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* semicolon */");
         r = config_parse_exec(NULL, "fake", 5, "section", 1,
@@ -227,7 +227,7 @@ TEST(config_parse_exec) {
         c1 = c1->command_next;
         check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
 
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* trailing semicolon, no whitespace */");
         r = config_parse_exec(NULL, "fake", 5, "section", 1,
@@ -238,7 +238,7 @@ TEST(config_parse_exec) {
         c1 = c1->command_next;
         check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
 
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* trailing semicolon in single quotes */");
         r = config_parse_exec(NULL, "fake", 5, "section", 1,
@@ -366,7 +366,7 @@ TEST(config_parse_exec) {
                                       "LValue", 0, path,
                                       &c, u);
                 assert_se(r == -ENOEXEC);
-                assert_se(c1->command_next == NULL);
+                ASSERT_NULL(c1->command_next);
         }
 
         log_info("/* valid character: \\s */");
@@ -392,35 +392,35 @@ TEST(config_parse_exec) {
                               "LValue", 0, "/path\\",
                               &c, u);
         assert_se(r == -ENOEXEC);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* missing ending ' */");
         r = config_parse_exec(NULL, "fake", 4, "section", 1,
                               "LValue", 0, "/path 'foo",
                               &c, u);
         assert_se(r == -ENOEXEC);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* missing ending ' with trailing backslash */");
         r = config_parse_exec(NULL, "fake", 4, "section", 1,
                               "LValue", 0, "/path 'foo\\",
                               &c, u);
         assert_se(r == -ENOEXEC);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* invalid space between modifiers */");
         r = config_parse_exec(NULL, "fake", 4, "section", 1,
                               "LValue", 0, "- /path",
                               &c, u);
         assert_se(r == 0);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* only modifiers, no path */");
         r = config_parse_exec(NULL, "fake", 4, "section", 1,
                               "LValue", 0, "-",
                               &c, u);
         assert_se(r == 0);
-        assert_se(c1->command_next == NULL);
+        ASSERT_NULL(c1->command_next);
 
         log_info("/* long arg */"); /* See issue #22957. */
 
@@ -442,7 +442,7 @@ TEST(config_parse_exec) {
                               "LValue", 0, "",
                               &c, u);
         assert_se(r == 0);
-        assert_se(c == NULL);
+        ASSERT_NULL(c);
 
         exec_command_free_list(c);
 }
index 1bd00d1af110860d00643bcc28da0684064e3177..27a41e863d22433da2cbbefd173390ca92fc8737 100644 (file)
@@ -328,7 +328,7 @@ static int run(int argc, char *argv[]) {
         log_notice("All threads started now.");
 
         if (arg_n_threads == 1)
-                assert_se(thread_func(FD_TO_PTR(fd)) == NULL);
+                ASSERT_NULL(thread_func(FD_TO_PTR(fd)));
         else
                 for (unsigned i = 0; i < arg_n_threads; i++) {
                         log_notice("Joining thread #%u.", i);
index 017a20f540ae1fd1bb0ba94ce52a5b8dd8ae21a7..6a6e7a0962f94c3f1236df33db3e217e9bf38d0d 100644 (file)
@@ -500,12 +500,12 @@ TEST(FOREACH_ARGUMENT) {
         FOREACH_ARGUMENT(p, p_1, NULL, p_2, p_3, NULL, p_4, NULL) {
                 switch (i++) {
                 case 0: assert_se(p == p_1); break;
-                case 1: assert_se(p == NULL); break;
+                case 1: ASSERT_NULL(p); break;
                 case 2: assert_se(p == p_2); break;
                 case 3: assert_se(p == p_3); break;
-                case 4: assert_se(p == NULL); break;
+                case 4: ASSERT_NULL(p); break;
                 case 5: assert_se(p == p_4); break;
-                case 6: assert_se(p == NULL); break;
+                case 6: ASSERT_NULL(p); break;
                 default: assert_se(false);
                 }
         }
@@ -525,20 +525,20 @@ TEST(FOREACH_ARGUMENT) {
         FOREACH_ARGUMENT(v, v_1, NULL, u32p, v_3, p_2, p_4, v_2, NULL) {
                 switch (i++) {
                 case 0: assert_se(v == v_1); break;
-                case 1: assert_se(v == NULL); break;
+                case 1: ASSERT_NULL(v); break;
                 case 2: assert_se(v == u32p); break;
                 case 3: assert_se(v == v_3); break;
                 case 4: assert_se(v == p_2); break;
                 case 5: assert_se(v == p_4); break;
                 case 6: assert_se(v == v_2); break;
-                case 7: assert_se(v == NULL); break;
+                case 7: ASSERT_NULL(v); break;
                 default: assert_se(false);
                 }
         }
         assert_se(i == 8);
         i = 0;
         FOREACH_ARGUMENT(v, NULL) {
-                assert_se(v == NULL);
+                ASSERT_NULL(v);
                 assert_se(i++ == 0);
         }
         assert_se(i == 1);
index 77fce983b912af6e1504c9a6720a27cfaa147d4a..9bacc7b511244ea8ed81ea0a0defe515a21dd4f0 100644 (file)
@@ -31,15 +31,15 @@ TEST(mount_option_mangle) {
 
         assert_se(mount_option_mangle(NULL, MS_RDONLY|MS_NOSUID, &f, &opts) == 0);
         assert_se(f == (MS_RDONLY|MS_NOSUID));
-        assert_se(opts == NULL);
+        ASSERT_NULL(opts);
 
         assert_se(mount_option_mangle("", MS_RDONLY|MS_NOSUID, &f, &opts) == 0);
         assert_se(f == (MS_RDONLY|MS_NOSUID));
-        assert_se(opts == NULL);
+        ASSERT_NULL(opts);
 
         assert_se(mount_option_mangle("ro,nosuid,nodev,noexec", 0, &f, &opts) == 0);
         assert_se(f == (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC));
-        assert_se(opts == NULL);
+        ASSERT_NULL(opts);
 
         assert_se(mount_option_mangle("ro,nosuid,nodev,noexec,mode=0755", 0, &f, &opts) == 0);
         assert_se(f == (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC));
index f03fcffc6246101b40b0748655d6271029bafe7e..8c1b0d407e36c0275ab00ef72ce76220e61b79c6 100644 (file)
@@ -84,7 +84,7 @@ static int test_tunnel_configure(sd_netlink *rtnl) {
 
         assert_se(sd_netlink_call(rtnl, m, -1, 0) == 1);
 
-        assert_se((m = sd_netlink_message_unref(m)) == NULL);
+        ASSERT_NULL((m = sd_netlink_message_unref(m)));
 
         /* sit */
         assert_se(sd_rtnl_message_new_link(rtnl, &n, RTM_NEWLINK, 0) >= 0);
@@ -110,7 +110,7 @@ static int test_tunnel_configure(sd_netlink *rtnl) {
 
         assert_se(sd_netlink_call(rtnl, n, -1, 0) == 1);
 
-        assert_se((n = sd_netlink_message_unref(n)) == NULL);
+        ASSERT_NULL((n = sd_netlink_message_unref(n)));
 
         return EXIT_SUCCESS;
 }
@@ -126,7 +126,7 @@ int main(int argc, char *argv[]) {
 
         r = test_tunnel_configure(rtnl);
 
-        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+        ASSERT_NULL((rtnl = sd_netlink_unref(rtnl)));
 
         return r;
 }
index dfdd1ab5b45d4a56e2a1dd512887546f661ecb10..51dc492e965dee9bfb1155fe24d42066208983bb 100644 (file)
@@ -95,7 +95,7 @@ TEST(invalid) {
 
         DEFINE_HEX_PTR(key, "2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b7b");
         assert_se(openssl_pkey_from_pem(key, key_len, &pkey) == -EIO);
-        assert_se(pkey == NULL);
+        ASSERT_NULL(pkey);
 }
 
 static const struct {
index cf3d54288abb9899a2aaaa76f72d923abd00b8e4..3772a874360e314386852abb4e154ebf75738441 100644 (file)
@@ -26,7 +26,7 @@ TEST(parse_path_argument) {
         assert_se(streq(path, "/"));
 
         assert_se(parse_path_argument("/", true, &path) == 0);
-        assert_se(path == NULL);
+        ASSERT_NULL(path);
 }
 
 TEST(parse_signal_argument) {
index 5f36ae49f05ff3e7f9fc7ab10c0e11aa14836044..139bed76c4df3a9814d34e18bb0a81d7c27263f2 100644 (file)
@@ -687,7 +687,7 @@ TEST(path_strv_resolve) {
         _cleanup_strv_free_ char **search_dirs = NULL;
         _cleanup_strv_free_ char **absolute_dirs = NULL;
 
-        assert_se(mkdtemp(tmp_dir) != NULL);
+        ASSERT_NOT_NULL(mkdtemp(tmp_dir));
 
         search_dirs = strv_new("/dir1", "/dir2", "/dir3");
         assert_se(search_dirs);
@@ -986,7 +986,7 @@ TEST(path_find_last_component) {
 }
 
 TEST(last_path_component) {
-        assert_se(last_path_component(NULL) == NULL);
+        ASSERT_NULL(last_path_component(NULL));
         assert_se(streq(last_path_component("a/b/c"), "c"));
         assert_se(streq(last_path_component("a/b/c/"), "c/"));
         assert_se(streq(last_path_component("/"), "/"));
index d1b1ce9170a39c30445e990265c535c818f2e3da..92c22d3b20d78d346f82131ccfbecbee1253f61d 100644 (file)
@@ -70,10 +70,10 @@ TEST(struct) {
         assert_se(q = prioq_new((compare_func_t) test_compare));
         assert_se(s = set_new(&test_hash_ops));
 
-        assert_se(prioq_peek(q) == NULL);
-        assert_se(prioq_peek_by_index(q, 0) == NULL);
-        assert_se(prioq_peek_by_index(q, 1) == NULL);
-        assert_se(prioq_peek_by_index(q, UINT_MAX) == NULL);
+        ASSERT_NULL(prioq_peek(q));
+        ASSERT_NULL(prioq_peek_by_index(q, 0));
+        ASSERT_NULL(prioq_peek_by_index(q, 1));
+        ASSERT_NULL(prioq_peek_by_index(q, UINT_MAX));
 
         for (i = 0; i < SET_SIZE; i++) {
                 assert_se(t = new0(struct test, 1));
@@ -87,7 +87,7 @@ TEST(struct) {
 
         for (i = 0; i < SET_SIZE; i++)
                 assert_se(prioq_peek_by_index(q, i));
-        assert_se(prioq_peek_by_index(q, SET_SIZE) == NULL);
+        ASSERT_NULL(prioq_peek_by_index(q, SET_SIZE));
 
         unsigned count = 0;
         PRIOQ_FOREACH_ITEM(q, t) {
index 027b2a401eb1d2a3dda7662938818effbfb29d09..3b3fa9d12430c8d72d426cafcdd883aebcd5ff5d 100644 (file)
@@ -651,7 +651,7 @@ TEST(safe_fork) {
 
 TEST(pid_to_ptr) {
         assert_se(PTR_TO_PID(NULL) == 0);
-        assert_se(PID_TO_PTR(0) == NULL);
+        ASSERT_NULL(PID_TO_PTR(0));
 
         assert_se(PTR_TO_PID(PID_TO_PTR(1)) == 1);
         assert_se(PTR_TO_PID(PID_TO_PTR(2)) == 2);
index e14f27df7935c75312274972bfd118b679fdd901..6a68d28090af69c16f7fd4f039f49003af8a258c 100644 (file)
@@ -119,7 +119,7 @@ TEST(setrlimit) {
         assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0);
 
         assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "NOFILE"));
-        assert_se(rlimit_to_string(-1) == NULL);
+        ASSERT_NULL(rlimit_to_string(-1));
 
         assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0);
         assert_se(setrlimit_closest(RLIMIT_NOFILE, &old) == 0);
index 27e6a20e09d40652a0b622bad72a4038c657e592..21cfe701570dd36cc84751e3a903e8512f381a1a 100644 (file)
@@ -61,7 +61,7 @@ TEST(secure_bits_basic) {
 
         /* Bits to string with check */
         assert_se(secure_bits_to_string_alloc_with_check(INT_MAX, &str) == -EINVAL);
-        assert_se(str == NULL);
+        ASSERT_NULL(str);
         assert_se(secure_bits_to_string_alloc_with_check(
                                 (1 << SECURE_KEEP_CAPS) | (1 << SECURE_KEEP_CAPS_LOCKED),
                                 &str) >= 0);
index 84a897801a5595546d0665d3878b865e4fb9a837..fb65573e7a7908e7c1c2de60b23cee9943359fb3 100644 (file)
@@ -66,7 +66,7 @@ static int test_socket_bind(
         fputc('\n', stderr);
 
         exec_start = strjoin("-timeout --preserve-status -sSIGTERM 1s ", netcat_path, " -l ", port, " -vv");
-        assert_se(exec_start != NULL);
+        ASSERT_NOT_NULL(exec_start);
 
         r = config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart",
                         SERVICE_EXEC_START, exec_start, SERVICE(u)->exec_command, u);
index 39a7142b5bb645a7af65cdd649c14a6c2ea6bf80..7198c6734688a9fb9b87bdc685725d18bdd6811e 100644 (file)
@@ -37,7 +37,7 @@ TEST(strbuf) {
         assert_se(streq(l[2], "foo"));
         assert_se(streq(l[3], "bar"));
         assert_se(streq(l[4], "waldorf"));
-        assert_se(l[5] == NULL);
+        ASSERT_NULL(l[5]);
 
         assert_se(sb->nodes_count == 5); /* root + 4 non-duplicates */
         assert_se(sb->dedup_count == 4);
@@ -67,7 +67,7 @@ TEST(strbuf) {
         assert_se(streq(sb->buf + h, ""));
 
         strbuf_complete(sb);
-        assert_se(sb->root == NULL);
+        ASSERT_NULL(sb->root);
 }
 
 DEFINE_TEST_MAIN(LOG_INFO);
index 67f332db8edb432510573390891351f8d7e60d1c..a84125d7228d79c46c25e7b254c255542046d814 100644 (file)
@@ -460,7 +460,7 @@ static void check(const char *test, char** expected, bool trailing) {
                 assert_se(streq(word, expected[i++]));
                 printf("<%s>\n", word);
         }
-        assert_se(expected[i] == NULL);
+        ASSERT_NULL(expected[i]);
 }
 
 TEST(foreach_word_quoted) {
@@ -802,7 +802,7 @@ TEST(string_contains_word_strv) {
         assert_se(streq(w, "a"));
 
         assert_se(!string_contains_word_strv("a b cc", NULL, STRV_MAKE("d"), &w));
-        assert_se(w == NULL);
+        ASSERT_NULL(w);
 
         assert_se(string_contains_word_strv("a b cc", NULL, STRV_MAKE("b", "a"), &w));
         assert_se(streq(w, "a"));
@@ -814,7 +814,7 @@ TEST(string_contains_word_strv) {
         assert_se(streq(w, "b"));
 
         assert_se(!string_contains_word_strv("a b cc", NULL, STRV_MAKE(""), &w));
-        assert_se(w == NULL);
+        ASSERT_NULL(w);
 
         assert_se(string_contains_word_strv("a b  cc", " ", STRV_MAKE(""), &w));
         assert_se(streq(w, ""));
index 47ad0eb639c30407b91b2ec06350afccc8953176..63a88c2301329f58c37d5ffa955799b4374e9274 100644 (file)
@@ -217,7 +217,7 @@ static void test_strv_unquote_one(const char *quoted, char **list) {
         STRV_FOREACH(t, s)
                 assert_se(streq(list[i++], *t));
 
-        assert_se(list[i] == NULL);
+        ASSERT_NULL(list[i]);
 }
 
 TEST(strv_unquote) {
@@ -245,7 +245,7 @@ static void test_invalid_unquote_one(const char *quoted) {
         log_info("/* %s */", __func__);
 
         r = strv_split_full(&s, quoted, WHITESPACE, EXTRACT_UNQUOTE);
-        assert_se(s == NULL);
+        ASSERT_NULL(s);
         assert_se(r == -EINVAL);
 }
 
@@ -601,7 +601,7 @@ TEST(strv_extend_with_size) {
         assert_se(streq(a[1], "test1"));
         assert_se(streq(a[2], "test2"));
         assert_se(streq(a[3], "test3"));
-        assert_se(a[4] == NULL);
+        ASSERT_NULL(a[4]);
 }
 
 TEST(strv_extend) {
@@ -918,7 +918,7 @@ TEST(strv_extend_n) {
         assert_se(streq(v[4], "waldo"));
         assert_se(streq(v[5], "piep"));
         assert_se(streq(v[6], "piep"));
-        assert_se(v[7] == NULL);
+        ASSERT_NULL(v[7]);
 
         v = strv_free(v);
 
@@ -926,7 +926,7 @@ TEST(strv_extend_n) {
         assert_se(strv_extend_n(&v, "bar", 0) >= 0);
 
         assert_se(streq(v[0], "foo"));
-        assert_se(v[1] == NULL);
+        ASSERT_NULL(v[1]);
 }
 
 TEST(foreach_string) {
@@ -1013,10 +1013,10 @@ TEST(strv_copy_n) {
 TEST(strv_find_first_field) {
         char **haystack = STRV_MAKE("a", "b", "c", "d", "e", "f", "g", "h", "i", "j");
 
-        assert_se(strv_find_first_field(NULL, NULL) == NULL);
-        assert_se(strv_find_first_field(NULL, haystack) == NULL);
-        assert_se(strv_find_first_field(STRV_MAKE("k", "l", "m", "d", "b"), NULL) == NULL);
-        assert_se(strv_find_first_field(STRV_MAKE("k", "l", "m", "d", "b"), haystack) == NULL);
+        ASSERT_NULL(strv_find_first_field(NULL, NULL));
+        ASSERT_NULL(strv_find_first_field(NULL, haystack));
+        ASSERT_NULL(strv_find_first_field(STRV_MAKE("k", "l", "m", "d", "b"), NULL));
+        ASSERT_NULL(strv_find_first_field(STRV_MAKE("k", "l", "m", "d", "b"), haystack));
         assert_se(streq_ptr(strv_find_first_field(STRV_MAKE("k", "l", "m", "d", "a", "c"), haystack), "b"));
         assert_se(streq_ptr(strv_find_first_field(STRV_MAKE("k", "l", "m", "d", "c", "a"), haystack), "d"));
         assert_se(streq_ptr(strv_find_first_field(STRV_MAKE("i", "k", "l", "m", "d", "c", "a", "b"), haystack), "j"));
index 254c4c5e8bc2218a1a1baf4e44a3f7bc84d569db..0d42df9d9fce7cd020d4f6389205bba0f01a78fb 100644 (file)
@@ -678,7 +678,7 @@ TEST(parse_pcr_argument) {
         assert_se(tpm2_parse_pcr_argument("1,2=123456abc", &v, &n_v) < 0);
         assert_se(tpm2_parse_pcr_argument("1,2:invalid", &v, &n_v) < 0);
         assert_se(tpm2_parse_pcr_argument("1:sha1=invalid", &v, &n_v) < 0);
-        assert_se(v == NULL);
+        ASSERT_NULL(v);
         assert_se(n_v == 0);
 
         check_parse_pcr_argument_to_mask("", 0x0);
index 271af24c8040af4d5a89be7a296f2880def43643..423a9be380259bc5683d966a27a0ea61eb13c8cc 100644 (file)
@@ -54,7 +54,7 @@ int main(int argc, char *argv[]) {
         assert_se(pid >= 0);
 
         assert_se(hashmap_isempty(m->watch_pids));
-        assert_se(manager_get_unit_by_pid(m, pid) == NULL);
+        ASSERT_NULL(manager_get_unit_by_pid(m, pid));
 
         assert_se(unit_watch_pid(a, pid, false) >= 0);
         assert_se(manager_get_unit_by_pid(m, pid) == a);
@@ -93,10 +93,10 @@ int main(int argc, char *argv[]) {
         assert_se(manager_get_unit_by_pid(m, pid) == c);
 
         unit_unwatch_pid(c, pid);
-        assert_se(manager_get_unit_by_pid(m, pid) == NULL);
+        ASSERT_NULL(manager_get_unit_by_pid(m, pid));
 
         unit_unwatch_pid(c, pid);
-        assert_se(manager_get_unit_by_pid(m, pid) == NULL);
+        ASSERT_NULL(manager_get_unit_by_pid(m, pid));
 
         return 0;
 }
index ac50700401484aeb0195f4802be40674ec67aa3a..11502fdb53599d682f87476227accf8e9e2b7781 100644 (file)
@@ -6,8 +6,6 @@ Name=veth99
 IPv6AcceptRA=true
 
 [IPv6AcceptRA]
-Token=prefixstable:2002:da8:1::
-Token=prefixstable:2002:da8:1::,86b123b969ba4b7eb8b3d8605123525a
 # invalid tokens
 Token=prefixstable:2002:da8:1::,00000000000000000000000000000000
 Token=prefixstable:2002:da8:1::,
@@ -17,3 +15,10 @@ Token=prefixstable@
 Token=static
 Token=static:
 Token=static:::
+# valid token
+Token=prefixstable:2002:da8:1::
+Token=prefixstable:2002:da8:1::,86b123b969ba4b7eb8b3d8605123525a
+# reset token
+Token=
+# set token again
+Token=prefixstable:2002:da8:1::,86b123b969ba4b7eb8b3d8605123525a
diff --git a/test/test-network/conf/25-veth-peer-no-address.network b/test/test-network/conf/25-veth-peer-no-address.network
new file mode 100644 (file)
index 0000000..dbea3bd
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=veth-peer
+
+[Network]
+IPv6AcceptRA=no
index 4c69bc903366efa8492b706ec0d9aea439985f72..3732e7a0d7ec0e231bc937a3e1cf15b34e5cdb04 100755 (executable)
@@ -5572,15 +5572,91 @@ class NetworkdRATests(unittest.TestCase, Utilities):
         self.wait_route_dropped('veth99', 'proto redirect', ipv='-6', timeout_sec=10)
         self.wait_route_dropped('veth99', 'proto ra', ipv='-6', timeout_sec=10)
 
+    def check_ndisc_mtu(self, mtu):
+        for _ in range(20):
+            output = read_ipv6_sysctl_attr('veth99', 'mtu')
+            if output == f'{mtu}':
+                break
+            time.sleep(0.5)
+        else:
+            self.fail(f'IPv6 MTU does not matches: value={output}, expected={mtu}')
+
+    def test_ndisc_mtu(self):
+        if not os.path.exists(test_ndisc_send):
+            self.skipTest(f"{test_ndisc_send} does not exist.")
+
+        copy_network_unit('25-veth.netdev',
+                          '25-veth-peer-no-address.network',
+                          '25-ipv6-prefix-veth-token-static.network')
+        start_networkd()
+        self.wait_online('veth-peer:degraded')
+
+        for _ in range(20):
+            output = read_networkd_log()
+            if 'veth99: NDISC: Started IPv6 Router Solicitation client' in output:
+                break
+            time.sleep(0.5)
+        else:
+            self.fail('sd-ndisc does not started on veth99.')
+
+        check_output(f'{test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1400')
+        self.check_ndisc_mtu(1400)
+
+        check_output(f'{test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1410')
+        self.check_ndisc_mtu(1410)
+
+        check_output('ip link set dev veth99 mtu 1600')
+        self.check_ndisc_mtu(1410)
+
+        check_output(f'{test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1700')
+        self.check_ndisc_mtu(1600)
+
+        check_output('ip link set dev veth99 mtu 1800')
+        self.check_ndisc_mtu(1700)
+
     def test_ipv6_token_prefixstable(self):
         copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable.network')
         start_networkd()
         self.wait_online('veth99:routable', 'veth-peer:degraded')
 
-        output = networkctl_status('veth99')
+        output = check_output('ip -6 address show dev veth99')
         print(output)
-        self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
-        self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output) # EUI64
+        self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
+        self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc/64', output) # EUI64
+
+        with open(os.path.join(network_unit_dir, '25-ipv6-prefix-veth-token-prefixstable.network'), mode='a', encoding='utf-8') as f:
+            f.write('\n[IPv6AcceptRA]\nPrefixAllowList=2002:da8:1:0::/64\n')
+
+        networkctl_reload()
+        self.wait_online('veth99:routable')
+
+        output = check_output('ip -6 address show dev veth99')
+        print(output)
+        self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
+        self.assertNotIn('2002:da8:2:0:1034:56ff:fe78:9abc/64', output) # EUI64
+
+        check_output('ip address del 2002:da8:1:0:b47e:7975:fc7a:7d6e/64 dev veth99')
+        check_output('ip address add 2002:da8:1:0:b47e:7975:fc7a:7d6e/64 dev veth-peer nodad')
+
+        networkctl_reconfigure('veth99')
+        self.wait_online('veth99:routable')
+
+        output = check_output('ip -6 address show dev veth99')
+        print(output)
+        self.assertNotIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
+        self.assertIn('2002:da8:1:0:da5d:e50a:43fd:5d0f/64', output) # the 2nd prefixstable
+
+        check_output('ip address del 2002:da8:1:0:da5d:e50a:43fd:5d0f/64 dev veth99')
+        check_output('ip address add 2002:da8:1:0:da5d:e50a:43fd:5d0f/64 dev veth-peer nodad')
+
+        networkctl_reconfigure('veth99')
+        self.wait_online('veth99:routable')
+
+        output = check_output('ip -6 address show dev veth99')
+        print(output)
+        self.assertNotIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
+        self.assertNotIn('2002:da8:1:0:da5d:e50a:43fd:5d0f/64', output) # the 2nd prefixstable
+        self.assertIn('2002:da8:1:0:c7e4:77ec:eb31:1b0d/64', output) # the 3rd prefixstable
 
     def test_ipv6_token_prefixstable_without_address(self):
         copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable-without-address.network')
index c4d4b3e1ec0336cbcc306970261244d60221abfc..d4a87df3555f7927b9624de65381d8299449a6ed 100644 (file)
@@ -3,7 +3,12 @@
 
 import os
 import sys
-import lxml.etree as tree
+
+try:
+    import lxml.etree as tree
+except ImportError as e:
+    print(str(e), file=sys.stderr)
+    sys.exit(77)
 
 _parser = tree.XMLParser(resolve_entities=False)
 tree.set_default_parser(_parser)
diff --git a/tools/git-post-rewrite-hook.sh b/tools/git-post-rewrite-hook.sh
new file mode 100755 (executable)
index 0000000..78feb9d
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+exec git submodule update
index 4b49ab9c45f9d48547b93d3827038809b0550bfe..a53f1790c17a7ae2d2a233a3d351abbc732d7762 100755 (executable)
@@ -10,10 +10,19 @@ if [ -e .git ]; then
     git config push.recurseSubmodules no
 fi
 
-if [ ! -f .git/hooks/pre-commit.sample ] || [ -f .git/hooks/pre-commit ]; then
-    exit 2 # not needed
+ret=2
+
+if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then
+    cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit
+    chmod +x .git/hooks/pre-commit
+    echo 'Activated pre-commit hook'
+    ret=0
+fi
+
+if [ ! -f .git/hooks/post-rewrite ]; then
+    cp -p tools/git-post-rewrite-hook.sh .git/hooks/post-rewrite
+    echo 'Activated post-rewrite hook'
+    ret=0
 fi
 
-cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit
-chmod +x .git/hooks/pre-commit
-echo 'Activated pre-commit hook'
+exit $ret
index eaadd0e55446387aa36ec444c6f6df5481f20040..2e17cb9c8e8b9e19686855faafbdc68b64aeee20 100644 (file)
@@ -12,8 +12,6 @@ Description=Check if Any System Units Failed
 Documentation=man:systemd-boot-check-no-failures.service(8)
 After=default.target graphical.target multi-user.target
 Before=boot-complete.target
-Conflicts=shutdown.target
-Before=shutdown.target
 
 [Service]
 Type=oneshot