$ 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
-Subproject commit 282d1f30a64204630e96bcf048597f6afbe4a8bf
+Subproject commit ad880b10ee6bbfbe266c518fc87b8c7a3df962da
-Subproject commit 3f8c38e5d6481fa01e766516cbdf7779c4a2825b
+Subproject commit 2822a03dded26b9453bddbba7c6a152de8204aec
#include "generator.h"
#include "initrd-util.h"
#include "log.h"
-#include "mkdir.h"
#include "special.h"
#include "string-util.h"
#include "virt.h"
* 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.");
}
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;
/* 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);
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;
}
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;
}
* 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? */
}
/* 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);
}
int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
- assert_return(client, -EINVAL);
+ if (!client)
+ return false;
return client->state != DHCP6_STATE_STOPPED;
}
}
int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
- assert_return(acd, false);
+ if (!acd)
+ return false;
return acd->state != IPV4ACD_STATE_INIT;
}
}
int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
- assert_return(ll, false);
+ if (!ll)
+ return false;
return sd_ipv4acd_is_running(ll->acd);
}
}
int sd_radv_is_running(sd_radv *ra) {
- assert_return(ra, false);
+ if (!ra)
+ return false;
return ra->state != RADV_STATE_IDLE;
}
_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);
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;
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(
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;
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)
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;
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(
#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);
#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"
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);
}
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;
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);
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;
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);
}
}
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);
(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. */
#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"
* 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;
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);
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)
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");
}
#include "conf-parser.h"
+typedef struct Address Address;
typedef struct Link Link;
bool link_dhcp_pd_is_enabled(Link *link);
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);
/* 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");
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)
Set *ndisc_captive_portals;
Set *ndisc_pref64;
Set *ndisc_redirects;
+ uint32_t ndisc_mtu;
unsigned ndisc_messages;
bool ndisc_configured:1;
}
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)
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;
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;
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);
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
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;
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] = {
#include "conf-parser.h"
#include "time-util.h"
+typedef struct Address Address;
typedef struct Link Link;
typedef struct Network Network;
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);
return 0;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
- _cleanup_set_free_ Set *addresses = NULL;
- struct in6_addr *a;
-
if (!p->assign)
continue;
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);
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)
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;
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);
}
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(
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;
}))
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;
}
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,
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);
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");
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_;
#include <stdbool.h>
#include <sys/prctl.h>
+#include <unistd.h>
#include "sd-daemon.h"
}
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__);
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);
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);
}
case 15 ... 16:
assert_se(r == -ENOBUFS);
- assert_se(setting1 == NULL);
+ ASSERT_NULL(setting1);
break;
case 17:
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));
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);
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) {
_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) {
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) {
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) {
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) {
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) {
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) {
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);
}
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);
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);
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);
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);
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);
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);
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);
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);
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"));
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);
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);
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) {
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) {
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);
}
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");
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));
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);
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"));
assert_se(val);
r = hashmap_get(NULL, "Key 1");
- assert_se(r == NULL);
+ ASSERT_NULL(r);
m = hashmap_new(&string_hash_ops);
assert_se(streq(r, val));
r = hashmap_get(m, "no such key");
- assert_se(r == NULL);
+ ASSERT_NULL(r);
assert_se(m);
}
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);
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);
}
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
}
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) {
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
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) {
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) {
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]);
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]);
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]);
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]);
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]);
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]);
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]);
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]));
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]));
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]);
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]);
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]);
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);
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 */
LIST_CLEAR(item_list, head, free);
- assert_se(head == NULL);
+ ASSERT_NULL(head);
/* A list can be cleared partially */
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;
}
"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,
"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,
"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,
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,
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,
"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 */");
"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. */
"LValue", 0, "",
&c, u);
assert_se(r == 0);
- assert_se(c == NULL);
+ ASSERT_NULL(c);
exec_command_free_list(c);
}
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);
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);
}
}
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);
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));
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);
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;
}
r = test_tunnel_configure(rtnl);
- assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+ ASSERT_NULL((rtnl = sd_netlink_unref(rtnl)));
return r;
}
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 {
assert_se(streq(path, "/"));
assert_se(parse_path_argument("/", true, &path) == 0);
- assert_se(path == NULL);
+ ASSERT_NULL(path);
}
TEST(parse_signal_argument) {
_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);
}
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("/"), "/"));
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));
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) {
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);
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);
/* 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);
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);
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);
assert_se(streq(sb->buf + h, ""));
strbuf_complete(sb);
- assert_se(sb->root == NULL);
+ ASSERT_NULL(sb->root);
}
DEFINE_TEST_MAIN(LOG_INFO);
assert_se(streq(word, expected[i++]));
printf("<%s>\n", word);
}
- assert_se(expected[i] == NULL);
+ ASSERT_NULL(expected[i]);
}
TEST(foreach_word_quoted) {
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"));
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, ""));
STRV_FOREACH(t, s)
assert_se(streq(list[i++], *t));
- assert_se(list[i] == NULL);
+ ASSERT_NULL(list[i]);
}
TEST(strv_unquote) {
log_info("/* %s */", __func__);
r = strv_split_full(&s, quoted, WHITESPACE, EXTRACT_UNQUOTE);
- assert_se(s == NULL);
+ ASSERT_NULL(s);
assert_se(r == -EINVAL);
}
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) {
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);
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) {
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"));
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);
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);
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;
}
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::,
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
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=veth-peer
+
+[Network]
+IPv6AcceptRA=no
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')
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)
--- /dev/null
+#!/bin/sh
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+exec git submodule update
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
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