1
0
mirror of https://github.com/systemd/systemd synced 2026-03-15 01:24:51 +01:00

Compare commits

..

57 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
c799d93cfa
Merge pull request #19567 from poettering/ipv4-ipv6-lowercase
various follow-ups to socket-bind logic
2021-05-12 12:21:58 +02:00
Michael Catanzaro
aa2b370ddd resolved.conf.in: add missing Quad9 servers
The example configuration is missing half of Quad9's addresses.
2021-05-12 12:17:39 +02:00
Lennart Poettering
5a0d0b8f9c resolved: be more careful with weird links with low MTUs
Apparently CAN links will show up in rtnetlink with very low MTUs. We
shouldn't consider them relevant if no IP is spoken over them, since
these MTUs are irrelevant for us then.

Hence, let's check if there's an address assigned to the link before
considering its MTU.

As additional safety net filter out MTUs smaller than the minimum DNS
packet size, too.

Finally, in case we don't find any suitable interface MTU, let's default
to 1500 as the generic Ethernet MTU.

Fixes: #19396
2021-05-12 12:15:56 +02:00
Lennart Poettering
971c07fc68 pam: fix typo try_authtok → use_authtok
This was a copy/paste mistae apparently, there's not "try_authtok" and
this was supposed to copy what Fedora uses, which uses "use_authtok"
correctly. Hence adjust this.

Fixes: #19369
2021-05-12 12:14:17 +02:00
Zbigniew Jędrzejewski-Szmek
7a7e58ce44
Merge pull request #19533 from yuwata/network-queue
network: introduce queue to configure address, route, etc
2021-05-12 12:12:22 +02:00
Zbigniew Jędrzejewski-Szmek
8f7123731d
Merge pull request #18986 from poettering/oomd-varlink-fix
varlink ref fix
2021-05-12 11:36:32 +02:00
Zbigniew Jędrzejewski-Szmek
01d0123f04
Merge pull request #19506 from xnox/ship-stub-elf
boot/efi: install ELF linux.elf.stub in addition to PE linux.efi.stub
2021-05-12 09:45:36 +02:00
Lennart Poettering
dc90ad6825
Merge pull request #19581 from yuwata/specifier-refuse-too-long-results
specifier: refuse too long results
2021-05-12 09:42:08 +02:00
Lennart Poettering
041ea9f9bb netlink,network: drop "const" from opaque object parameters in supposed-to-be-public APIs
This drops the "const" specifier from the opaque object parameters to
various functions in our API.

This effectively reverts #19292 and more.

Why drop this? Our public APIs should not leak too much information
about how stuff is implemented internally. In our public APIs we
shouldn't give too many guarantees we don#t want to necessarily keep.
Specifically: in many cases it makes sense that getters actually
generate/parse/allocate data on the fly, storing/caching the result
internally, to speed things up, do things lazily or to track memory
allocations so that they can be freed later. Doing this means we need to
change the objects, even though the getters are semantically a read
operation.

We want to retain the freedom that we can change things around
internally. By exposing the objects as "const" we remove a good chunk of
that, for little gain.

See sd_bus_creds_get_description() for a real example of a getter that
implicitly caches and thus modifies the relevant object.

This removes the "const" decorators from sd-dhcp and sd-netlink, two
APIs that we intend to make public eventually even though they still are
not, leaving us the chance to still fix this before it becomes set in
stone.
2021-05-12 16:19:58 +09:00
Yu Watanabe
932e157b5e test-network: wait for the interfaces are configured after reloading .network files 2021-05-12 11:26:06 +09:00
Yu Watanabe
1ef2eedce7 test-network: wait for the intreface is configured if it is expected 2021-05-12 11:26:06 +09:00
Yu Watanabe
5cb76467af network: make route_configure() return all created routes 2021-05-12 11:26:06 +09:00
Yu Watanabe
b19afdfef8 network: make log_route_debug() show multipath routes and Gateway=_dhcp4 or _ipv6ra 2021-05-12 11:26:06 +09:00
Yu Watanabe
76c5a0f27b network: use request queue to configure addresses, routes, and nexthops
Why is this necessary? Several examples below.

- When a route sets prefsrc, then the address must be already assigned
  (see issue #19285), and also it must be ready if IPv6.
- When a route or nexthop sets gateway, then the address must be reachable.
- When a route sets nexthop ID, then the corresponding nexthop must be
  assigned.
- When a route sets multipath routes on another interface, then the
  interface must exist and be ready to configure.
- When configuring address, the same address must not be under removing
  (see issue #18108).
Etc,. etc,...

So, this makes all requests about addresses, routes, and nethops are once
stored in the queue, and will be processed when they are ready to configure.

Fixes #18108 and #19285.
2021-05-12 11:26:06 +09:00
Yu Watanabe
40ca350ea1 network: use request queue to configure neighbors 2021-05-12 11:26:06 +09:00
Yu Watanabe
0e5ef6beb6 network: use request queue to configure routing policy rules 2021-05-12 11:26:06 +09:00
Yu Watanabe
7191a57a0e network: introduce link_is_ready_to_configure() helper function
This will be used in later commits.
2021-05-12 11:26:06 +09:00
Yu Watanabe
19d9a5adf0 network: add skeleton of request queue
This will be used in later commits.
2021-05-12 11:26:06 +09:00
Yu Watanabe
17060f02cc network: nexthop: add NextHop object before sending netlink request
Otherwise, if nexthop_add() fails, then assertion about nexthop_messages in
static_nexthop_handler() will be triggered.
2021-05-12 11:26:06 +09:00
Yu Watanabe
5a07fa9dd1 network: split out common part of route or address handlers 2021-05-12 11:26:06 +09:00
Yu Watanabe
e36d601c5e network: change order of dropping network configs
As routes may requires nexthops and addresses, nexthops may requires
addresses.
2021-05-12 11:26:06 +09:00
Yu Watanabe
e80509a904 network: simplify and rename routing_policy_rule_copy() 2021-05-12 11:25:55 +09:00
Yu Watanabe
c0bd9eb1ed network: introduce route_dup()
The function will be used in later commits.
2021-05-12 11:22:24 +09:00
Yu Watanabe
4867b9d711 sd-netlink: introduce multipath_route_dup()
The function will be used in later commits.
2021-05-12 10:39:12 +09:00
Yu Watanabe
d94e8ba021 network: introduce manager_address_is_reachable()
The function will be used in later commits.
2021-05-12 10:39:12 +09:00
Yu Watanabe
884a63d76e network: introduce link_has_route()
The function will be used in later commits.
2021-05-12 10:39:12 +09:00
Yu Watanabe
e8f52f3c19 network: delay resolving interface specifier in MultiPathRoute=
The interface may not exist when .network files are loaded.
2021-05-12 10:37:17 +09:00
Yu Watanabe
591bd5f35d network: introduce manager_has_address()
The function will be used in later commits.
2021-05-12 10:30:45 +09:00
Yu Watanabe
d38a6476aa ordered-set: introduce ordered_set_clear/free_with_destructor() 2021-05-12 10:30:45 +09:00
Yu Watanabe
38c116df7f hashmap,set: make hashmap_clear_with_destructor() or friends safer 2021-05-12 10:30:45 +09:00
Yu Watanabe
b8ce3b4490 network: use IPV4_ADDRESS_FMT_STR/VAL macros and in6_addr_to_string() or friends 2021-05-12 10:30:45 +09:00
Yu Watanabe
280323984b in-addr-util: move IPV4_ADDRESS_FMT_STR/VAL macros from networkd-address.h 2021-05-12 10:30:45 +09:00
Yu Watanabe
ae7b68db97 in-addr-util: introduce in6_addr_to_string() or friends 2021-05-12 10:30:45 +09:00
Yu Watanabe
5c97932f09 network: use in6_addr_is_link_local() or friends 2021-05-12 10:30:45 +09:00
Yu Watanabe
7ad3e90932 network: rename routing_policy_rule_configure_internal() and make it take callback 2021-05-12 10:30:45 +09:00
Yu Watanabe
3eacccf493 network: make nexthop_configure() take callback 2021-05-12 10:30:45 +09:00
Yu Watanabe
7575e1f42d network: make neighbor_configure() take callback 2021-05-12 10:30:45 +09:00
Yu Watanabe
0653649202 tree-wide: refuse too long strings earlier in specifier_printf()
We usually call specifier_printf() and then check the validity of
the result. In many cases, validity checkers, e.g. path_is_valid(),
refuse too long strings. This makes specifier_printf() refuse such
long results earlier.

Moreover, unit_full_string() and description field in sysuser now
refuse results longer than LONG_LINE_MAX. config_parse() already
refuses the line longer than LONG_LINE_MAX. Hence, it should be ok
to set the same value as the maximum length of the resolved string.
2021-05-12 10:26:07 +09:00
Yu Watanabe
678d6b4f92 dns-domain: use DNS_LABEL_MAX at one more place 2021-05-12 10:21:22 +09:00
Yu Watanabe
3d862ff066 creds-util: introduce CREDENTIAL_NAME_MAX 2021-05-12 10:20:47 +09:00
Yu Watanabe
ae3f4bae68 fd-util: introduce FDNAME_MAX 2021-05-12 10:19:19 +09:00
Yu Watanabe
6001df6594 gpt: introduce GPT_LAVEL_MAX 2021-05-12 10:16:36 +09:00
Yu Watanabe
f4767dc081 test: move test_specifier_printf() to test-specifier.c 2021-05-12 10:09:11 +09:00
Yu Watanabe
695c5fee6d specifier: rename variable 2021-05-12 10:09:11 +09:00
Yu Watanabe
567097848c specifier: use SD_ID128_STRING_MAX 2021-05-12 10:09:11 +09:00
Lennart Poettering
d65e974e67 core: don't accidentally unref a varlink connection twice
Let's make sure that our close handler unrefs a connection again that we
are already unreffing a few stack frames up by invalidating the pointer
first, and dropping the ref counter only after that.

Replaces: 39ad3f1c092b5dffcbb4b1d12eb9ca407f010a3c

Fixes: #18025
2021-05-11 21:45:32 +02:00
Lennart Poettering
cc6b0a18ff Revert "varlink: avoid using dangling ref in varlink_close_unref()"
This reverts commit 39ad3f1c092b5dffcbb4b1d12eb9ca407f010a3c.
2021-05-11 21:45:32 +02:00
Lennart Poettering
11ab01e439 cgroup: drop explicit NULL comparisons 2021-05-11 15:42:47 +02:00
Lennart Poettering
a67abc490b tree-wide: move variables to innermost scope 2021-05-11 15:42:46 +02:00
Lennart Poettering
a481753648 tree-wide: use af_to_ipv4_ipv6() + af_from_ipv4_ipv6() helpers at various places 2021-05-11 15:42:11 +02:00
Lennart Poettering
23118193d2 af-list: add helpers mapping AF_INET/AF_INET6 to "ipv4"/"ipv6" 2021-05-11 15:37:31 +02:00
Lennart Poettering
f80a206aa4 socket-bind: use lowercase "ipv4"/"ipv6" spelling
In most of our codebase when we referenced "ipv4" and "ipv6" on the
right-hand-side of an assignment, we lowercases it (on the
left-hand-side we used CamelCase, and thus "IPv4" and "IPv6"). In
particular all across the networkd codebase the various "per-protocol
booleans" use the lower-case spelling. Hence, let's use lower-case for
SocketBindAllow=/SocketBindDeny= too, just make sure things feel like
they belong together better.

(This work is not included in any released version, hence let's fix this
now, before any fixes in this area would be API breakage)

Follow-up for #17655
2021-05-11 15:37:31 +02:00
Zbigniew Jędrzejewski-Szmek
031e7e3241 test-efi-create-disk: support /boot/efi
Most of our tools allow EFI mount to be on /boot/efi. Do the same here.
2021-05-10 20:35:31 +02:00
Zbigniew Jędrzejewski-Szmek
bdf5d8d4c0 test-efi-create-disk: shellcheckify 2021-05-10 20:34:08 +02:00
Zbigniew Jędrzejewski-Szmek
4f3dca78bb meson: rework test-efi-disk.img creation to not require variables
The primary goal is to make the name of the custom_target() rule match
the output file again. Having them different is confusing.
2021-05-10 20:28:24 +02:00
Dimitri John Ledkov
36c5f589fb
boot/efi: add --build-id=sha1 to ELF efi objects
As it is not nice to ship ELF binary without a note.gnu.build-id set.
2021-05-10 09:36:04 +01:00
Dimitri John Ledkov
7840d7af22
boot/efi: install ELF linux.elf.stub in addition to PE linux.efi.stub
Binutils for non-x86 architectures currently does not support PE binaries. Thus
linux.efi.stub is useless on those, as one cannot use any tooling to add
linux/cmdline/splash sections to it. In addition to PE linux.efi.stub also
install ELF linux.elf.stub, such that one can use objcopy ELF target to copy in
linux/cmdline/splash sections and then convert the result to a PE binary.
2021-05-10 09:35:59 +01:00
81 changed files with 2587 additions and 1572 deletions

View File

@ -13,7 +13,7 @@ account sufficient pam_unix.so
account required pam_permit.so
-password sufficient pam_systemd_home.so
password sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
password sufficient pam_unix.so sha512 shadow try_first_pass use_authtok
password required pam_deny.so
-session optional pam_keyinit.so revoke

View File

@ -318,7 +318,8 @@ account sufficient pam_unix.so
account required pam_permit.so
-password sufficient pam_systemd_home.so
password sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
password sufficient pam_unix.so sha512 shadow try_first_pass use_authtok
password required pam_deny.so
-session optional pam_keyinit.so revoke

View File

@ -139,7 +139,7 @@ account sufficient pam_unix.so
account required pam_permit.so
<command>-password sufficient pam_systemd_home.so</command>
password sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
password sufficient pam_unix.so sha512 shadow try_first_pass use_authtok
password required pam_deny.so
-session optional pam_keyinit.so revoke

View File

@ -775,7 +775,7 @@ BPFProgram=bind6:/sys/fs/bpf/sock-addr-hook
<para><replaceable>bind-rule</replaceable> := [<replaceable>address-family</replaceable><constant>:</constant>]<replaceable>ip-ports</replaceable></para>
<para><replaceable>address-family</replaceable> := { <constant>IPv4</constant> | <constant>IPv6</constant> }</para>
<para><replaceable>address-family</replaceable> := { <constant>ipv4</constant> | <constant>ipv6</constant> }</para>
<para><replaceable>ip-ports</replaceable> := { <replaceable>ip-port</replaceable> | <replaceable>ip-port-range</replaceable> |
<constant>any</constant> }</para>
@ -812,7 +812,7 @@ BPFProgram=bind6:/sys/fs/bpf/sock-addr-hook
<para>Examples:<programlisting>
# Allow binding IPv6 socket addresses with a port greater than or equal to 10000.
[Service]
SocketBindAllow=IPv6:10000-65535
SocketBindAllow=ipv6:10000-65535
SocketBindDeny=any
# Allow binding IPv4 and IPv6 socket addresses with 1234 and 4321 ports.
@ -823,7 +823,7 @@ SocketBindDeny=any
# Deny binding IPv6 socket addresses.
[Service]
SocketBindDeny=IPv6:any
SocketBindDeny=ipv6:any
# Deny binding IPv4 and IPv6 socket addresses.
[Service]

View File

@ -38,3 +38,15 @@ int af_from_name(const char *name) {
int af_max(void) {
return ELEMENTSOF(af_names);
}
const char *af_to_ipv4_ipv6(int id) {
/* Pretty often we want to map the address family to the typically used protocol name for IPv4 +
* IPv6. Let's add special helpers for that. */
return id == AF_INET ? "ipv4" :
id == AF_INET6 ? "ipv6" : NULL;
}
int af_from_ipv4_ipv6(const char *af) {
return streq_ptr(af, "ipv4") ? AF_INET :
streq_ptr(af, "ipv6") ? AF_INET6 : AF_UNSPEC;
}

View File

@ -22,4 +22,7 @@ static inline const char* af_to_name_short(int id) {
return f + 3;
}
const char* af_to_ipv4_ipv6(int id);
int af_from_ipv4_ipv6(const char *af);
int af_max(void);

View File

@ -5,6 +5,10 @@
#include <stdbool.h>
#include <sys/types.h>
#include "fd-util.h"
#define CREDENTIAL_NAME_MAX FDNAME_MAX
bool credential_name_valid(const char *s);
int get_credentials_dir(const char **ret);

View File

@ -454,7 +454,7 @@ bool fdname_is_valid(const char *s) {
return false;
}
return p - s < 256;
return p - s <= FDNAME_MAX;
}
int fd_get_path(int fd, char **ret) {

View File

@ -8,6 +8,9 @@
#include "macro.h"
/* maximum length of fdname */
#define FDNAME_MAX 255
/* Make sure we can distinguish fd 0 and NULL */
#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)

View File

@ -371,28 +371,26 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
return _hashmap_first_key(HASHMAP_BASE(h), false);
}
#define hashmap_clear_with_destructor(_s, _f) \
#define hashmap_clear_with_destructor(h, f) \
({ \
Hashmap *_h = (h); \
void *_item; \
while ((_item = hashmap_steal_first(_s))) \
_f(_item); \
while ((_item = hashmap_steal_first(_h))) \
f(_item); \
_h; \
})
#define hashmap_free_with_destructor(_s, _f) \
({ \
hashmap_clear_with_destructor(_s, _f); \
hashmap_free(_s); \
})
#define ordered_hashmap_clear_with_destructor(_s, _f) \
#define hashmap_free_with_destructor(h, f) \
hashmap_free(hashmap_clear_with_destructor(h, f))
#define ordered_hashmap_clear_with_destructor(h, f) \
({ \
OrderedHashmap *_h = (h); \
void *_item; \
while ((_item = ordered_hashmap_steal_first(_s))) \
_f(_item); \
})
#define ordered_hashmap_free_with_destructor(_s, _f) \
({ \
ordered_hashmap_clear_with_destructor(_s, _f); \
ordered_hashmap_free(_s); \
while ((_item = ordered_hashmap_steal_first(_h))) \
f(_item); \
_h; \
})
#define ordered_hashmap_free_with_destructor(h, f) \
ordered_hashmap_free(ordered_hashmap_clear_with_destructor(h, f))
/* no hashmap_next */
void* ordered_hashmap_next(OrderedHashmap *h, const void *key);

View File

@ -73,7 +73,13 @@ int in_addr_prefix_range(
union in_addr_union *ret_start,
union in_addr_union *ret_end);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
static inline int in6_addr_to_string(const struct in6_addr *u, char **ret) {
return in_addr_to_string(AF_INET6, (const union in_addr_union*) u, ret);
}
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
static inline int in6_addr_prefix_to_string(const struct in6_addr *u, unsigned prefixlen, char **ret) {
return in_addr_prefix_to_string(AF_INET6, (const union in_addr_union*) u, prefixlen, ret);
}
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret);
@ -120,3 +126,10 @@ extern const struct hash_ops in_addr_data_hash_ops;
extern const struct hash_ops in_addr_prefix_hash_ops;
extern const struct hash_ops in_addr_prefix_hash_ops_free;
extern const struct hash_ops in6_addr_hash_ops;
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
#define IPV4_ADDRESS_FMT_VAL(address) \
be32toh((address).s_addr) >> 24, \
(be32toh((address).s_addr) >> 16) & 0xFFu, \
(be32toh((address).s_addr) >> 8) & 0xFFu, \
be32toh((address).s_addr) & 0xFFu

View File

@ -75,6 +75,17 @@ void ordered_set_print(FILE *f, const char *field, OrderedSet *s);
#define ORDERED_SET_FOREACH(e, s) \
_ORDERED_SET_FOREACH(e, s, UNIQ_T(i, UNIQ))
#define ordered_set_clear_with_destructor(s, f) \
({ \
OrderedSet *_s = (s); \
void *_item; \
while ((_item = ordered_set_steal_first(_s))) \
f(_item); \
_s; \
})
#define ordered_set_free_with_destructor(s, f) \
ordered_set_free(ordered_set_clear_with_destructor(s, f))
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free);

View File

@ -95,17 +95,16 @@ static inline void *set_steal_first(Set *s) {
return _hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
}
#define set_clear_with_destructor(_s, _f) \
#define set_clear_with_destructor(s, f) \
({ \
Set *_s = (s); \
void *_item; \
while ((_item = set_steal_first(_s))) \
_f(_item); \
})
#define set_free_with_destructor(_s, _f) \
({ \
set_clear_with_destructor(_s, _f); \
set_free(_s); \
f(_item); \
_s; \
})
#define set_free_with_destructor(s, f) \
set_free(set_clear_with_destructor(s, f))
/* no set_steal_first_key */
/* no set_first_key */

View File

@ -224,6 +224,7 @@ if have_gnu_efi
'-Bsymbolic',
'-nostdlib',
'-znocombreloc',
'--build-id=sha1',
'-L', efi_libdir,
efi_crt0]
if ['aarch64', 'arm', 'riscv64'].contains(efi_arch)
@ -254,24 +255,22 @@ if have_gnu_efi
libgcc_file_name = run_command(efi_cc + ['-print-libgcc-file-name']).stdout().strip()
systemd_boot_efi_name = 'systemd-boot@0@.efi'.format(EFI_MACHINE_TYPE_NAME)
stub_elf_name = 'linux@0@.elf.stub'.format(EFI_MACHINE_TYPE_NAME)
stub_efi_name = 'linux@0@.efi.stub'.format(EFI_MACHINE_TYPE_NAME)
no_undefined_symbols = find_program('no-undefined-symbols.sh')
foreach tuple : [['systemd_boot.so', systemd_boot_efi_name, systemd_boot_objects],
['stub.so', stub_efi_name, stub_objects]]
efi_stubs = []
foreach tuple : [['systemd_boot.so', systemd_boot_efi_name, systemd_boot_objects, false],
[stub_elf_name, stub_efi_name, stub_objects, true]]
so = custom_target(
tuple[0],
input : tuple[2],
output : tuple[0],
command : [efi_ld, '-o', '@OUTPUT@'] +
efi_ldflags + tuple[2] +
['-lefi', '-lgnuefi', libgcc_file_name])
if want_tests != 'false'
test('no-undefined-symbols-' + tuple[0],
no_undefined_symbols,
args : [so])
endif
command : [efi_ld, '-o', '@OUTPUT@',
efi_ldflags, tuple[2],
'-lefi', '-lgnuefi', libgcc_file_name],
install : tuple[3],
install_dir : bootlibdir)
stub = custom_target(
tuple[1],
@ -284,22 +283,26 @@ if have_gnu_efi
'-j', '.data',
'-j', '.dynamic',
'-j', '.dynsym',
'-j', '.rel*']
+ efi_format +
['@INPUT@', '@OUTPUT@'],
'-j', '.rel*',
efi_format,
'@INPUT@', '@OUTPUT@'],
install : true,
install_dir : bootlibdir)
set_variable(tuple[0].underscorify(), so)
set_variable(tuple[0].underscorify() + '_stub', stub)
efi_stubs += [[so, stub]]
if want_tests != 'false'
test('no-undefined-symbols-' + tuple[0],
no_undefined_symbols,
args : so)
endif
endforeach
############################################################
test_efi_disk_img = custom_target(
'test-efi-disk.img',
input : [systemd_boot_so, stub_so_stub],
input : [efi_stubs[0][0], efi_stubs[1][1]],
output : 'test-efi-disk.img',
command : [test_efi_create_disk_sh, '@OUTPUT@',
'@INPUT0@', '@INPUT1@', splash_bmp])
command : [test_efi_create_disk_sh, '@OUTPUT@','@INPUT@', splash_bmp])
endif

View File

@ -4,6 +4,7 @@
#include "sd-messages.h"
#include "af-list.h"
#include "alloc-util.h"
#include "blockdev-util.h"
#include "bpf-devices.h"
@ -202,12 +203,10 @@ void cgroup_context_remove_bpf_foreign_program(CGroupContext *c, CGroupBPFForeig
}
void cgroup_context_remove_socket_bind(CGroupSocketBindItem **head) {
CGroupSocketBindItem *h;
assert(head);
while (*head) {
h = *head;
CGroupSocketBindItem *h = *head;
LIST_REMOVE(socket_bind_items, *head, h);
free(h);
}
@ -594,16 +593,18 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
}
void cgroup_context_dump_socket_bind_item(const CGroupSocketBindItem *item, FILE *f) {
const char *family = item->address_family == AF_INET ? "IPv4:" :
item->address_family == AF_INET6 ? "IPv6:" : "";
const char *family, *colon;
family = strempty(af_to_ipv4_ipv6(item->address_family));
colon = isempty(family) ? "" : ":";
if (item->nr_ports == 0)
fprintf(f, " %sany", family);
fprintf(f, " %s%sany", family, colon);
else if (item->nr_ports == 1)
fprintf(f, " %s%" PRIu16, family, item->port_min);
fprintf(f, " %s%s%" PRIu16, family, colon, item->port_min);
else {
uint16_t port_max = item->port_min + item->nr_ports - 1;
fprintf(f, " %s%" PRIu16 "-%" PRIu16, family, item->port_min, port_max);
fprintf(f, " %s%s%" PRIu16 "-%" PRIu16, family, colon, item->port_min, port_max);
}
}
@ -1580,7 +1581,7 @@ static bool unit_get_needs_socket_bind(Unit *u) {
if (!c)
return false;
return c->socket_bind_allow != NULL || c->socket_bind_deny != NULL;
return c->socket_bind_allow || c->socket_bind_deny;
}
static CGroupMask unit_get_cgroup_mask(Unit *u) {

View File

@ -475,8 +475,11 @@ int manager_varlink_init(Manager *m) {
void manager_varlink_done(Manager *m) {
assert(m);
/* Send the final message if we still have a subscribe request open. */
m->managed_oom_varlink_request = varlink_close_unref(m->managed_oom_varlink_request);
/* Explicitly close the varlink connection to oomd. Note we first take the varlink connection out of
* the manager, and only then disconnect it in two steps so that we don't end up accidentally
* unreffing it twice. After all, closing the connection might cause the disconnect handler we
* installed (vl_disconnect() above) to be called, where we will unref it too. */
varlink_close_unref(TAKE_PTR(m->managed_oom_varlink_request));
m->varlink_server = varlink_server_unref(m->varlink_server);
}

View File

@ -293,15 +293,7 @@ int config_parse_unit_path_printf(
assert(rvalue);
assert(u);
/* Let's not bother with anything that is too long */
if (strlen(rvalue) >= PATH_MAX) {
log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, 0,
"%s value too long%s.",
lvalue, fatal ? "" : ", ignoring");
return fatal ? -ENAMETOOLONG : 0;
}
r = unit_full_printf(u, rvalue, &k);
r = unit_path_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s'%s: %m",
@ -352,7 +344,7 @@ int config_parse_unit_path_strv_printf(
return 0;
}
r = unit_full_printf(u, word, &k);
r = unit_path_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", word);
@ -433,7 +425,7 @@ int config_parse_socket_listen(
if (ltype != SOCKET_SOCKET) {
_cleanup_free_ char *k = NULL;
r = unit_full_printf(UNIT(s), rvalue, &k);
r = unit_path_printf(UNIT(s), rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -455,7 +447,7 @@ int config_parse_socket_listen(
} else if (streq(lvalue, "ListenNetlink")) {
_cleanup_free_ char *k = NULL;
r = unit_full_printf(UNIT(s), rvalue, &k);
r = unit_path_printf(UNIT(s), rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -472,7 +464,7 @@ int config_parse_socket_listen(
} else {
_cleanup_free_ char *k = NULL;
r = unit_full_printf(UNIT(s), rvalue, &k);
r = unit_path_printf(UNIT(s), rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -769,7 +761,7 @@ int config_parse_exec(
f++;
}
r = unit_full_printf(u, f, &path);
r = unit_path_printf(u, f, &path);
if (r < 0) {
log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r,
"Failed to resolve unit specifiers in '%s'%s: %m",
@ -856,7 +848,7 @@ int config_parse_exec(
if (r < 0)
return ignore ? 0 : -ENOEXEC;
r = unit_full_printf(u, word, &resolved);
r = unit_path_printf(u, word, &resolved);
if (r < 0) {
log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r,
"Failed to resolve unit specifiers in %s%s: %m",
@ -956,7 +948,7 @@ int config_parse_exec_input(
if (n) {
_cleanup_free_ char *resolved = NULL;
r = unit_full_printf(u, n, &resolved);
r = unit_fd_printf(u, n, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", n);
return 0;
@ -976,7 +968,7 @@ int config_parse_exec_input(
} else if ((n = startswith(rvalue, "file:"))) {
_cleanup_free_ char *resolved = NULL;
r = unit_full_printf(u, n, &resolved);
r = unit_path_printf(u, n, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", n);
return 0;
@ -1040,7 +1032,7 @@ int config_parse_exec_input_text(
return 0;
}
r = unit_full_printf(u, unescaped, &resolved);
r = unit_full_printf_full(u, unescaped, EXEC_STDIN_DATA_MAX, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", unescaped);
@ -1155,7 +1147,7 @@ int config_parse_exec_output(
n = startswith(rvalue, "fd:");
if (n) {
r = unit_full_printf(u, n, &resolved);
r = unit_fd_printf(u, n, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
return 0;
@ -1180,7 +1172,7 @@ int config_parse_exec_output(
} else if ((n = startswith(rvalue, "file:"))) {
r = unit_full_printf(u, n, &resolved);
r = unit_path_printf(u, n, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n);
return 0;
@ -1194,7 +1186,7 @@ int config_parse_exec_output(
} else if ((n = startswith(rvalue, "append:"))) {
r = unit_full_printf(u, n, &resolved);
r = unit_path_printf(u, n, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n);
return 0;
@ -1208,7 +1200,7 @@ int config_parse_exec_output(
} else if ((n = startswith(rvalue, "truncate:"))) {
r = unit_full_printf(u, n, &resolved);
r = unit_path_printf(u, n, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n);
return 0;
@ -2080,7 +2072,7 @@ int config_parse_path_spec(const char *unit,
return 0;
}
r = unit_full_printf(UNIT(p), rvalue, &k);
r = unit_path_printf(UNIT(p), rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
@ -2175,7 +2167,7 @@ int config_parse_fdname(
return 0;
}
r = unit_full_printf(UNIT(s), rvalue, &p);
r = unit_fd_printf(UNIT(s), rvalue, &p);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -2264,7 +2256,7 @@ int config_parse_bus_name(
assert(rvalue);
assert(u);
r = unit_full_printf(u, rvalue, &k);
r = unit_full_printf_full(u, rvalue, SD_BUS_MAXIMUM_NAME_LENGTH, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
@ -2557,7 +2549,7 @@ int config_parse_working_directory(
} else {
_cleanup_free_ char *k = NULL;
r = unit_full_printf(u, rvalue, &k);
r = unit_path_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, missing_ok ? LOG_WARNING : LOG_ERR, filename, line, r,
"Failed to resolve unit specifiers in working directory path '%s'%s: %m",
@ -2604,7 +2596,7 @@ int config_parse_unit_env_file(const char *unit,
return 0;
}
r = unit_full_printf(u, rvalue, &n);
r = unit_full_printf_full(u, rvalue, PATH_MAX, &n);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -2665,7 +2657,7 @@ int config_parse_environ(
return 0;
if (u) {
r = unit_full_printf(u, word, &resolved);
r = unit_env_printf(u, word, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in %s, ignoring: %m", word);
@ -2730,7 +2722,7 @@ int config_parse_pass_environ(
break;
if (u) {
r = unit_full_printf(u, word, &k);
r = unit_env_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve specifiers in %s, ignoring: %m", word);
@ -2805,7 +2797,7 @@ int config_parse_unset_environ(
break;
if (u) {
r = unit_full_printf(u, word, &k);
r = unit_env_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in %s, ignoring: %m", word);
@ -2932,7 +2924,7 @@ int config_parse_log_namespace(
return 0;
}
r = unit_full_printf(u, rvalue, &k);
r = unit_full_printf_full(u, rvalue, NAME_MAX, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
@ -2985,7 +2977,7 @@ int config_parse_unit_condition_path(
if (negate)
rvalue++;
r = unit_full_printf(u, rvalue, &p);
r = unit_path_printf(u, rvalue, &p);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
@ -3090,7 +3082,7 @@ int config_parse_unit_requires_mounts_for(
if (r == 0)
return 0;
r = unit_full_printf(u, word, &resolved);
r = unit_path_printf(u, word, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
continue;
@ -3960,7 +3952,7 @@ int config_parse_device_allow(
return 0;
}
r = unit_full_printf(userdata, path, &resolved);
r = unit_path_printf(userdata, path, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", path);
@ -4026,7 +4018,7 @@ int config_parse_io_device_weight(
return 0;
}
r = unit_full_printf(userdata, path, &resolved);
r = unit_path_printf(userdata, path, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", path);
@ -4095,7 +4087,7 @@ int config_parse_io_device_latency(
return 0;
}
r = unit_full_printf(userdata, path, &resolved);
r = unit_path_printf(userdata, path, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", path);
@ -4165,7 +4157,7 @@ int config_parse_io_limit(
return 0;
}
r = unit_full_printf(userdata, path, &resolved);
r = unit_path_printf(userdata, path, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", path);
@ -4251,7 +4243,7 @@ int config_parse_blockio_device_weight(
return 0;
}
r = unit_full_printf(userdata, path, &resolved);
r = unit_path_printf(userdata, path, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", path);
@ -4324,7 +4316,7 @@ int config_parse_blockio_bandwidth(
return 0;
}
r = unit_full_printf(userdata, path, &resolved);
r = unit_path_printf(userdata, path, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", path);
@ -4440,7 +4432,7 @@ int config_parse_exec_directories(
if (r == 0)
return 0;
r = unit_full_printf(u, word, &k);
r = unit_path_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
@ -4503,7 +4495,7 @@ int config_parse_set_credential(
return 0;
}
r = unit_full_printf(u, word, &k);
r = unit_cred_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
return 0;
@ -4588,7 +4580,7 @@ int config_parse_load_credential(
return 0;
}
r = unit_full_printf(u, word, &k);
r = unit_cred_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
return 0;
@ -4605,7 +4597,7 @@ int config_parse_load_credential(
if (!q)
return log_oom();
} else {
r = unit_full_printf(u, p, &q);
r = unit_path_printf(u, p, &q);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", p);
return 0;
@ -4740,7 +4732,7 @@ int config_parse_namespace_path_strv(
w++;
}
r = unit_full_printf(u, w, &resolved);
r = unit_path_printf(u, w, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s: %m", w);
continue;
@ -4820,7 +4812,7 @@ int config_parse_temporary_filesystems(
continue;
}
r = unit_full_printf(u, path, &resolved);
r = unit_path_printf(u, path, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", path);
continue;
@ -4881,7 +4873,7 @@ int config_parse_bind_paths(
if (r == 0)
break;
r = unit_full_printf(u, source, &sresolved);
r = unit_full_printf_full(u, source, PATH_MAX, &sresolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in \"%s\", ignoring: %m", source);
@ -4912,7 +4904,7 @@ int config_parse_bind_paths(
continue;
}
r = unit_full_printf(u, destination, &dresolved);
r = unit_path_printf(u, destination, &dresolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve specifiers in \"%s\", ignoring: %m", destination);
@ -5028,7 +5020,7 @@ int config_parse_mount_images(
s++;
}
r = unit_full_printf(u, s, &sresolved);
r = unit_path_printf(u, s, &sresolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
@ -5044,7 +5036,7 @@ int config_parse_mount_images(
continue;
}
r = unit_full_printf(u, second, &dresolved);
r = unit_path_printf(u, second, &dresolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve specifiers in \"%s\", ignoring: %m", second);
@ -5187,7 +5179,7 @@ int config_parse_extension_images(
s++;
}
r = unit_full_printf(u, s, &sresolved);
r = unit_path_printf(u, s, &sresolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
@ -5416,7 +5408,7 @@ int config_parse_pid_file(
return 0;
}
r = unit_full_printf(u, rvalue, &k);
r = unit_path_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -5537,7 +5529,7 @@ int config_parse_ip_filter_bpf_progs(
return 0;
}
r = unit_full_printf(u, rvalue, &resolved);
r = unit_path_printf(u, rvalue, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -5611,7 +5603,7 @@ int config_parse_bpf_foreign_program(
return 0;
}
r = unit_full_printf(u, rvalue, &resolved);
r = unit_path_printf(u, rvalue, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
@ -5661,13 +5653,10 @@ int config_parse_cgroup_socket_bind(
}
if (rvalue) {
if (streq(word, "IPv4"))
af = AF_INET;
else if (streq(word, "IPv6"))
af = AF_INET6;
else {
af = af_from_ipv4_ipv6(word);
if (af == AF_UNSPEC) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Only IPv4 and IPv6 protocols are supported, ignoring.");
"Only \"ipv4\" and \"ipv6\" protocols are supported, ignoring.");
return 0;
}

View File

@ -201,10 +201,10 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) {
assert(format);
assert(ret);
return specifier_printf(format, table, u, ret);
return specifier_printf(format, UNIT_NAME_MAX, table, u, ret);
}
int unit_full_printf(const Unit *u, const char *format, char **ret) {
int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, char **ret) {
/* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of additional codes
* (which are likely not suitable for unescaped inclusion in unit names):
*
@ -265,5 +265,5 @@ int unit_full_printf(const Unit *u, const char *format, char **ret) {
{}
};
return specifier_printf(format, table, u, ret);
return specifier_printf(format, max_length, table, u, ret);
}

View File

@ -1,7 +1,26 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "creds-util.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "unit.h"
int unit_name_printf(const Unit *u, const char* text, char **ret);
int unit_full_printf(const Unit *u, const char *text, char **ret);
int unit_full_printf_full(const Unit *u, const char *text, size_t max_length, char **ret);
static inline int unit_full_printf(const Unit *u, const char *text, char **ret) {
return unit_full_printf_full(u, text, LONG_LINE_MAX, ret);
}
static inline int unit_path_printf(const Unit *u, const char *text, char **ret) {
return unit_full_printf_full(u, text, PATH_MAX-1, ret);
}
static inline int unit_fd_printf(const Unit *u, const char *text, char **ret) {
return unit_full_printf_full(u, text, FDNAME_MAX, ret);
}
static inline int unit_cred_printf(const Unit *u, const char *text, char **ret) {
return unit_full_printf_full(u, text, CREDENTIAL_NAME_MAX, ret);
}
static inline int unit_env_printf(const Unit *u, const char *text, char **ret) {
return unit_full_printf_full(u, text, sc_arg_max(), ret);
}

View File

@ -8,6 +8,7 @@
#include "sd-daemon.h"
#include "af-list.h"
#include "alloc-util.h"
#include "def.h"
#include "errno-util.h"
@ -498,7 +499,7 @@ static int accept_connection(
log_debug("Accepted %s %s connection from %s",
type,
socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
af_to_ipv4_ipv6(socket_address_family(addr)),
a);
*hostname = b;

View File

@ -27,5 +27,5 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
int dhcp_lease_save(const sd_dhcp_lease *lease, const char *lease_file);
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);

View File

@ -2052,7 +2052,7 @@ int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
return client_initialize_time_events(client);
}
int sd_dhcp_client_is_running(const sd_dhcp_client *client) {
int sd_dhcp_client_is_running(sd_dhcp_client *client) {
if (!client)
return 0;

View File

@ -31,7 +31,7 @@
#include "tmpfile-util.h"
#include "unaligned.h"
int sd_dhcp_lease_get_address(const sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
@ -42,7 +42,7 @@ int sd_dhcp_lease_get_address(const sd_dhcp_lease *lease, struct in_addr *addr)
return 0;
}
int sd_dhcp_lease_get_broadcast(const sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
@ -53,7 +53,7 @@ int sd_dhcp_lease_get_broadcast(const sd_dhcp_lease *lease, struct in_addr *addr
return 0;
}
int sd_dhcp_lease_get_lifetime(const sd_dhcp_lease *lease, uint32_t *lifetime) {
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
assert_return(lease, -EINVAL);
assert_return(lifetime, -EINVAL);
@ -64,7 +64,7 @@ int sd_dhcp_lease_get_lifetime(const sd_dhcp_lease *lease, uint32_t *lifetime) {
return 0;
}
int sd_dhcp_lease_get_t1(const sd_dhcp_lease *lease, uint32_t *t1) {
int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
assert_return(lease, -EINVAL);
assert_return(t1, -EINVAL);
@ -75,7 +75,7 @@ int sd_dhcp_lease_get_t1(const sd_dhcp_lease *lease, uint32_t *t1) {
return 0;
}
int sd_dhcp_lease_get_t2(const sd_dhcp_lease *lease, uint32_t *t2) {
int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
assert_return(lease, -EINVAL);
assert_return(t2, -EINVAL);
@ -86,7 +86,7 @@ int sd_dhcp_lease_get_t2(const sd_dhcp_lease *lease, uint32_t *t2) {
return 0;
}
int sd_dhcp_lease_get_mtu(const sd_dhcp_lease *lease, uint16_t *mtu) {
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
assert_return(lease, -EINVAL);
assert_return(mtu, -EINVAL);
@ -98,7 +98,7 @@ int sd_dhcp_lease_get_mtu(const sd_dhcp_lease *lease, uint16_t *mtu) {
}
int sd_dhcp_lease_get_servers(
const sd_dhcp_lease *lease,
sd_dhcp_lease *lease,
sd_dhcp_lease_server_type_t what,
const struct in_addr **addr) {
@ -114,26 +114,26 @@ int sd_dhcp_lease_get_servers(
return (int) lease->servers[what].size;
}
int sd_dhcp_lease_get_dns(const sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, addr);
}
int sd_dhcp_lease_get_ntp(const sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, addr);
}
int sd_dhcp_lease_get_sip(const sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, addr);
}
int sd_dhcp_lease_get_pop3(const sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_POP3, addr);
}
int sd_dhcp_lease_get_smtp(const sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SMTP, addr);
}
int sd_dhcp_lease_get_lpr(const sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_LPR, addr);
}
int sd_dhcp_lease_get_domainname(const sd_dhcp_lease *lease, const char **domainname) {
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
assert_return(lease, -EINVAL);
assert_return(domainname, -EINVAL);
@ -144,7 +144,7 @@ int sd_dhcp_lease_get_domainname(const sd_dhcp_lease *lease, const char **domain
return 0;
}
int sd_dhcp_lease_get_hostname(const sd_dhcp_lease *lease, const char **hostname) {
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
assert_return(lease, -EINVAL);
assert_return(hostname, -EINVAL);
@ -155,7 +155,7 @@ int sd_dhcp_lease_get_hostname(const sd_dhcp_lease *lease, const char **hostname
return 0;
}
int sd_dhcp_lease_get_root_path(const sd_dhcp_lease *lease, const char **root_path) {
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
assert_return(lease, -EINVAL);
assert_return(root_path, -EINVAL);
@ -166,7 +166,7 @@ int sd_dhcp_lease_get_root_path(const sd_dhcp_lease *lease, const char **root_pa
return 0;
}
int sd_dhcp_lease_get_router(const sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
@ -177,7 +177,7 @@ int sd_dhcp_lease_get_router(const sd_dhcp_lease *lease, const struct in_addr **
return (int) lease->router_size;
}
int sd_dhcp_lease_get_netmask(const sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
@ -188,7 +188,7 @@ int sd_dhcp_lease_get_netmask(const sd_dhcp_lease *lease, struct in_addr *addr)
return 0;
}
int sd_dhcp_lease_get_server_identifier(const sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
@ -199,7 +199,7 @@ int sd_dhcp_lease_get_server_identifier(const sd_dhcp_lease *lease, struct in_ad
return 0;
}
int sd_dhcp_lease_get_next_server(const sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
@ -214,7 +214,7 @@ int sd_dhcp_lease_get_next_server(const sd_dhcp_lease *lease, struct in_addr *ad
* The returned routes array must be freed by the caller.
* Route objects have the same lifetime of the lease and must not be freed.
*/
int sd_dhcp_lease_get_routes(const sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
sd_dhcp_route **ret;
unsigned i;
@ -235,7 +235,7 @@ int sd_dhcp_lease_get_routes(const sd_dhcp_lease *lease, sd_dhcp_route ***routes
return (int) lease->static_route_size;
}
int sd_dhcp_lease_get_search_domains(const sd_dhcp_lease *lease, char ***domains) {
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
size_t r;
assert_return(lease, -EINVAL);
@ -250,7 +250,7 @@ int sd_dhcp_lease_get_search_domains(const sd_dhcp_lease *lease, char ***domains
return -ENODATA;
}
int sd_dhcp_lease_get_vendor_specific(const sd_dhcp_lease *lease, const void **data, size_t *data_len) {
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
assert_return(lease, -EINVAL);
assert_return(data, -EINVAL);
assert_return(data_len, -EINVAL);
@ -868,7 +868,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
return 0;
}
int dhcp_lease_save(const sd_dhcp_lease *lease, const char *lease_file) {
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
struct sd_dhcp_raw_option *option;
@ -1313,7 +1313,7 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
return 0;
}
int sd_dhcp_lease_get_client_id(const sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
assert_return(lease, -EINVAL);
assert_return(client_id, -EINVAL);
assert_return(client_id_len, -EINVAL);
@ -1348,7 +1348,7 @@ int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t
return 0;
}
int sd_dhcp_lease_get_timezone(const sd_dhcp_lease *lease, const char **tz) {
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
assert_return(lease, -EINVAL);
assert_return(tz, -EINVAL);
@ -1359,7 +1359,7 @@ int sd_dhcp_lease_get_timezone(const sd_dhcp_lease *lease, const char **tz) {
return 0;
}
int sd_dhcp_route_get_destination(const sd_dhcp_route *route, struct in_addr *destination) {
int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
assert_return(route, -EINVAL);
assert_return(destination, -EINVAL);
@ -1367,7 +1367,7 @@ int sd_dhcp_route_get_destination(const sd_dhcp_route *route, struct in_addr *de
return 0;
}
int sd_dhcp_route_get_destination_prefix_length(const sd_dhcp_route *route, uint8_t *length) {
int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
assert_return(route, -EINVAL);
assert_return(length, -EINVAL);
@ -1375,7 +1375,7 @@ int sd_dhcp_route_get_destination_prefix_length(const sd_dhcp_route *route, uint
return 0;
}
int sd_dhcp_route_get_gateway(const sd_dhcp_route *route, struct in_addr *gateway) {
int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
assert_return(route, -EINVAL);
assert_return(gateway, -EINVAL);
@ -1383,7 +1383,7 @@ int sd_dhcp_route_get_gateway(const sd_dhcp_route *route, struct in_addr *gatewa
return 0;
}
int sd_dhcp_route_get_option(const sd_dhcp_route *route) {
int sd_dhcp_route_get_option(sd_dhcp_route *route) {
assert_return(route, -EINVAL);
return route->option;

View File

@ -12,6 +12,7 @@
#include "sd-bus.h"
#include "af-list.h"
#include "alloc-util.h"
#include "bus-container.h"
#include "bus-control.h"
@ -821,11 +822,8 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
return -EINVAL;
if (family) {
if (streq(family, "ipv4"))
hints.ai_family = AF_INET;
else if (streq(family, "ipv6"))
hints.ai_family = AF_INET6;
else
hints.ai_family = af_from_ipv4_ipv6(family);
if (hints.ai_family == AF_UNSPEC)
return -EINVAL;
}

View File

@ -152,7 +152,7 @@ int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_famil
return 0;
}
int sd_genl_message_get_family(const sd_netlink *nl, const sd_netlink_message *m, sd_genl_family_t *family) {
int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *family) {
uint16_t type;
int r;

View File

@ -114,7 +114,7 @@ sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
return NULL;
}
int sd_netlink_message_get_type(const sd_netlink_message *m, uint16_t *type) {
int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
assert_return(m, -EINVAL);
assert_return(type, -EINVAL);
@ -132,7 +132,7 @@ int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
return 0;
}
int sd_netlink_message_is_broadcast(const sd_netlink_message *m) {
int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
assert_return(m, -EINVAL);
return m->broadcast;
@ -1235,14 +1235,14 @@ uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
return m->hdr->nlmsg_seq;
}
int sd_netlink_message_is_error(const sd_netlink_message *m) {
int sd_netlink_message_is_error(sd_netlink_message *m) {
assert_return(m, 0);
assert_return(m->hdr, 0);
return m->hdr->nlmsg_type == NLMSG_ERROR;
}
int sd_netlink_message_get_errno(const sd_netlink_message *m) {
int sd_netlink_message_get_errno(sd_netlink_message *m) {
struct nlmsgerr *err;
assert_return(m, -EINVAL);

View File

@ -142,7 +142,7 @@ void *sd_netlink_slot_set_userdata(sd_netlink_slot *slot, void *userdata) {
return ret;
}
int sd_netlink_slot_get_destroy_callback(const sd_netlink_slot *slot, sd_netlink_destroy_t *callback) {
int sd_netlink_slot_get_destroy_callback(sd_netlink_slot *slot, sd_netlink_destroy_t *callback) {
assert_return(slot, -EINVAL);
if (callback)
@ -158,7 +158,7 @@ int sd_netlink_slot_set_destroy_callback(sd_netlink_slot *slot, sd_netlink_destr
return 0;
}
int sd_netlink_slot_get_floating(const sd_netlink_slot *slot) {
int sd_netlink_slot_get_floating(sd_netlink_slot *slot) {
assert_return(slot, -EINVAL);
return slot->floating;
@ -186,7 +186,7 @@ int sd_netlink_slot_set_floating(sd_netlink_slot *slot, int b) {
return 1;
}
int sd_netlink_slot_get_description(const sd_netlink_slot *slot, const char **description) {
int sd_netlink_slot_get_description(sd_netlink_slot *slot, const char **description) {
assert_return(slot, -EINVAL);
if (description)

View File

@ -409,6 +409,44 @@ int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void
return 0;
}
MultipathRoute *multipath_route_free(MultipathRoute *m) {
if (!m)
return NULL;
free(m->ifname);
return mfree(m);
}
int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret) {
_cleanup_(multipath_route_freep) MultipathRoute *n = NULL;
_cleanup_free_ char *ifname = NULL;
assert(m);
assert(ret);
if (m->ifname) {
ifname = strdup(m->ifname);
if (!ifname)
return -ENOMEM;
}
n = new(MultipathRoute, 1);
if (!n)
return -ENOMEM;
*n = (MultipathRoute) {
.gateway = m->gateway,
.weight = m->weight,
.ifindex = m->ifindex,
.ifname = TAKE_PTR(ifname),
};
*ret = TAKE_PTR(n);
return 0;
}
int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret) {
_cleanup_ordered_set_free_free_ OrderedSet *set = NULL;
int r;
@ -420,7 +458,7 @@ int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, O
return -EBADMSG;
for (; size >= sizeof(struct rtnexthop); ) {
_cleanup_free_ MultipathRoute *m = NULL;
_cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
if (NLMSG_ALIGN(rtnh->rtnh_len) > size)
return -EBADMSG;

View File

@ -19,10 +19,16 @@ typedef struct RouteVia {
typedef struct MultipathRoute {
RouteVia gateway;
int ifindex;
uint32_t weight;
int ifindex;
char *ifname;
} MultipathRoute;
MultipathRoute *multipath_route_free(MultipathRoute *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret);
uint32_t rtnl_message_get_serial(sd_netlink_message *m);
void rtnl_message_seal(sd_netlink_message *m);

View File

@ -81,7 +81,7 @@ int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags) {
return 0;
}
int sd_rtnl_message_route_get_flags(const sd_netlink_message *m, unsigned *flags) {
int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -110,7 +110,7 @@ int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table)
return 0;
}
int sd_rtnl_message_route_get_family(const sd_netlink_message *m, int *family) {
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -125,7 +125,7 @@ int sd_rtnl_message_route_get_family(const sd_netlink_message *m, int *family) {
return 0;
}
int sd_rtnl_message_route_get_type(const sd_netlink_message *m, unsigned char *type) {
int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -154,7 +154,7 @@ int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type) {
return 0;
}
int sd_rtnl_message_route_get_protocol(const sd_netlink_message *m, unsigned char *protocol) {
int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -169,7 +169,7 @@ int sd_rtnl_message_route_get_protocol(const sd_netlink_message *m, unsigned cha
return 0;
}
int sd_rtnl_message_route_get_scope(const sd_netlink_message *m, unsigned char *scope) {
int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -184,7 +184,7 @@ int sd_rtnl_message_route_get_scope(const sd_netlink_message *m, unsigned char *
return 0;
}
int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, uint8_t *tos) {
int sd_rtnl_message_route_get_tos(sd_netlink_message *m, uint8_t *tos) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -199,7 +199,7 @@ int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, uint8_t *tos) {
return 0;
}
int sd_rtnl_message_route_get_table(const sd_netlink_message *m, unsigned char *table) {
int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -214,7 +214,7 @@ int sd_rtnl_message_route_get_table(const sd_netlink_message *m, unsigned char *
return 0;
}
int sd_rtnl_message_route_get_dst_prefixlen(const sd_netlink_message *m, unsigned char *dst_len) {
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -229,7 +229,7 @@ int sd_rtnl_message_route_get_dst_prefixlen(const sd_netlink_message *m, unsigne
return 0;
}
int sd_rtnl_message_route_get_src_prefixlen(const sd_netlink_message *m, unsigned char *src_len) {
int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len) {
struct rtmsg *rtm;
assert_return(m, -EINVAL);
@ -324,7 +324,7 @@ int sd_rtnl_message_nexthop_set_flags(sd_netlink_message *m, uint8_t flags) {
return 0;
}
int sd_rtnl_message_nexthop_get_family(const sd_netlink_message *m, uint8_t *family) {
int sd_rtnl_message_nexthop_get_family(sd_netlink_message *m, uint8_t *family) {
struct nhmsg *nhm;
assert_return(m, -EINVAL);
@ -338,7 +338,7 @@ int sd_rtnl_message_nexthop_get_family(const sd_netlink_message *m, uint8_t *fam
return 0;
}
int sd_rtnl_message_nexthop_get_protocol(const sd_netlink_message *m, uint8_t *protocol) {
int sd_rtnl_message_nexthop_get_protocol(sd_netlink_message *m, uint8_t *protocol) {
struct nhmsg *nhm;
assert_return(m, -EINVAL);
@ -378,7 +378,7 @@ int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state) {
return 0;
}
int sd_rtnl_message_neigh_get_flags(const sd_netlink_message *m, uint8_t *flags) {
int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags) {
struct ndmsg *ndm;
assert_return(m, -EINVAL);
@ -391,7 +391,7 @@ int sd_rtnl_message_neigh_get_flags(const sd_netlink_message *m, uint8_t *flags)
return 0;
}
int sd_rtnl_message_neigh_get_state(const sd_netlink_message *m, uint16_t *state) {
int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state) {
struct ndmsg *ndm;
assert_return(m, -EINVAL);
@ -404,7 +404,7 @@ int sd_rtnl_message_neigh_get_state(const sd_netlink_message *m, uint16_t *state
return 0;
}
int sd_rtnl_message_neigh_get_family(const sd_netlink_message *m, int *family) {
int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family) {
struct ndmsg *ndm;
assert_return(m, -EINVAL);
@ -419,7 +419,7 @@ int sd_rtnl_message_neigh_get_family(const sd_netlink_message *m, int *family) {
return 0;
}
int sd_rtnl_message_neigh_get_ifindex(const sd_netlink_message *m, int *index) {
int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index) {
struct ndmsg *ndm;
assert_return(m, -EINVAL);
@ -572,7 +572,7 @@ int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope) {
return 0;
}
int sd_rtnl_message_addr_get_family(const sd_netlink_message *m, int *family) {
int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family) {
struct ifaddrmsg *ifa;
assert_return(m, -EINVAL);
@ -587,7 +587,7 @@ int sd_rtnl_message_addr_get_family(const sd_netlink_message *m, int *family) {
return 0;
}
int sd_rtnl_message_addr_get_prefixlen(const sd_netlink_message *m, unsigned char *prefixlen) {
int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
struct ifaddrmsg *ifa;
assert_return(m, -EINVAL);
@ -602,7 +602,7 @@ int sd_rtnl_message_addr_get_prefixlen(const sd_netlink_message *m, unsigned cha
return 0;
}
int sd_rtnl_message_addr_get_scope(const sd_netlink_message *m, unsigned char *scope) {
int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope) {
struct ifaddrmsg *ifa;
assert_return(m, -EINVAL);
@ -617,7 +617,7 @@ int sd_rtnl_message_addr_get_scope(const sd_netlink_message *m, unsigned char *s
return 0;
}
int sd_rtnl_message_addr_get_flags(const sd_netlink_message *m, unsigned char *flags) {
int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags) {
struct ifaddrmsg *ifa;
assert_return(m, -EINVAL);
@ -632,7 +632,7 @@ int sd_rtnl_message_addr_get_flags(const sd_netlink_message *m, unsigned char *f
return 0;
}
int sd_rtnl_message_addr_get_ifindex(const sd_netlink_message *m, int *ifindex) {
int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex) {
struct ifaddrmsg *ifa;
assert_return(m, -EINVAL);
@ -692,7 +692,7 @@ int sd_rtnl_message_new_addr_update(sd_netlink *rtnl, sd_netlink_message **ret,
return 0;
}
int sd_rtnl_message_link_get_ifindex(const sd_netlink_message *m, int *ifindex) {
int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex) {
struct ifinfomsg *ifi;
assert_return(m, -EINVAL);
@ -707,7 +707,7 @@ int sd_rtnl_message_link_get_ifindex(const sd_netlink_message *m, int *ifindex)
return 0;
}
int sd_rtnl_message_link_get_flags(const sd_netlink_message *m, unsigned *flags) {
int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
struct ifinfomsg *ifi;
assert_return(m, -EINVAL);
@ -722,7 +722,7 @@ int sd_rtnl_message_link_get_flags(const sd_netlink_message *m, unsigned *flags)
return 0;
}
int sd_rtnl_message_link_get_type(const sd_netlink_message *m, unsigned short *type) {
int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) {
struct ifinfomsg *ifi;
assert_return(m, -EINVAL);
@ -737,7 +737,7 @@ int sd_rtnl_message_link_get_type(const sd_netlink_message *m, unsigned short *t
return 0;
}
int sd_rtnl_message_get_family(const sd_netlink_message *m, int *family) {
int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
assert_return(m, -EINVAL);
assert_return(family, -EINVAL);
@ -835,7 +835,7 @@ int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char
return 0;
}
int sd_rtnl_message_addrlabel_get_prefixlen(const sd_netlink_message *m, unsigned char *prefixlen) {
int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
struct ifaddrlblmsg *addrlabel;
assert_return(m, -EINVAL);
@ -884,7 +884,7 @@ int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, uint8_t t
return 0;
}
int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, uint8_t *tos) {
int sd_rtnl_message_routing_policy_rule_get_tos(sd_netlink_message *m, uint8_t *tos) {
struct fib_rule_hdr *frh;
assert_return(m, -EINVAL);
@ -912,7 +912,7 @@ int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, uint8_t
return 0;
}
int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, uint8_t *table) {
int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, uint8_t *table) {
struct fib_rule_hdr *frh;
assert_return(m, -EINVAL);
@ -939,7 +939,7 @@ int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, uint32_
return 0;
}
int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, uint32_t *flags) {
int sd_rtnl_message_routing_policy_rule_get_flags(sd_netlink_message *m, uint32_t *flags) {
struct fib_rule_hdr *frh;
assert_return(m, -EINVAL);
@ -966,7 +966,7 @@ int sd_rtnl_message_routing_policy_rule_set_fib_type(sd_netlink_message *m, uint
return 0;
}
int sd_rtnl_message_routing_policy_rule_get_fib_type(const sd_netlink_message *m, uint8_t *type) {
int sd_rtnl_message_routing_policy_rule_get_fib_type(sd_netlink_message *m, uint8_t *type) {
struct fib_rule_hdr *frh;
assert_return(m, -EINVAL);
@ -994,7 +994,7 @@ int sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(sd_netlink_message
return 0;
}
int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(const sd_netlink_message *m, uint8_t *len) {
int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(sd_netlink_message *m, uint8_t *len) {
struct fib_rule_hdr *frh;
assert_return(m, -EINVAL);
@ -1022,7 +1022,7 @@ int sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(sd_netlink_message
return 0;
}
int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(const sd_netlink_message *m, uint8_t *len) {
int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(sd_netlink_message *m, uint8_t *len) {
struct fib_rule_hdr *frh;
assert_return(m, -EINVAL);

View File

@ -742,7 +742,7 @@ int sd_netlink_call(sd_netlink *rtnl,
return sd_netlink_read(rtnl, serial, usec, ret);
}
int sd_netlink_get_events(const sd_netlink *rtnl) {
int sd_netlink_get_events(sd_netlink *rtnl) {
assert_return(rtnl, -EINVAL);
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
@ -752,7 +752,7 @@ int sd_netlink_get_events(const sd_netlink *rtnl) {
return 0;
}
int sd_netlink_get_timeout(const sd_netlink *rtnl, uint64_t *timeout_usec) {
int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) {
struct reply_callback *c;
assert_return(rtnl, -EINVAL);

View File

@ -105,6 +105,8 @@ sources = files('''
networkd-network.h
networkd-nexthop.c
networkd-nexthop.h
networkd-queue.c
networkd-queue.h
networkd-route.c
networkd-route.h
networkd-routing-policy-rule.c

View File

@ -9,9 +9,9 @@
#include "netlink-util.h"
#include "networkd-address-pool.h"
#include "networkd-address.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "parse-util.h"
#include "string-util.h"
#include "strv.h"
@ -150,7 +150,7 @@ static bool address_may_have_broadcast(const Address *a) {
* See https://tools.ietf.org/html/rfc3021 */
return a->family == AF_INET &&
in_addr_is_null(AF_INET, &a->in_addr_peer) &&
in4_addr_is_null(&a->in_addr_peer.in) &&
a->prefixlen <= 30;
}
@ -406,7 +406,7 @@ static int address_update(Address *address, const Address *src) {
}
if (address->family == AF_INET6 &&
in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
in6_addr_is_link_local(&address->in_addr.in6) > 0 &&
in6_addr_is_null(&address->link->ipv6ll_address)) {
r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
@ -485,6 +485,63 @@ int link_has_ipv6_address(Link *link, const struct in6_addr *address) {
return address_get(link, a, NULL) >= 0;
}
static int link_get_ipv4_address(Set *addresses, const struct in_addr *address, Address **ret) {
Address *a;
assert(address);
SET_FOREACH(a, addresses) {
if (a->family != AF_INET)
continue;
if (!in4_addr_equal(&a->in_addr.in, address))
continue;
if (ret)
*ret = a;
return 0;
}
return -ENOENT;
}
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
Link *link;
int r;
assert(manager);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
if (family == AF_INET)
HASHMAP_FOREACH(link, manager->links) {
Address *a;
if (link_get_ipv4_address(link->addresses, &address->in, &a) >= 0)
return !check_ready || address_is_ready(a);
if (link_get_ipv4_address(link->addresses_foreign, &address->in, &a) >= 0)
return !check_ready || address_is_ready(a);
}
else {
_cleanup_(address_freep) Address *tmp = NULL;
Address *a;
r = address_new(&tmp);
if (r < 0)
return r;
tmp->family = family;
tmp->in_addr = *address;
HASHMAP_FOREACH(link, manager->links)
if (address_get(link, tmp, &a) >= 0)
return !check_ready || address_is_ready(a);
}
return false;
}
static void log_address_debug(const Address *address, const char *str, const Link *link) {
_cleanup_free_ char *addr = NULL, *peer = NULL;
char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX];
@ -520,25 +577,6 @@ static void log_address_debug(const Address *address, const char *str, const Lin
preferred_str ? "for " : "forever", strempty(preferred_str));
}
static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->ifname);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
log_link_message_warning_errno(link, m, r, "Could not drop address");
else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
return 1;
}
static int address_set_netlink_message(const Address *address, sd_netlink_message *req, Link *link) {
int r;
@ -570,6 +608,33 @@ static int address_set_netlink_message(const Address *address, sd_netlink_messag
return 0;
}
int address_remove_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->address_remove_messages > 0);
assert(error_msg);
link->address_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
log_link_message_warning_errno(link, m, r, error_msg);
else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
return 1;
}
static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return address_remove_handler_internal(rtnl, m, link, "Could not drop address");
}
int address_remove(
const Address *address,
Link *link,
@ -603,6 +668,7 @@ int address_remove(
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
link->address_remove_messages++;
return 0;
}
@ -706,7 +772,7 @@ int link_drop_foreign_addresses(Link *link) {
SET_FOREACH(address, link->addresses_foreign) {
/* we consider IPv6LL addresses to be managed by the kernel */
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1 && link_ipv6ll_enabled(link))
continue;
if (link_address_is_dynamic(link, address)) {
@ -732,35 +798,6 @@ int link_drop_foreign_addresses(Link *link) {
return r;
}
static int remove_static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->ifname);
assert(link->address_remove_messages > 0);
link->address_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
log_link_message_warning_errno(link, m, r, "Could not drop address");
else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
if (link->address_remove_messages == 0 && link->request_static_addresses) {
link_set_state(link, LINK_STATE_CONFIGURING);
r = link_set_addresses(link);
if (r < 0)
link_enter_failed(link);
}
return 1;
}
int link_drop_addresses(Link *link) {
Address *address, *pool_address;
int k, r = 0;
@ -769,17 +806,15 @@ int link_drop_addresses(Link *link) {
SET_FOREACH(address, link->addresses) {
/* we consider IPv6LL addresses to be managed by the kernel */
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1 && link_ipv6ll_enabled(link))
continue;
k = address_remove(address, link, remove_static_address_handler);
k = address_remove(address, link, NULL);
if (k < 0 && r >= 0) {
r = k;
continue;
}
link->address_remove_messages++;
SET_FOREACH(pool_address, link->pool_addresses)
if (address_equal(address, pool_address))
address_free(set_remove(link->pool_addresses, pool_address));
@ -845,9 +880,31 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
return 1;
}
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(error_msg);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, error_msg);
link_enter_failed(link);
return 0;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
return 1;
}
static int ipv4_dad_configure(Address *address);
int address_configure(
static int address_configure(
const Address *address,
Link *link,
link_netlink_message_handler_t callback,
@ -951,78 +1008,24 @@ int address_configure(
return k;
}
static int static_address_ready_callback(Address *address) {
Address *a;
Link *link;
static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(address);
assert(address->link);
assert(link);
assert(link->static_address_messages > 0);
link = address->link;
link->static_address_messages--;
if (!link->addresses_configured)
return 0;
SET_FOREACH(a, link->static_addresses)
if (!address_is_ready(a)) {
_cleanup_free_ char *str = NULL;
(void) in_addr_prefix_to_string(a->family, &a->in_addr, a->prefixlen, &str);
log_link_debug(link, "an address %s is not ready", strnull(str));
return 0;
}
/* This should not be called again */
SET_FOREACH(a, link->static_addresses)
a->callback = NULL;
link->addresses_ready = true;
r = link_set_ipv6_proxy_ndp_addresses(link);
if (r < 0)
r = address_configure_handler_internal(rtnl, m, link, "Failed to set static address");
if (r <= 0)
return r;
return link_set_routes(link);
}
static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->ifname);
assert(link->address_messages > 0);
link->address_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
if (link->address_messages == 0) {
Address *a;
if (link->static_address_messages == 0) {
log_link_debug(link, "Addresses set");
link->addresses_configured = true;
link->static_addresses_configured = true;
link_check_ready(link);
/* When all static addresses are already ready, then static_address_ready_callback()
* will not be called automatically. So, call it here. */
a = set_first(link->static_addresses);
if (!a) {
log_link_debug(link, "No static address is stored. Already removed?");
return 1;
}
r = static_address_ready_callback(a);
r = dhcp4_server_configure(link);
if (r < 0)
link_enter_failed(link);
}
@ -1030,55 +1033,65 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
return 1;
}
static int static_address_configure(const Address *address, Link *link) {
Address *ret;
static int static_address_after_configure(Request *req, void *object) {
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(address);
assert(link);
r = address_configure(address, link, address_handler, &ret);
if (r < 0)
return log_link_warning_errno(link, r, "Could not configure static address: %m");
link = req->link;
link->address_messages++;
r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret);
r = set_ensure_put(&link->static_addresses, &address_hash_ops, address);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store static address: %m");
ret->callback = static_address_ready_callback;
return 0;
}
int link_set_addresses(Link *link) {
Address *ad;
int link_request_address(
Link *link,
Address *address,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
assert(link);
assert(address);
log_address_debug(address, "Requesting", link);
return link_queue_request(link, REQUEST_TYPE_ADDRESS, address, consume_object,
message_counter, netlink_handler, ret);
}
int link_request_static_addresses(Link *link) {
Address *a;
Prefix *p;
int r;
assert(link);
assert(link->network);
if (link->address_remove_messages != 0) {
log_link_debug(link, "Removing old addresses, new addresses will be configured later.");
link->request_static_addresses = true;
return 0;
}
link->static_addresses_configured = false;
if (link->address_messages != 0) {
log_link_debug(link, "Static addresses are configuring.");
return 0;
}
ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) {
Request *req;
ORDERED_HASHMAP_FOREACH(ad, link->network->addresses_by_section) {
r = static_address_configure(ad, link);
r = link_request_address(link, a, false, &link->static_address_messages,
static_address_handler, &req);
if (r < 0)
return r;
req->after_configure = static_address_after_configure;
}
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
_cleanup_(address_freep) Address *address = NULL;
Request *req;
if (!p->assign)
continue;
@ -1097,22 +1110,18 @@ int link_set_addresses(Link *link) {
address->family = AF_INET6;
address->route_metric = p->route_metric;
r = static_address_configure(address, link);
r = link_request_address(link, TAKE_PTR(address), true, &link->static_address_messages,
static_address_handler, &req);
if (r < 0)
return r;
req->after_configure = static_address_after_configure;
}
if (link->address_messages == 0) {
link->addresses_configured = true;
link->addresses_ready = true;
r = link_set_ipv6_proxy_ndp_addresses(link);
if (r < 0)
return r;
r = link_set_routes(link);
if (r < 0)
return r;
if (link->static_address_messages == 0) {
link->static_addresses_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting addresses");
link_set_state(link, LINK_STATE_CONFIGURING);
@ -1121,6 +1130,34 @@ int link_set_addresses(Link *link) {
return 0;
}
int request_process_address(Request *req) {
Address *ret = NULL; /* avoid false maybe-uninitialized warning */
int r;
assert(req);
assert(req->link);
assert(req->address);
assert(req->type == REQUEST_TYPE_ADDRESS);
if (!link_is_ready_to_configure(req->link, false))
return 0;
if (req->link->address_remove_messages > 0)
return 0;
r = address_configure(req->address, req->link, req->netlink_handler, &ret);
if (r < 0)
return r;
if (req->after_configure) {
r = req->after_configure(req, ret);
if (r < 0)
return r;
}
return 1;
}
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(address_freep) Address *tmp = NULL;
Link *link = NULL;
@ -1304,7 +1341,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
}
static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
_cleanup_free_ char *pretty = NULL;
Address *address;
Link *link;
int r;
@ -1315,22 +1351,26 @@ static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
address = (Address *) userdata;
link = address->link;
(void) in_addr_to_string(address->family, &address->in_addr, &pretty);
assert(address->family == AF_INET);
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
log_link_debug(link, "Stopping ACD client...");
return;
case SD_IPV4ACD_EVENT_BIND:
log_link_debug(link, "Successfully claimed address %s", strna(pretty));
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
link_check_ready(link);
break;
case SD_IPV4ACD_EVENT_CONFLICT:
log_link_warning(link, "DAD conflict. Dropping address %s", strna(pretty));
log_link_warning(link, "DAD conflict. Dropping address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
r = address_remove(address, link, NULL);
if (r < 0)
log_link_error_errno(link, r, "Failed to drop DAD conflicted address %s", strna(pretty));;
log_link_error_errno(link, r, "Failed to drop DAD conflicted address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
link_check_ready(link);
break;
@ -1353,12 +1393,7 @@ static int ipv4_dad_configure(Address *address) {
if (address->family != AF_INET)
return 0;
if (DEBUG_LOGGING) {
_cleanup_free_ char *pretty = NULL;
(void) in_addr_to_string(address->family, &address->in_addr, &pretty);
log_link_debug(address->link, "Starting IPv4ACD client. Probing address %s", strna(pretty));
}
log_address_debug(address, "Starting IPv4ACD client. Probing", address->link);
if (!address->acd) {
r = sd_ipv4acd_new(&address->acd);

View File

@ -16,6 +16,7 @@
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Request Request;
typedef int (*address_ready_callback_t)(Address *address);
typedef struct Address {
@ -51,7 +52,8 @@ typedef struct Address {
int address_new(Address **ret);
Address *address_free(Address *address);
int address_get(Link *link, const Address *in, Address **ret);
int address_configure(const Address *address, Link *link, link_netlink_message_handler_t callback, Address **ret);
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int address_remove_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int address_remove(const Address *address, Link *link, link_netlink_message_handler_t callback);
bool address_equal(const Address *a1, const Address *a2);
bool address_is_ready(const Address *a);
@ -60,16 +62,26 @@ int generate_ipv6_eui_64_address(const Link *link, struct in6_addr *ret);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
int link_set_addresses(Link *link);
int link_drop_addresses(Link *link);
int link_drop_foreign_addresses(Link *link);
bool link_address_is_dynamic(const Link *link, const Address *address);
int link_has_ipv6_address(Link *link, const struct in6_addr *address);
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
void ipv4_dad_unref(Link *link);
int ipv4_dad_stop(Link *link);
int ipv4_dad_update_mac(Link *link);
int link_request_address(
Link *link,
Address *address,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret);
int link_request_static_addresses(Link *link);
int request_process_address(Request *req);
int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, Manager *m);
void network_drop_invalid_addresses(Network *network);
@ -86,10 +98,3 @@ CONFIG_PARSER_PROTOTYPE(config_parse_address_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_address_scope);
CONFIG_PARSER_PROTOTYPE(config_parse_address_route_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_duplicate_address_detection);
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
#define IPV4_ADDRESS_FMT_VAL(address) \
be32toh((address).s_addr) >> 24, \
(be32toh((address).s_addr) >> 16) & 0xFFu, \
(be32toh((address).s_addr) >> 8) & 0xFFu, \
be32toh((address).s_addr) & 0xFFu

View File

@ -17,13 +17,16 @@
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-state-file.h"
#include "string-table.h"
#include "strv.h"
#include "sysctl-util.h"
#include "web-util.h"
static int dhcp4_update_address(Link *link, bool announce);
static int dhcp4_request_address_and_routes(Link *link, bool announce);
static int dhcp4_remove_all(Link *link);
void network_adjust_dhcp4(Network *network) {
@ -83,8 +86,20 @@ static void dhcp4_check_ready(Link *link) {
if (link->network->dhcp_send_decline && !link->dhcp4_address_bind)
return;
if (link->dhcp4_messages > 0)
if (link->dhcp4_messages > 0) {
log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
return;
}
if (!link->dhcp_address) {
log_link_debug(link, "%s(): DHCPv4 address is not set.", __func__);
return;
}
if (!address_is_ready(link->dhcp_address)) {
log_link_debug(link, "%s(): DHCPv4 address is not ready.", __func__);
return;
}
link->dhcp4_configured = true;
@ -102,6 +117,27 @@ static void dhcp4_check_ready(Link *link) {
link_check_ready(link);
}
static int dhcp4_after_route_configure(Request *req, void *object) {
Route *route = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ROUTE);
assert(route);
link = req->link;
r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
set_remove(link->dhcp_routes_old, route);
return 0;
}
static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@ -135,6 +171,15 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
r = dhcp4_remove_all(link);
if (r < 0)
link_enter_failed(link);
r = link_request_static_nexthops(link, true);
if (r < 0)
link_enter_failed(link);
r = link_request_static_routes(link, true);
if (r < 0)
link_enter_failed(link);
return 1;
}
@ -143,24 +188,26 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1;
}
static int dhcp_route_configure(Route *route, Link *link) {
Route *ret;
static int dhcp4_request_route(Route *in, Link *link) {
_cleanup_(route_freep) Route *route = in;
Request *req;
int r;
assert(route);
assert(link);
r = route_configure(route, link, dhcp4_route_handler, &ret);
r = link_has_route(link, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv4 route: %m");
return r;
if (r == 0)
link->dhcp4_configured = false;
link->dhcp4_messages++;
r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, ret);
r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
dhcp4_route_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
return r;
(void) set_remove(link->dhcp_routes_old, ret);
req->after_configure = dhcp4_after_route_configure;
return 0;
}
@ -171,7 +218,7 @@ static bool link_prefixroute(Link *link) {
link->manager->dhcp4_prefix_root_cannot_set_table;
}
static int link_set_dhcp_prefix_route(Link *link) {
static int dhcp4_request_prefix_route(Link *link) {
_cleanup_(route_freep) Route *route = NULL;
struct in_addr address, netmask;
int r;
@ -204,10 +251,10 @@ static int link_set_dhcp_prefix_route(Link *link) {
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
return dhcp_route_configure(route, link);
return dhcp4_request_route(TAKE_PTR(route), link);
}
static int link_set_dhcp_route_to_gateway(Link *link, const struct in_addr *gw) {
static int dhcp4_request_route_to_gateway(Link *link, const struct in_addr *gw) {
_cleanup_(route_freep) Route *route = NULL;
struct in_addr address;
int r;
@ -234,14 +281,15 @@ static int link_set_dhcp_route_to_gateway(Link *link, const struct in_addr *gw)
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
return dhcp_route_configure(route, link);
return dhcp4_request_route(TAKE_PTR(route), link);
}
static int dhcp_route_configure_auto(
Route *route,
static int dhcp4_request_route_auto(
Route *in,
Link *link,
const struct in_addr *gw) {
_cleanup_(route_freep) Route *route = in;
struct in_addr address, netmask, prefix;
uint8_t prefixlen;
int r;
@ -251,8 +299,6 @@ static int dhcp_route_configure_auto(
assert(link->dhcp_lease);
assert(gw);
/* The route object may be reused in an iteration. All elements must be set or cleared. */
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return r;
@ -309,7 +355,7 @@ static int dhcp_route_configure_auto(
return 0;
}
r = link_set_dhcp_route_to_gateway(link, gw);
r = dhcp4_request_route_to_gateway(link, gw);
if (r < 0)
return r;
@ -319,13 +365,12 @@ static int dhcp_route_configure_auto(
route->prefsrc.in = address;
}
return dhcp_route_configure(route, link);
return dhcp4_request_route(TAKE_PTR(route), link);
}
static int link_set_dhcp_static_routes(Link *link, struct in_addr *ret_default_gw) {
static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_gw) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false;
_cleanup_(route_freep) Route *route = NULL;
struct in_addr default_gw = {};
int n, r;
@ -360,24 +405,25 @@ static int link_set_dhcp_static_routes(Link *link, struct in_addr *ret_default_g
if (classless_route && static_route)
log_link_debug(link, "Classless static routes received from DHCP server: ignoring static-route option");
r = route_new(&route);
if (r < 0)
return r;
route->family = AF_INET;
route->gw_family = AF_INET;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp_route_metric;
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
for (int i = 0; i < n; i++) {
_cleanup_(route_freep) Route *route = NULL;
struct in_addr gw;
if (sd_dhcp_route_get_option(static_routes[i]) !=
(classless_route ? SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE : SD_DHCP_OPTION_STATIC_ROUTE))
continue;
r = route_new(&route);
if (r < 0)
return r;
route->family = AF_INET;
route->gw_family = AF_INET;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp_route_metric;
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
r = sd_dhcp_route_get_gateway(static_routes[i], &gw);
if (r < 0)
return r;
@ -398,7 +444,7 @@ static int link_set_dhcp_static_routes(Link *link, struct in_addr *ret_default_g
in4_addr_is_null(&default_gw))
default_gw = gw;
r = dhcp_route_configure_auto(route, link, &gw);
r = dhcp4_request_route_auto(TAKE_PTR(route), link, &gw);
if (r < 0)
return r;
}
@ -407,7 +453,7 @@ static int link_set_dhcp_static_routes(Link *link, struct in_addr *ret_default_g
return classless_route;
}
static int link_set_dhcp_gateway(Link *link, struct in_addr *ret_gw) {
static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) {
_cleanup_(route_freep) Route *route = NULL;
const struct in_addr *router;
struct in_addr address;
@ -439,7 +485,7 @@ static int link_set_dhcp_gateway(Link *link, struct in_addr *ret_gw) {
/* The dhcp netmask may mask out the gateway. First, add an explicit route for the gateway host
* so that we can route no matter the netmask or existing kernel route tables. */
r = link_set_dhcp_route_to_gateway(link, &router[0]);
r = dhcp4_request_route_to_gateway(link, &router[0]);
if (r < 0)
return r;
@ -457,7 +503,7 @@ static int link_set_dhcp_gateway(Link *link, struct in_addr *ret_gw) {
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
r = dhcp_route_configure(route, link);
r = dhcp4_request_route(TAKE_PTR(route), link);
if (r < 0)
return r;
@ -468,17 +514,21 @@ static int link_set_dhcp_gateway(Link *link, struct in_addr *ret_gw) {
if (rt->gw_family != AF_INET)
continue;
rt->gw.in = router[0];
if (!rt->protocol_set)
rt->protocol = RTPROT_DHCP;
if (!rt->priority_set)
rt->priority = link->network->dhcp_route_metric;
if (!rt->table_set)
rt->table = link_get_dhcp_route_table(link);
if (rt->mtu == 0)
rt->mtu = link->network->dhcp_route_mtu;
r = route_dup(rt, &route);
if (r < 0)
return r;
r = dhcp_route_configure(rt, link);
route->gw.in = router[0];
if (!route->protocol_set)
route->protocol = RTPROT_DHCP;
if (!route->priority_set)
route->priority = link->network->dhcp_route_metric;
if (!route->table_set)
route->table = link_get_dhcp_route_table(link);
if (route->mtu == 0)
route->mtu = link->network->dhcp_route_mtu;
r = dhcp4_request_route(TAKE_PTR(route), link);
if (r < 0)
return r;
}
@ -487,13 +537,12 @@ static int link_set_dhcp_gateway(Link *link, struct in_addr *ret_gw) {
return 0;
}
static int link_set_routes_to_servers(
static int dhcp4_request_routes_to_servers(
Link *link,
const struct in_addr *servers,
size_t n_servers,
const struct in_addr *gw) {
_cleanup_(route_freep) Route *route = NULL;
int r;
assert(link);
@ -502,24 +551,25 @@ static int link_set_routes_to_servers(
assert(servers || n_servers == 0);
assert(gw);
r = route_new(&route);
if (r < 0)
return r;
route->family = AF_INET;
route->dst_prefixlen = 32;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp_route_metric;
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
for (size_t i = 0; i < n_servers; i++) {
_cleanup_(route_freep) Route *route = NULL;
if (in4_addr_is_null(&servers[i]))
continue;
route->dst.in = servers[i];
r = route_new(&route);
if (r < 0)
return r;
r = dhcp_route_configure_auto(route, link, gw);
route->family = AF_INET;
route->dst.in = servers[i];
route->dst_prefixlen = 32;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp_route_metric;
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
r = dhcp4_request_route_auto(TAKE_PTR(route), link, gw);
if (r < 0)
return r;
}
@ -527,7 +577,7 @@ static int link_set_routes_to_servers(
return 0;
}
static int link_set_routes_to_dns(Link *link, const struct in_addr *gw) {
static int dhcp4_request_routes_to_dns(Link *link, const struct in_addr *gw) {
const struct in_addr *dns;
int r;
@ -546,10 +596,10 @@ static int link_set_routes_to_dns(Link *link, const struct in_addr *gw) {
if (r < 0)
return r;
return link_set_routes_to_servers(link, dns, r, gw);
return dhcp4_request_routes_to_servers(link, dns, r, gw);
}
static int link_set_routes_to_ntp(Link *link, const struct in_addr *gw) {
static int dhcp4_request_routes_to_ntp(Link *link, const struct in_addr *gw) {
const struct in_addr *ntp;
int r;
@ -568,25 +618,17 @@ static int link_set_routes_to_ntp(Link *link, const struct in_addr *gw) {
if (r < 0)
return r;
return link_set_routes_to_servers(link, ntp, r, gw);
return dhcp4_request_routes_to_servers(link, ntp, r, gw);
}
static int link_set_dhcp_routes(Link *link) {
static int dhcp4_request_routes(Link *link) {
struct in_addr gw = {};
Route *rt;
int r;
assert(link);
if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
return 0;
if (!link->network) /* link went down while we configured the IP addresses? */
return 0;
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
/* During configuring addresses, the link lost its carrier. As networkd is dropping
* the addresses now, let's not configure the routes either. */
if (!link->dhcp_lease)
return 0;
while ((rt = set_steal_first(link->dhcp_routes))) {
@ -595,28 +637,28 @@ static int link_set_dhcp_routes(Link *link) {
return log_link_error_errno(link, r, "Failed to store old DHCPv4 route: %m");
}
r = link_set_dhcp_prefix_route(link);
r = dhcp4_request_prefix_route(link);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: Could not set prefix route: %m");
return log_link_error_errno(link, r, "DHCP error: Could not request prefix route: %m");
r = link_set_dhcp_static_routes(link, &gw);
r = dhcp4_request_static_routes(link, &gw);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: Could not set static routes: %m");
return log_link_error_errno(link, r, "DHCP error: Could not request static routes: %m");
if (r == 0) {
/* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
* a Router option, the DHCP client MUST ignore the Router option. */
r = link_set_dhcp_gateway(link, &gw);
r = dhcp4_request_gateway(link, &gw);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: Could not set gateway: %m");
return log_link_error_errno(link, r, "DHCP error: Could not request gateway: %m");
}
r = link_set_routes_to_dns(link, &gw);
r = dhcp4_request_routes_to_dns(link, &gw);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: Could not set routes to DNS servers: %m");
return log_link_error_errno(link, r, "DHCP error: Could not request routes to DNS servers: %m");
r = link_set_routes_to_ntp(link, &gw);
r = dhcp4_request_routes_to_ntp(link, &gw);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: Could not set routes to NTP servers: %m");
return log_link_error_errno(link, r, "DHCP error: Could not request routes to NTP servers: %m");
return 0;
}
@ -670,24 +712,20 @@ static int dhcp_reset_hostname(Link *link) {
return 0;
}
static int dhcp4_remove_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int dhcp4_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->dhcp4_remove_messages > 0);
link->dhcp4_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 route, ignoring");
r = link_route_remove_handler_internal(rtnl, m, link, "Failed to remove DHCPv4 route, ignoring");
if (r <= 0)
return r;
if (link->dhcp4_remove_messages == 0) {
r = dhcp4_update_address(link, false);
r = dhcp4_request_address_and_routes(link, false);
if (r < 0)
link_enter_failed(link);
}
@ -695,26 +733,20 @@ static int dhcp4_remove_route_handler(sd_netlink *rtnl, sd_netlink_message *m, L
return 1;
}
static int dhcp4_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int dhcp4_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->dhcp4_remove_messages > 0);
link->dhcp4_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring");
else
(void) manager_rtnl_process_address(rtnl, m, link->manager);
r = address_remove_handler_internal(rtnl, m, link, "Failed to remove DHCPv4 address, ignoring");
if (r <= 0)
return r;
if (link->dhcp4_remove_messages == 0) {
r = dhcp4_update_address(link, false);
r = dhcp4_request_address_and_routes(link, false);
if (r < 0)
link_enter_failed(link);
}
@ -729,7 +761,7 @@ static int dhcp4_remove_all(Link *link) {
assert(link);
SET_FOREACH(route, link->dhcp_routes) {
k = route_remove(route, NULL, link, dhcp4_remove_route_handler);
k = route_remove(route, NULL, link, dhcp4_route_remove_handler);
if (k < 0)
r = k;
else
@ -737,7 +769,7 @@ static int dhcp4_remove_all(Link *link) {
}
if (link->dhcp_address) {
k = address_remove(link->dhcp_address, link, dhcp4_remove_address_handler);
k = address_remove(link->dhcp_address, link, dhcp4_address_remove_handler);
if (k < 0)
r = k;
else
@ -779,12 +811,18 @@ static int dhcp_lease_lost(Link *link) {
(void) sd_ipv4acd_stop(link->dhcp_acd);
return r;
if (r < 0)
return r;
r = link_request_static_nexthops(link, true);
if (r < 0)
return r;
return link_request_static_routes(link, true);
}
static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
_cleanup_free_ char *pretty = NULL;
union in_addr_union address = {};
struct in_addr address;
Link *link;
int r;
@ -795,23 +833,21 @@ static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
log_link_debug(link, "Stopping ACD client for DHCP4...");
log_link_debug(link, "Stopping ACD client for DHCPv4 address.");
return;
case SD_IPV4ACD_EVENT_BIND:
if (DEBUG_LOGGING) {
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
(void) in_addr_to_string(AF_INET, &address, &pretty);
log_link_debug(link, "Successfully claimed DHCP4 address %s", strna(pretty));
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
log_link_debug(link, "Successfully claimed DHCPv4 address "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address));
}
link->dhcp4_address_bind = true;
dhcp4_check_ready(link);
break;
case SD_IPV4ACD_EVENT_CONFLICT:
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
(void) in_addr_to_string(AF_INET, &address, &pretty);
log_link_warning(link, "DAD conflict. Dropping DHCP4 address %s", strna(pretty));
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
log_link_warning(link, "DAD conflict. Dropping DHCPv4 address "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address));
r = sd_dhcp_client_send_decline(link->dhcp_client);
if (r < 0)
@ -893,8 +929,7 @@ static int dhcp4_dad_update_mac(Link *link) {
}
static int dhcp4_start_acd(Link *link) {
union in_addr_union addr;
struct in_addr old;
struct in_addr addr, old;
int r;
if (!link->network->dhcp_send_decline)
@ -907,7 +942,7 @@ static int dhcp4_start_acd(Link *link) {
link->dhcp4_address_bind = false;
r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr.in);
r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
if (r < 0)
return r;
@ -915,7 +950,7 @@ static int dhcp4_start_acd(Link *link) {
if (r < 0)
return r;
r = sd_ipv4acd_set_address(link->dhcp_acd, &addr.in);
r = sd_ipv4acd_set_address(link->dhcp_acd, &addr);
if (r < 0)
return r;
@ -923,45 +958,51 @@ static int dhcp4_start_acd(Link *link) {
if (r < 0)
return r;
if (DEBUG_LOGGING) {
_cleanup_free_ char *pretty = NULL;
log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(addr));
(void) in_addr_to_string(AF_INET, &addr, &pretty);
log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
}
r = sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr.in, &old));
if (r < 0)
return r;
return 1;
return sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr, &old));
}
static int dhcp4_address_ready_callback(Address *address) {
Link *link;
int r;
assert(address);
link = address->link;
/* Do not call this again. */
address->callback = NULL;
r = link_set_dhcp_routes(link);
if (r < 0)
return r;
dhcp4_check_ready(address->link);
return 0;
}
/* Reconfigure static routes as kernel may remove some routes when lease expires. */
r = link_set_routes(link);
if (r < 0)
return r;
static int dhcp4_after_address_configure(Request *req, void *object) {
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(address);
link = req->link;
if (!address_equal(link->dhcp_address, address)) {
if (link->dhcp_address_old &&
!address_equal(link->dhcp_address_old, link->dhcp_address)) {
/* Still too old address exists? Let's remove it immediately. */
r = address_remove(link->dhcp_address_old, link, NULL);
if (r < 0)
return r;
}
link->dhcp_address_old = link->dhcp_address;
}
link->dhcp_address = address;
r = dhcp4_start_acd(link);
if (r < 0)
return log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCP4 address: %m");
return log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCPv4 address: %m");
dhcp4_check_ready(link);
return 0;
}
@ -969,36 +1010,30 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
int r;
assert(link);
assert(link->dhcp4_messages > 0);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
link->dhcp4_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv4 address");
if (r <= 0)
return r;
if (address_is_ready(link->dhcp_address)) {
r = dhcp4_address_ready_callback(link->dhcp_address);
if (r < 0) {
if (r < 0)
link_enter_failed(link);
return 1;
}
} else
link->dhcp_address->callback = dhcp4_address_ready_callback;
return 1;
}
static int dhcp4_update_address(Link *link, bool announce) {
static int dhcp4_request_address(Link *link, bool announce) {
_cleanup_(address_freep) Address *addr = NULL;
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
struct in_addr address, netmask;
unsigned prefixlen;
Address *ret;
Request *req;
int r;
assert(link);
@ -1007,15 +1042,6 @@ static int dhcp4_update_address(Link *link, bool announce) {
if (!link->dhcp_lease)
return 0;
link_set_state(link, LINK_STATE_CONFIGURING);
link->dhcp4_configured = false;
/* address_handler calls link_set_routes() and link_set_nexthop(). Before they are called, the
* related flags must be cleared. Otherwise, the link becomes configured state before routes
* are configured. */
link->static_routes_configured = false;
link->static_nexthops_configured = false;
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: no address: %m");
@ -1073,15 +1099,34 @@ static int dhcp4_update_address(Link *link, bool announce) {
SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
addr->route_metric = link->network->dhcp_route_metric;
/* allow reusing an existing address and simply update its lifetime
* in case it already exists */
r = address_configure(addr, link, dhcp4_address_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv4 address: %m");
if (address_get(link, addr, NULL) < 0)
link->dhcp4_configured = false;
if (!address_equal(link->dhcp_address, ret))
link->dhcp_address_old = link->dhcp_address;
link->dhcp_address = ret;
r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp4_messages,
dhcp4_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv4 address: %m");
req->after_configure = dhcp4_after_address_configure;
return 0;
}
static int dhcp4_request_address_and_routes(Link *link, bool announce) {
int r;
assert(link);
r = dhcp4_request_address(link, announce);
if (r < 0)
return r;
r = dhcp4_request_routes(link);
if (r < 0)
return r;
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
return 0;
}
@ -1101,7 +1146,7 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
link->dhcp_lease = sd_dhcp_lease_ref(lease);
link_dirty(link);
return dhcp4_update_address(link, false);
return dhcp4_request_address_and_routes(link, false);
}
static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
@ -1166,16 +1211,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
}
}
if (link->dhcp4_remove_messages == 0) {
r = dhcp4_update_address(link, true);
if (r < 0)
return r;
} else
log_link_debug(link,
"The link has previously assigned DHCPv4 address or routes. "
"The newly assigned address and routes will set up after old ones are removed.");
return 0;
return dhcp4_request_address_and_routes(link, true);
}
static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {

View File

@ -18,6 +18,7 @@
#include "networkd-dhcp6.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "networkd-radv.h"
#include "siphash24.h"
#include "string-table.h"
@ -43,7 +44,7 @@ bool link_dhcp6_pd_is_enabled(Link *link) {
static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
uint32_t lifetime_preferred, lifetime_valid;
union in_addr_union pd_prefix;
struct in6_addr pd_prefix;
uint8_t pd_prefix_len;
if (!lease)
@ -51,7 +52,7 @@ static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
return sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len, &lifetime_preferred, &lifetime_valid) >= 0;
return sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len, &lifetime_preferred, &lifetime_valid) >= 0;
}
DHCP6DelegatedPrefix *dhcp6_pd_free(DHCP6DelegatedPrefix *p) {
@ -86,21 +87,21 @@ static int dhcp6_pd_compare_func(const DHCP6DelegatedPrefix *a, const DHCP6Deleg
DEFINE_HASH_OPS(dhcp6_pd_hash_ops, DHCP6DelegatedPrefix, dhcp6_pd_hash_func, dhcp6_pd_compare_func);
static Link *dhcp6_pd_get_link_by_prefix(Link *link, const union in_addr_union *prefix) {
static Link *dhcp6_pd_get_link_by_prefix(Link *link, const struct in6_addr *prefix) {
DHCP6DelegatedPrefix *pd;
assert(link);
assert(link->manager);
assert(prefix);
pd = hashmap_get(link->manager->dhcp6_prefixes, &prefix->in6);
pd = hashmap_get(link->manager->dhcp6_prefixes, prefix);
if (!pd)
return NULL;
return pd->link;
}
static int dhcp6_pd_get_assigned_prefix(Link *link, const union in_addr_union *pd_prefix, union in_addr_union *ret_prefix) {
static int dhcp6_pd_get_assigned_prefix(Link *link, const struct in6_addr *pd_prefix, struct in6_addr *ret_prefix) {
DHCP6DelegatedPrefix *pd, in;
assert(link);
@ -109,7 +110,7 @@ static int dhcp6_pd_get_assigned_prefix(Link *link, const union in_addr_union *p
assert(ret_prefix);
in = (DHCP6DelegatedPrefix) {
.pd_prefix = pd_prefix->in6,
.pd_prefix = *pd_prefix,
.link = link,
};
@ -117,7 +118,7 @@ static int dhcp6_pd_get_assigned_prefix(Link *link, const union in_addr_union *p
if (!pd)
return -ENOENT;
ret_prefix->in6 = pd->prefix;
*ret_prefix = pd->prefix;
return 0;
}
@ -229,7 +230,7 @@ int dhcp6_pd_remove(Link *link) {
return r;
}
static int dhcp6_pd_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
static int dhcp6_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
@ -237,15 +238,9 @@ static int dhcp6_pd_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *l
link->dhcp6_pd_route_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Failed to add DHCPv6 Prefix Delegation route");
link_enter_failed(link);
return 1;
}
r = route_configure_handler_internal(rtnl, m, link, "Failed to add DHCPv6 Prefix Delegation route");
if (r <= 0)
return r;
if (link->dhcp6_pd_route_messages == 0) {
log_link_debug(link, "DHCPv6 prefix delegation routes set");
@ -264,11 +259,32 @@ static int dhcp6_pd_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *l
return 1;
}
static int dhcp6_set_pd_route(Link *link, const union in_addr_union *prefix, const union in_addr_union *pd_prefix) {
static int dhcp6_pd_after_route_configure(Request *req, void *object) {
Route *route = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ROUTE);
assert(route);
link = req->link;
r = set_ensure_put(&link->dhcp6_pd_routes, &route_hash_ops, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 prefix route: %m");
set_remove(link->dhcp6_pd_routes_old, route);
return 0;
}
static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, const struct in6_addr *pd_prefix) {
_cleanup_(dhcp6_pd_freep) DHCP6DelegatedPrefix *pd = NULL;
_cleanup_(route_freep) Route *route = NULL;
Link *assigned_link;
Route *ret;
Request *req;
int r;
assert(link);
@ -281,24 +297,23 @@ static int dhcp6_set_pd_route(Link *link, const union in_addr_union *prefix, con
return r;
route->family = AF_INET6;
route->dst = *prefix;
route->dst.in6 = *prefix;
route->dst_prefixlen = 64;
route->protocol = RTPROT_DHCP;
route->priority = link->network->dhcp6_pd_route_metric;
r = route_configure(route, link, dhcp6_pd_route_handler, &ret);
r = link_has_route(link, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv6 prefix route: %m");
if (r > 0)
return r;
if (r == 0)
link->dhcp6_pd_route_configured = false;
link->dhcp6_pd_route_messages++;
r = set_ensure_put(&link->dhcp6_pd_routes, &route_hash_ops, ret);
r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp6_pd_route_messages,
dhcp6_pd_route_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 prefix route: %m");
return log_link_error_errno(link, r, "Failed to request DHCPv6 prefix route: %m");
(void) set_remove(link->dhcp6_pd_routes_old, ret);
req->after_configure = dhcp6_pd_after_route_configure;
assigned_link = dhcp6_pd_get_link_by_prefix(link, prefix);
if (assigned_link) {
@ -311,8 +326,8 @@ static int dhcp6_set_pd_route(Link *link, const union in_addr_union *prefix, con
return log_oom();
*pd = (DHCP6DelegatedPrefix) {
.prefix = prefix->in6,
.pd_prefix = pd_prefix->in6,
.prefix = *prefix,
.pd_prefix = *pd_prefix,
.link = link_ref(link),
};
@ -338,16 +353,9 @@ static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin
link->dhcp6_pd_address_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set DHCPv6 delegated prefix address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv6 delegated prefix address");
if (r <= 0)
return r;
if (link->dhcp6_pd_address_messages == 0) {
log_link_debug(link, "DHCPv6 delegated prefix addresses set");
@ -370,12 +378,15 @@ static void log_dhcp6_pd_address(Link *link, const Address *address) {
_cleanup_free_ char *buffer = NULL;
int log_level;
assert(address);
assert(address->family == AF_INET6);
log_level = address_get(link, address, NULL) >= 0 ? LOG_DEBUG : LOG_INFO;
if (log_level < log_get_max_level())
return;
(void) in_addr_prefix_to_string(address->family, &address->in_addr, address->prefixlen, &buffer);
(void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buffer);
if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
address->cinfo.ifa_valid * USEC_PER_SEC,
@ -391,14 +402,35 @@ static void log_dhcp6_pd_address(Link *link, const Address *address) {
preferred_str ? "for " : "forever", strempty(preferred_str));
}
static int dhcp6_set_pd_address(
static int dhcp6_pd_after_address_configure(Request *req, void *object) {
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(address);
link = req->link;
r = set_ensure_put(&link->dhcp6_pd_addresses, &address_hash_ops, address);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 delegated prefix address: %m");
set_remove(link->dhcp6_pd_addresses_old, address);
return 0;
}
static int dhcp6_pd_request_address(
Link *link,
const union in_addr_union *prefix,
const struct in6_addr *prefix,
uint32_t lifetime_preferred,
uint32_t lifetime_valid) {
_cleanup_(address_freep) Address *address = NULL;
Address *ret;
Request *req;
int r;
assert(link);
@ -412,10 +444,10 @@ static int dhcp6_set_pd_address(
if (r < 0)
return log_link_error_errno(link, r, "Failed to allocate address for DHCPv6 delegated prefix: %m");
address->in_addr = *prefix;
address->in_addr.in6 = *prefix;
if (in_addr_is_set(AF_INET6, &link->network->dhcp6_pd_token))
memcpy(address->in_addr.in6.s6_addr + 8, link->network->dhcp6_pd_token.in6.s6_addr + 8, 8);
if (in6_addr_is_set(&link->network->dhcp6_pd_token))
memcpy(address->in_addr.in6.s6_addr + 8, link->network->dhcp6_pd_token.s6_addr + 8, 8);
else {
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0)
@ -430,27 +462,24 @@ static int dhcp6_set_pd_address(
address->route_metric = link->network->dhcp6_pd_route_metric;
log_dhcp6_pd_address(link, address);
r = address_configure(address, link, dhcp6_pd_address_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv6 delegated prefix address: %m");
if (r > 0)
if (address_get(link, address, NULL) < 0)
link->dhcp6_pd_address_configured = false;
link->dhcp6_pd_address_messages++;
r = set_ensure_put(&link->dhcp6_pd_addresses, &address_hash_ops, ret);
r = link_request_address(link, TAKE_PTR(address), true, &link->dhcp6_pd_address_messages,
dhcp6_pd_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 delegated prefix address: %m");
return log_link_error_errno(link, r, "Failed to request DHCPv6 delegated prefix address: %m");
(void) set_remove(link->dhcp6_pd_addresses_old, ret);
req->after_configure = dhcp6_pd_after_address_configure;
return 0;
}
static int dhcp6_pd_assign_prefix(
Link *link,
const union in_addr_union *prefix,
const union in_addr_union *pd_prefix,
const struct in6_addr *prefix,
const struct in6_addr *pd_prefix,
uint32_t lifetime_preferred,
uint32_t lifetime_valid) {
@ -461,16 +490,16 @@ static int dhcp6_pd_assign_prefix(
assert(prefix);
if (link->network->dhcp6_pd_announce) {
r = radv_add_prefix(link, &prefix->in6, 64, lifetime_preferred, lifetime_valid);
r = radv_add_prefix(link, prefix, 64, lifetime_preferred, lifetime_valid);
if (r < 0)
return r;
}
r = dhcp6_set_pd_route(link, prefix, pd_prefix);
r = dhcp6_pd_request_route(link, prefix, pd_prefix);
if (r < 0)
return r;
r = dhcp6_set_pd_address(link, prefix, lifetime_preferred, lifetime_valid);
r = dhcp6_pd_request_address(link, prefix, lifetime_preferred, lifetime_valid);
if (r < 0)
return r;
@ -486,9 +515,9 @@ static bool link_has_preferred_subnet_id(Link *link) {
static int dhcp6_get_preferred_delegated_prefix(
Link *link,
const union in_addr_union *masked_pd_prefix,
const struct in6_addr *masked_pd_prefix,
uint8_t pd_prefix_len,
union in_addr_union *ret) {
struct in6_addr *ret) {
/* We start off with the original PD prefix we have been assigned and iterate from there */
union in_addr_union prefix;
@ -502,7 +531,7 @@ static int dhcp6_get_preferred_delegated_prefix(
assert(pd_prefix_len <= 64);
n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
prefix = *masked_pd_prefix;
prefix.in6 = *masked_pd_prefix;
if (link_has_preferred_subnet_id(link)) {
uint64_t subnet_id = link->network->dhcp6_pd_subnet_id;
@ -521,28 +550,28 @@ static int dhcp6_get_preferred_delegated_prefix(
/* Verify that the prefix we did calculate fits in the pd prefix.
* This should not fail as we checked the prefix size beforehand */
assert_se(in_addr_prefix_covers(AF_INET6, masked_pd_prefix, pd_prefix_len, &prefix) > 0);
assert_se(in_addr_prefix_covers(AF_INET6, (const union in_addr_union*) masked_pd_prefix, pd_prefix_len, &prefix) > 0);
assigned_link = dhcp6_pd_get_link_by_prefix(link, &prefix);
assigned_link = dhcp6_pd_get_link_by_prefix(link, &prefix.in6);
if (assigned_link && assigned_link != link) {
_cleanup_free_ char *assigned_buf = NULL;
(void) in_addr_to_string(AF_INET6, &prefix, &assigned_buf);
(void) in6_addr_to_string(&prefix.in6, &assigned_buf);
return log_link_warning_errno(link, SYNTHETIC_ERRNO(EAGAIN),
"The requested prefix %s is already assigned to another link.",
strna(assigned_buf));
}
*ret = prefix;
*ret = prefix.in6;
return 0;
}
for (uint64_t n = 0; n < n_prefixes; n++) {
/* If we do not have an allocation preference just iterate
* through the address space and return the first free prefix. */
assigned_link = dhcp6_pd_get_link_by_prefix(link, &prefix);
assigned_link = dhcp6_pd_get_link_by_prefix(link, &prefix.in6);
if (!assigned_link || assigned_link == link) {
*ret = prefix;
*ret = prefix.in6;
return 0;
}
@ -555,7 +584,7 @@ static int dhcp6_get_preferred_delegated_prefix(
}
static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
const union in_addr_union *masked_pd_prefix,
const struct in6_addr *masked_pd_prefix,
uint8_t pd_prefix_len,
uint32_t lifetime_preferred,
uint32_t lifetime_valid,
@ -571,7 +600,7 @@ static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
HASHMAP_FOREACH(link, dhcp6_link->manager->links) {
_cleanup_free_ char *assigned_buf = NULL;
union in_addr_union assigned_prefix;
struct in6_addr assigned_prefix;
if (link == dhcp6_link)
continue;
@ -594,7 +623,7 @@ static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
}
}
(void) in_addr_to_string(AF_INET6, &assigned_prefix, &assigned_buf);
(void) in6_addr_to_string(&assigned_prefix, &assigned_buf);
r = dhcp6_pd_assign_prefix(link, &assigned_prefix, masked_pd_prefix,
lifetime_preferred, lifetime_valid);
if (r < 0) {
@ -659,11 +688,10 @@ static int dhcp6_pd_finalize(Link *link) {
if (r < 0)
return r;
if (link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured)
link_check_ready(link);
else
if (!link->dhcp6_pd_address_configured || !link->dhcp6_pd_route_configured)
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
return 0;
}
@ -781,7 +809,7 @@ static int dhcp6_remove(Link *link) {
return r;
}
static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
static int dhcp6_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
@ -789,15 +817,9 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link
link->dhcp6_route_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Failed to add unreachable route for DHCPv6 delegated subnet");
link_enter_failed(link);
return 1;
}
r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv6 delegated subnet");
if (r <= 0)
return r;
if (link->dhcp6_route_messages == 0) {
log_link_debug(link, "Unreachable routes for DHCPv6 delegated subnets set");
@ -815,16 +837,37 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link
return 1;
}
static int dhcp6_set_unreachable_route(Link *link, const union in_addr_union *addr, uint8_t prefixlen) {
static int dhcp6_after_route_configure(Request *req, void *object) {
Route *route = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ROUTE);
assert(route);
link = req->link;
r = set_ensure_put(&link->dhcp6_routes, &route_hash_ops, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store unreachable route for DHCPv6 delegated subnet: %m");
set_remove(link->dhcp6_routes_old, route);
return 0;
}
static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *addr, uint8_t prefixlen) {
_cleanup_(route_freep) Route *route = NULL;
_cleanup_free_ char *buf = NULL;
Route *ret;
Request *req;
int r;
assert(link);
assert(addr);
(void) in_addr_prefix_to_string(AF_INET6, addr, prefixlen, &buf);
(void) in6_addr_prefix_to_string(addr, prefixlen, &buf);
if (prefixlen == 64) {
log_link_debug(link, "Not adding a blocking route for DHCPv6 delegated subnet %s since distributed prefix is 64",
@ -837,32 +880,30 @@ static int dhcp6_set_unreachable_route(Link *link, const union in_addr_union *ad
return log_oom();
route->family = AF_INET6;
route->dst = *addr;
route->dst.in6 = *addr;
route->dst_prefixlen = prefixlen;
route->table = link_get_dhcp_route_table(link);
route->type = RTN_UNREACHABLE;
route->protocol = RTPROT_DHCP;
r = route_configure(route, link, dhcp6_route_handler, &ret);
r = link_has_route(link, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set unreachable route for DHCPv6 delegated subnet %s: %m",
strna(buf));
if (r > 0)
return r;
if (r == 0)
link->dhcp6_route_configured = false;
link->dhcp6_route_messages++;
r = set_ensure_put(&link->dhcp6_routes, &route_hash_ops, ret);
r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp6_route_messages,
dhcp6_route_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store unreachable route for DHCPv6 delegated subnet %s: %m",
return log_link_error_errno(link, r, "Failed to request unreachable route for DHCPv6 delegated subnet %s: %m",
strna(buf));
(void) set_remove(link->dhcp6_routes_old, ret);
req->after_configure = dhcp6_after_route_configure;
return 0;
}
static int dhcp6_pd_prefix_add(Link *link, const union in_addr_union *prefix, uint8_t prefixlen) {
static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_t prefixlen) {
_cleanup_free_ struct in_addr_prefix *p = NULL;
_cleanup_free_ char *buf = NULL;
int r;
@ -877,10 +918,10 @@ static int dhcp6_pd_prefix_add(Link *link, const union in_addr_union *prefix, ui
*p = (struct in_addr_prefix) {
.family = AF_INET6,
.prefixlen = prefixlen,
.address = *prefix,
.address.in6 = *prefix,
};
(void) in_addr_prefix_to_string(p->family, &p->address, p->prefixlen, &buf);
(void) in6_addr_prefix_to_string(prefix, prefixlen, &buf);
log_link_full(link,
set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG :
@ -918,10 +959,11 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
for (sd_dhcp6_lease_reset_pd_prefix_iter(dhcp6_link->dhcp6_lease);;) {
uint32_t lifetime_preferred, lifetime_valid;
union in_addr_union pd_prefix, prefix;
struct in6_addr pd_prefix;
union in_addr_union prefix;
uint8_t pd_prefix_len;
r = sd_dhcp6_lease_get_pd(dhcp6_link->dhcp6_lease, &pd_prefix.in6, &pd_prefix_len,
r = sd_dhcp6_lease_get_pd(dhcp6_link->dhcp6_lease, &pd_prefix, &pd_prefix_len,
&lifetime_preferred, &lifetime_valid);
if (r < 0)
break;
@ -932,7 +974,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
if (r == 0)
continue;
r = dhcp6_set_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len);
r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len);
if (r < 0)
return r;
@ -947,7 +989,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
assert(pd_prefix_len <= 64);
prefix = pd_prefix;
prefix.in6 = pd_prefix;
r = in_addr_mask(AF_INET6, &prefix, pd_prefix_len);
if (r < 0)
return log_link_error_errno(dhcp6_link, r, "Failed to mask DHCPv6 PD prefix: %m");
@ -956,20 +998,20 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
uint64_t n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
_cleanup_free_ char *buf = NULL;
(void) in_addr_prefix_to_string(AF_INET6, &prefix, pd_prefix_len, &buf);
(void) in6_addr_prefix_to_string(&prefix.in6, pd_prefix_len, &buf);
log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s",
n_prefixes, strna(buf));
}
dhcp6_pd_prefix_distribute(dhcp6_link,
&prefix,
&prefix.in6,
pd_prefix_len,
lifetime_preferred,
lifetime_valid,
true);
dhcp6_pd_prefix_distribute(dhcp6_link,
&prefix,
&prefix.in6,
pd_prefix_len,
lifetime_preferred,
lifetime_valid,
@ -996,16 +1038,9 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
link->dhcp6_address_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set DHCPv6 address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv6 address");
if (r <= 0)
return r;
if (link->dhcp6_address_messages == 0) {
log_link_debug(link, "DHCPv6 addresses set");
@ -1032,8 +1067,9 @@ static void log_dhcp6_address(Link *link, const Address *address, char **ret) {
assert(link);
assert(address);
assert(address->family == AF_INET6);
(void) in_addr_prefix_to_string(address->family, &address->in_addr, address->prefixlen, &buffer);
(void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buffer);
if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
address->cinfo.ifa_valid * USEC_PER_SEC,
@ -1085,7 +1121,28 @@ finalize:
*ret = TAKE_PTR(buffer);
}
static int dhcp6_update_address(
static int dhcp6_after_address_configure(Request *req, void *object) {
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(address);
link = req->link;
r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, address);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 address: %m");
set_remove(link->dhcp6_addresses_old, address);
return 0;
}
static int dhcp6_request_address(
Link *link,
const struct in6_addr *ip6_addr,
uint32_t lifetime_preferred,
@ -1093,7 +1150,7 @@ static int dhcp6_update_address(
_cleanup_(address_freep) Address *addr = NULL;
_cleanup_free_ char *buffer = NULL;
Address *ret;
Request *req;
int r;
r = address_new(&addr);
@ -1109,19 +1166,15 @@ static int dhcp6_update_address(
log_dhcp6_address(link, addr, &buffer);
r = address_configure(addr, link, dhcp6_address_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv6 address %s: %m", strna(buffer));
if (r > 0)
if (address_get(link, addr, NULL) < 0)
link->dhcp6_address_configured = false;
link->dhcp6_address_messages++;
r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, ret);
r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp6_address_messages,
dhcp6_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 address %s: %m", strna(buffer));
return log_link_error_errno(link, r, "Failed to request DHCPv6 address %s: %m", strna(buffer));
(void) set_remove(link->dhcp6_addresses_old, ret);
req->after_configure = dhcp6_after_address_configure;
return 0;
}
@ -1144,7 +1197,7 @@ static int dhcp6_address_acquired(Link *link) {
if (r < 0)
break;
r = dhcp6_update_address(link, &ip6_addr, lifetime_preferred, lifetime_valid);
r = dhcp6_request_address(link, &ip6_addr, lifetime_preferred, lifetime_valid);
if (r < 0)
return r;
}
@ -1224,11 +1277,10 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
if (r < 0)
return r;
if (link->dhcp6_address_configured && link->dhcp6_route_configured)
link_check_ready(link);
else
if (!link->dhcp6_address_configured || !link->dhcp6_route_configured)
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
return 0;
}
@ -1298,7 +1350,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
}
}
int dhcp6_request_address(Link *link, int ir) {
int dhcp6_request_information(Link *link, int ir) {
int r, inf_req, pd;
bool running;
@ -1376,7 +1428,7 @@ int dhcp6_start(Link *link) {
log_link_debug(link, "Acquiring DHCPv6 lease");
return dhcp6_request_address(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
return dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
}
int dhcp6_request_prefix_delegation(Link *link) {
@ -1849,7 +1901,8 @@ int config_parse_dhcp6_pd_token(
void *data,
void *userdata) {
union in_addr_union *addr = data, tmp;
struct in6_addr *addr = data;
union in_addr_union tmp;
int r;
assert(filename);
@ -1858,7 +1911,7 @@ int config_parse_dhcp6_pd_token(
assert(data);
if (isempty(rvalue)) {
*addr = IN_ADDR_NULL;
*addr = (struct in6_addr) {};
return 0;
}
@ -1875,7 +1928,7 @@ int config_parse_dhcp6_pd_token(
return 0;
}
*addr = tmp;
*addr = tmp.in6;
return 0;
}

View File

@ -32,7 +32,7 @@ int dhcp6_pd_remove(Link *link);
int dhcp6_configure(Link *link);
int dhcp6_update_mac(Link *link);
int dhcp6_start(Link *link);
int dhcp6_request_address(Link *link, int ir);
int dhcp6_request_information(Link *link, int ir);
int dhcp6_request_prefix_delegation(Link *link);
int link_serialize_dhcp6_client(Link *link, FILE *f);

View File

@ -8,39 +8,55 @@
#include "networkd-ipv4ll.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "parse-util.h"
static int address_new_from_ipv4ll(Link *link, Address **ret) {
_cleanup_(address_freep) Address *address = NULL;
struct in_addr addr;
int r;
assert(link);
assert(link->ipv4ll);
assert(ret);
r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
if (r < 0)
return r;
r = address_new(&address);
if (r < 0)
return -ENOMEM;
address->family = AF_INET;
address->in_addr.in = addr;
address->prefixlen = 16;
address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(UINT32_C(0xffffffff) >> address->prefixlen);
address->scope = RT_SCOPE_LINK;
address->route_metric = IPV4LL_ROUTE_METRIC;
*ret = TAKE_PTR(address);
return 0;
}
static int ipv4ll_address_lost(Link *link) {
_cleanup_(address_freep) Address *address = NULL;
struct in_addr addr;
int r;
assert(link);
link->ipv4ll_address_configured = false;
r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
if (r < 0)
r = address_new_from_ipv4ll(link, &address);
if (r == -ENOENT)
return 0;
log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(addr));
r = address_new(&address);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate address: %m");
address->family = AF_INET;
address->in_addr.in = addr;
address->prefixlen = 16;
address->scope = RT_SCOPE_LINK;
r = address_remove(address, link, NULL);
if (r < 0)
return r;
link_check_ready(link);
log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return 0;
return address_remove(address, link, NULL);
}
static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@ -49,13 +65,9 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
assert(link);
assert(!link->ipv4ll_address_configured);
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "could not set ipv4ll address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
r = address_configure_handler_internal(rtnl, m, link, "Could not set ipv4ll address");
if (r <= 0)
return r;
link->ipv4ll_address_configured = true;
link_check_ready(link);
@ -64,8 +76,7 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
}
static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
_cleanup_(address_freep) Address *ll_addr = NULL;
struct in_addr address;
_cleanup_(address_freep) Address *address = NULL;
int r;
assert(ll);
@ -73,31 +84,16 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
link->ipv4ll_address_configured = false;
r = sd_ipv4ll_get_address(ll, &address);
r = address_new_from_ipv4ll(link, &address);
if (r == -ENOENT)
return 0;
else if (r < 0)
if (r < 0)
return r;
log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address));
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
r = address_new(&ll_addr);
if (r < 0)
return r;
ll_addr->family = AF_INET;
ll_addr->in_addr.in = address;
ll_addr->prefixlen = 16;
ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
ll_addr->scope = RT_SCOPE_LINK;
ll_addr->route_metric = IPV4LL_ROUTE_METRIC;
r = address_configure(ll_addr, link, ipv4ll_address_handler, NULL);
if (r < 0)
return r;
return 0;
return link_request_address(link, TAKE_PTR(address), true, NULL, ipv4ll_address_handler, NULL);
}
static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {

View File

@ -33,6 +33,7 @@
#include "networkd-dhcp6.h"
#include "networkd-fdb.h"
#include "networkd-ipv4ll.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-link-bus.h"
#include "networkd-link.h"
#include "networkd-lldp-tx.h"
@ -41,11 +42,12 @@
#include "networkd-ndisc.h"
#include "networkd-neighbor.h"
#include "networkd-nexthop.h"
#include "networkd-sriov.h"
#include "networkd-sysctl.h"
#include "networkd-queue.h"
#include "networkd-radv.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-sriov.h"
#include "networkd-state-file.h"
#include "networkd-sysctl.h"
#include "networkd-wifi.h"
#include "set.h"
#include "socket-util.h"
@ -133,6 +135,25 @@ bool link_ipv6_enabled(Link *link) {
return false;
}
bool link_is_ready_to_configure(Link *link, bool allow_unmanaged) {
assert(link);
if (!link->network || link->network->unmanaged) {
if (!allow_unmanaged)
return false;
return link_has_carrier(link);
}
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
return false;
return true;
}
static bool link_is_enslaved(Link *link) {
if (link->flags & IFF_SLAVE)
/* Even if the link is not managed by networkd, honor IFF_SLAVE flag. */
@ -773,12 +794,9 @@ void link_check_ready(Link *link) {
return;
}
if (!link->addresses_configured)
if (!link->static_addresses_configured)
return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__);
if (!link->neighbors_configured)
return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
SET_FOREACH(a, link->addresses)
if (!address_is_ready(a)) {
_cleanup_free_ char *str = NULL;
@ -787,13 +805,16 @@ void link_check_ready(Link *link) {
return (void) log_link_debug(link, "%s(): an address %s is not ready.", __func__, strna(str));
}
if (!link->static_routes_configured)
return (void) log_link_debug(link, "%s(): static routes are not configured.", __func__);
if (!link->static_neighbors_configured)
return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
if (!link->static_nexthops_configured)
return (void) log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
if (!link->routing_policy_rules_configured)
if (!link->static_routes_configured)
return (void) log_link_debug(link, "%s(): static routes are not configured.", __func__);
if (!link->static_routing_policy_rules_configured)
return (void) log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
if (!link->tc_configured)
@ -857,15 +878,6 @@ static int link_set_static_configs(Link *link) {
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
/* Reset all *_configured flags we are configuring. */
link->request_static_addresses = false;
link->addresses_configured = false;
link->addresses_ready = false;
link->neighbors_configured = false;
link->static_routes_configured = false;
link->static_nexthops_configured = false;
link->routing_policy_rules_configured = false;
r = link_set_bridge_fdb(link);
if (r < 0)
return r;
@ -874,11 +886,7 @@ static int link_set_static_configs(Link *link) {
if (r < 0)
return r;
r = link_set_neighbors(link);
if (r < 0)
return r;
r = link_set_addresses(link);
r = link_set_ipv6_proxy_ndp_addresses(link);
if (r < 0)
return r;
@ -886,8 +894,23 @@ static int link_set_static_configs(Link *link) {
if (r < 0)
return r;
/* now that we can figure out a default address for the dhcp server, start it */
r = dhcp4_server_configure(link);
r = link_request_static_addresses(link);
if (r < 0)
return r;
r = link_request_static_neighbors(link);
if (r < 0)
return r;
r = link_request_static_nexthops(link, false);
if (r < 0)
return r;
r = link_request_static_routes(link, false);
if (r < 0)
return r;
r = link_request_static_routing_policy_rules(link);
if (r < 0)
return r;
@ -2028,20 +2051,20 @@ static int link_drop_foreign_config(Link *link) {
assert(link);
assert(link->manager);
r = link_drop_foreign_addresses(link);
k = link_drop_foreign_neighbors(link);
if (k < 0 && r >= 0)
r = k;
k = link_drop_foreign_routes(link);
if (k < 0 && r >= 0)
r = k;
r = link_drop_foreign_routes(link);
k = link_drop_foreign_nexthops(link);
if (k < 0 && r >= 0)
r = k;
k = link_drop_foreign_addresses(link);
if (k < 0 && r >= 0)
r = k;
k = link_drop_foreign_neighbors(link);
if (k < 0 && r >= 0)
r = k;
k = manager_drop_foreign_routing_policy_rules(link->manager);
if (k < 0 && r >= 0)
r = k;
@ -2055,20 +2078,20 @@ static int link_drop_config(Link *link) {
assert(link);
assert(link->manager);
r = link_drop_addresses(link);
k = link_drop_neighbors(link);
if (k < 0 && r >= 0)
r = k;
k = link_drop_routes(link);
if (k < 0 && r >= 0)
r = k;
r = link_drop_routes(link);
k = link_drop_nexthops(link);
if (k < 0 && r >= 0)
r = k;
k = link_drop_addresses(link);
if (k < 0 && r >= 0)
r = k;
k = link_drop_neighbors(link);
if (k < 0 && r >= 0)
r = k;
k = manager_drop_routing_policy_rules(link->manager, link);
if (k < 0 && r >= 0)
r = k;
@ -2078,6 +2101,17 @@ static int link_drop_config(Link *link) {
return r;
}
static void link_drop_requests(Link *link) {
Request *req;
assert(link);
assert(link->manager);
ORDERED_SET_FOREACH(req, link->manager->request_queue)
if (req->link == link)
request_drop(req);
}
int link_configure(Link *link) {
int r;
@ -2232,6 +2266,8 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
if (r < 0)
return r;
link_drop_requests(link);
r = link_drop_config(link);
if (r < 0)
return r;
@ -2664,6 +2700,8 @@ static int link_carrier_lost(Link *link) {
return r;
}
link_drop_requests(link);
r = link_drop_config(link);
if (r < 0)
return r;

View File

@ -78,13 +78,16 @@ typedef struct Link {
LinkAddressState ipv4_address_state;
LinkAddressState ipv6_address_state;
unsigned address_messages;
unsigned address_remove_messages;
unsigned address_label_messages;
unsigned neighbor_messages;
unsigned route_messages;
unsigned nexthop_messages;
unsigned routing_policy_rule_messages;
unsigned static_address_messages;
unsigned static_neighbor_messages;
unsigned static_nexthop_messages;
unsigned static_route_messages;
unsigned static_routing_policy_rule_messages;
unsigned address_remove_messages;
unsigned neighbor_remove_messages;
unsigned nexthop_remove_messages;
unsigned route_remove_messages;
unsigned tc_messages;
unsigned sr_iov_messages;
unsigned enslaving;
@ -118,13 +121,11 @@ typedef struct Link {
sd_ipv4ll *ipv4ll;
bool ipv4ll_address_configured:1;
bool request_static_addresses:1;
bool addresses_configured:1;
bool addresses_ready:1;
bool neighbors_configured:1;
bool static_routes_configured:1;
bool static_addresses_configured:1;
bool static_neighbors_configured:1;
bool static_nexthops_configured:1;
bool routing_policy_rules_configured:1;
bool static_routes_configured:1;
bool static_routing_policy_rules_configured:1;
bool tc_configured:1;
bool sr_iov_configured:1;
bool setting_mtu:1;
@ -199,6 +200,8 @@ typedef struct Link {
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
bool link_is_ready_to_configure(Link *link, bool allow_unmanaged);
void link_ntp_settings_clear(Link *link);
void link_dns_settings_clear(Link *link);
Link *link_unref(Link *link);

View File

@ -34,6 +34,7 @@
#include "networkd-neighbor.h"
#include "networkd-network-bus.h"
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-speed-meter.h"
#include "networkd-state-file.h"
@ -406,6 +407,10 @@ int manager_new(Manager **ret) {
if (r < 0)
return r;
r = sd_event_add_post(m->event, NULL, manager_process_requests, m);
if (r < 0)
return r;
r = manager_connect_rtnl(m);
if (r < 0)
return r;
@ -446,6 +451,8 @@ Manager* manager_free(Manager *m) {
HASHMAP_FOREACH(link, m->links)
(void) link_stop_engines(link, true);
m->request_queue = ordered_set_free_with_destructor(m->request_queue, request_free);
m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);

View File

@ -62,6 +62,7 @@ struct Manager {
char* dynamic_hostname;
char* dynamic_timezone;
unsigned routing_policy_rule_remove_messages;
Set *rules;
Set *rules_foreign;
@ -69,10 +70,12 @@ struct Manager {
Hashmap *nexthops_by_id;
/* Manager stores nexthops without RTA_OIF attribute. */
unsigned nexthop_remove_messages;
Set *nexthops;
Set *nexthops_foreign;
/* Manager stores routes without RTA_OIF attribute. */
unsigned route_remove_messages;
Set *routes;
Set *routes_foreign;
@ -91,6 +94,8 @@ struct Manager {
bool bridge_mdb_on_master_not_supported;
FirewallContext *fw_ctx;
OrderedSet *request_queue;
};
int manager_new(Manager **ret);

View File

@ -15,6 +15,7 @@
#include "networkd-dhcp6.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-queue.h"
#include "networkd-state-file.h"
#include "string-table.h"
#include "string-util.h"
@ -89,6 +90,7 @@ static int ndisc_address_callback(Address *address) {
assert(address);
assert(address->link);
assert(address->family == AF_INET6);
SET_FOREACH(n, address->link->ndisc_addresses)
if (n->address == address) {
@ -99,7 +101,7 @@ static int ndisc_address_callback(Address *address) {
if (in6_addr_is_null(&router)) {
_cleanup_free_ char *buf = NULL;
(void) in_addr_prefix_to_string(address->family, &address->in_addr, address->prefixlen, &buf);
(void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buf);
log_link_debug(address->link, "%s is called for %s, but it is already removed, ignoring.",
__func__, strna(buf));
return 0;
@ -107,7 +109,7 @@ static int ndisc_address_callback(Address *address) {
/* Make this called only once */
SET_FOREACH(n, address->link->ndisc_addresses)
if (IN6_ARE_ADDR_EQUAL(&n->router, &router))
if (in6_addr_equal(&n->router, &router))
n->address->callback = NULL;
return ndisc_remove_old_one(address->link, &router, true);
@ -131,7 +133,7 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
return 0;
SET_FOREACH(na, link->ndisc_addresses)
if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
if (!na->marked && in6_addr_equal(&na->router, router)) {
set_callback = true;
break;
}
@ -145,13 +147,13 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
if (set_callback) {
SET_FOREACH(na, link->ndisc_addresses)
if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router))
if (!na->marked && in6_addr_equal(&na->router, router))
na->address->callback = ndisc_address_callback;
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
(void) in_addr_to_string(AF_INET6, (const union in_addr_union*) router, &buf);
(void) in6_addr_to_string(router, &buf);
log_link_debug(link, "No SLAAC address obtained from %s is ready. "
"The old NDisc information will be removed later.",
strna(buf));
@ -163,32 +165,32 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
(void) in_addr_to_string(AF_INET6, (const union in_addr_union*) router, &buf);
(void) in6_addr_to_string(router, &buf);
log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
}
SET_FOREACH(na, link->ndisc_addresses)
if (na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
if (na->marked && in6_addr_equal(&na->router, router)) {
k = address_remove(na->address, link, NULL);
if (k < 0)
r = k;
}
SET_FOREACH(nr, link->ndisc_routes)
if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
if (nr->marked && in6_addr_equal(&nr->router, router)) {
k = route_remove(nr->route, NULL, link, NULL);
if (k < 0)
r = k;
}
SET_FOREACH(rdnss, link->ndisc_rdnss)
if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router)) {
if (rdnss->marked && in6_addr_equal(&rdnss->router, router)) {
free(set_remove(link->ndisc_rdnss, rdnss));
updated = true;
}
SET_FOREACH(dnssl, link->ndisc_dnssl)
if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router)) {
if (dnssl->marked && in6_addr_equal(&dnssl->router, router)) {
free(set_remove(link->ndisc_dnssl, dnssl));
updated = true;
}
@ -304,15 +306,9 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
link->ndisc_routes_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_error_errno(link, m, r, "Could not set NDisc route");
link_enter_failed(link);
return 1;
}
r = route_configure_handler_internal(rtnl, m, link, "Could not set NDisc route");
if (r <= 0)
return r;
if (link->ndisc_routes_messages == 0) {
log_link_debug(link, "NDisc routes set.");
@ -330,24 +326,23 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1;
}
static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt) {
static int ndisc_after_route_configure(Request *req, void *object) {
_cleanup_free_ NDiscRoute *nr = NULL;
NDiscRoute *nr_exist;
struct in6_addr router;
Route *ret;
Route *route = object;
sd_ndisc_router *rt;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ROUTE);
assert(req->userdata);
assert(route);
assert(link);
assert(rt);
r = route_configure(route, link, ndisc_route_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
if (r > 0)
link->ndisc_routes_configured = false;
link->ndisc_routes_messages++;
link = req->link;
rt = req->userdata;
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
@ -359,7 +354,7 @@ static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt)
*nr = (NDiscRoute) {
.router = router,
.route = ret,
.route = route,
};
nr_exist = set_get(link->ndisc_routes, nr);
@ -378,6 +373,39 @@ static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt)
return 0;
}
static void ndisc_request_on_free(Request *req) {
assert(req);
sd_ndisc_router_unref(req->userdata);
}
static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = in;
Request *req;
int r;
assert(route);
assert(link);
assert(rt);
r = link_has_route(link, route);
if (r < 0)
return r;
if (r == 0)
link->ndisc_routes_configured = false;
r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_routes_messages,
ndisc_route_handler, &req);
if (r < 0)
return r;
req->userdata = sd_ndisc_router_ref(rt);
req->after_configure = ndisc_after_route_configure;
req->on_free = ndisc_request_on_free;
return 0;
}
static void ndisc_address_hash_func(const NDiscAddress *x, struct siphash *state) {
address_hash_func(x->address, state);
}
@ -401,16 +429,9 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
link->ndisc_addresses_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_error_errno(link, m, r, "Could not set NDisc address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
if (r <= 0)
return r;
if (link->ndisc_addresses_messages == 0) {
log_link_debug(link, "NDisc SLAAC addresses set.");
@ -426,24 +447,23 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1;
}
static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router *rt) {
static int ndisc_after_address_configure(Request *req, void *object) {
_cleanup_free_ NDiscAddress *na = NULL;
NDiscAddress *na_exist;
struct in6_addr router;
Address *ret;
sd_ndisc_router *rt;
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(req->userdata);
assert(address);
assert(link);
assert(rt);
r = address_configure(address, link, ndisc_address_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set NDisc SLAAC address: %m");
if (r > 0)
link->ndisc_addresses_configured = false;
link->ndisc_addresses_messages++;
link = req->link;
rt = req->userdata;
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
@ -455,7 +475,7 @@ static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router
*na = (NDiscAddress) {
.router = router,
.address = ret,
.address = address,
};
na_exist = set_get(link->ndisc_addresses, na);
@ -474,9 +494,33 @@ static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router
return 0;
}
static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
_cleanup_(address_freep) Address *address = in;
Request *req;
int r;
assert(address);
assert(link);
assert(rt);
if (address_get(link, address, NULL) < 0)
link->ndisc_addresses_configured = false;
r = link_request_address(link, TAKE_PTR(address), true, &link->ndisc_addresses_messages,
ndisc_address_handler, &req);
if (r < 0)
return r;
req->userdata = sd_ndisc_router_ref(rt);
req->after_configure = ndisc_after_address_configure;
req->on_free = ndisc_request_on_free;
return 0;
}
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = NULL;
union in_addr_union gateway;
struct in6_addr gateway;
uint16_t lifetime;
unsigned preference;
uint32_t table, mtu;
@ -493,17 +537,17 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
if (lifetime == 0) /* not a default router */
return 0;
r = sd_ndisc_router_get_address(rt, &gateway.in6);
r = sd_ndisc_router_get_address(rt, &gateway);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
if (link_has_ipv6_address(link, &gateway.in6) > 0) {
if (link_has_ipv6_address(link, &gateway) > 0) {
if (DEBUG_LOGGING) {
_cleanup_free_ char *buffer = NULL;
(void) in_addr_to_string(AF_INET6, &gateway, &buffer);
(void) in6_addr_to_string(&gateway, &buffer);
log_link_debug(link, "No NDisc route added, gateway %s matches local address",
strnull(buffer));
strna(buffer));
}
return 0;
}
@ -534,13 +578,13 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw_family = AF_INET6;
route->gw = gateway;
route->gw.in6 = gateway;
route->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC);
route->mtu = mtu;
r = ndisc_route_configure(route, link, rt);
r = ndisc_request_route(TAKE_PTR(route), link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set default route: %m");
return log_link_error_errno(link, r, "Could not request default route: %m");
Route *route_gw;
HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
@ -550,22 +594,26 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
if (route_gw->gw_family != AF_INET6)
continue;
route_gw->gw = gateway;
if (!route_gw->table_set)
route_gw->table = table;
if (!route_gw->priority_set)
route_gw->priority = link->network->ipv6_accept_ra_route_metric;
if (!route_gw->protocol_set)
route_gw->protocol = RTPROT_RA;
if (!route_gw->pref_set)
route_gw->pref = preference;
route_gw->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC);
if (route_gw->mtu == 0)
route_gw->mtu = mtu;
r = ndisc_route_configure(route_gw, link, rt);
r = route_dup(route_gw, &route);
if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m");
return r;
route->gw.in6 = gateway;
if (!route->table_set)
route->table = table;
if (!route->priority_set)
route->priority = link->network->ipv6_accept_ra_route_metric;
if (!route->protocol_set)
route->protocol = RTPROT_RA;
if (!route->pref_set)
route->pref = preference;
route->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC);
if (route->mtu == 0)
route->mtu = mtu;
r = ndisc_request_route(TAKE_PTR(route), link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not request gateway: %m");
}
return 0;
@ -650,7 +698,7 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address,
_cleanup_free_ struct in6_addr *new_address = NULL;
if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
&& (in6_addr_is_null(&j->prefix) || IN6_ARE_ADDR_EQUAL(&j->prefix, address))) {
&& (in6_addr_is_null(&j->prefix) || in6_addr_equal(&j->prefix, address))) {
/* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop
* does not actually attempt Duplicate Address Detection; the counter will be incremented
* only when the address generation algorithm produces an invalid address, and the loop
@ -709,7 +757,6 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address,
static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
_cleanup_set_free_free_ Set *addresses = NULL;
_cleanup_(address_freep) Address *address = NULL;
struct in6_addr addr, *a;
unsigned prefixlen;
usec_t time_now;
@ -746,18 +793,18 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
if (r < 0)
return r;
r = address_new(&address);
if (r < 0)
return log_oom();
address->family = AF_INET6;
address->prefixlen = prefixlen;
address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
address->cinfo.ifa_prefered = lifetime_preferred;
SET_FOREACH(a, addresses) {
_cleanup_(address_freep) Address *address = NULL;
Address *existing_address;
r = address_new(&address);
if (r < 0)
return log_oom();
address->family = AF_INET6;
address->prefixlen = prefixlen;
address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
address->cinfo.ifa_prefered = lifetime_preferred;
address->in_addr.in6 = *a;
/* see RFC4862 section 5.5.3.e */
@ -778,9 +825,9 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
if (address->cinfo.ifa_valid == 0)
continue;
r = ndisc_address_configure(address, link, rt);
r = ndisc_request_address(TAKE_PTR(address), link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
return log_link_error_errno(link, r, "Could not request SLAAC address: %m");
}
return 0;
@ -824,16 +871,16 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
r = ndisc_route_configure(route, link, rt);
r = ndisc_request_route(TAKE_PTR(route), link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set prefix route: %m");;
return log_link_error_errno(link, r, "Could not request prefix route: %m");;
return 0;
}
static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = NULL;
union in_addr_union gateway, dst;
struct in6_addr gateway, dst;
uint32_t lifetime;
unsigned preference, prefixlen;
usec_t time_now;
@ -848,35 +895,35 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
if (lifetime == 0)
return 0;
r = sd_ndisc_router_route_get_address(rt, &dst.in6);
r = sd_ndisc_router_route_get_address(rt, &dst);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get route address: %m");
if ((!set_isempty(link->network->ndisc_allow_listed_route_prefix) &&
!set_contains(link->network->ndisc_allow_listed_route_prefix, &dst.in6)) ||
set_contains(link->network->ndisc_deny_listed_route_prefix, &dst.in6)) {
!set_contains(link->network->ndisc_allow_listed_route_prefix, &dst)) ||
set_contains(link->network->ndisc_deny_listed_route_prefix, &dst)) {
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
(void) in_addr_to_string(AF_INET6, &dst, &buf);
(void) in6_addr_to_string(&dst, &buf);
if (!set_isempty(link->network->ndisc_allow_listed_route_prefix))
log_link_debug(link, "Route prefix '%s' is not in allow list, ignoring", strnull(buf));
log_link_debug(link, "Route prefix '%s' is not in allow list, ignoring", strna(buf));
else
log_link_debug(link, "Route prefix '%s' is in deny list, ignoring", strnull(buf));
log_link_debug(link, "Route prefix '%s' is in deny list, ignoring", strna(buf));
}
return 0;
}
r = sd_ndisc_router_get_address(rt, &gateway.in6);
r = sd_ndisc_router_get_address(rt, &gateway);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
if (link_has_ipv6_address(link, &gateway.in6) > 0) {
if (link_has_ipv6_address(link, &gateway) > 0) {
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
(void) in_addr_to_string(AF_INET6, &gateway, &buf);
log_link_debug(link, "Advertised route gateway, %s, is local to the link, ignoring route", strnull(buf));
(void) in6_addr_to_string(&gateway, &buf);
log_link_debug(link, "Advertised route gateway %s is local to the link, ignoring route", strna(buf));
}
return 0;
}
@ -902,15 +949,15 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
route->priority = link->network->ipv6_accept_ra_route_metric;
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw = gateway;
route->gw.in6 = gateway;
route->gw_family = AF_INET6;
route->dst = dst;
route->dst.in6 = dst;
route->dst_prefixlen = prefixlen;
route->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC);
r = ndisc_route_configure(route, link, rt);
r = ndisc_request_route(TAKE_PTR(route), link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set additional route: %m");
return log_link_error_errno(link, r, "Could not request additional route: %m");
return 0;
}
@ -959,7 +1006,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
SET_FOREACH(rdnss, link->ndisc_rdnss)
if (IN6_ARE_ADDR_EQUAL(&rdnss->router, &router))
if (in6_addr_equal(&rdnss->router, &router))
rdnss->marked = true;
if (lifetime == 0)
@ -1053,7 +1100,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
SET_FOREACH(dnssl, link->ndisc_dnssl)
if (IN6_ARE_ADDR_EQUAL(&dnssl->router, &router))
if (in6_addr_equal(&dnssl->router, &router))
dnssl->marked = true;
if (lifetime == 0)
@ -1119,20 +1166,20 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
switch (type) {
case SD_NDISC_OPTION_PREFIX_INFORMATION: {
union in_addr_union a;
struct in6_addr a;
uint8_t flags;
r = sd_ndisc_router_prefix_get_address(rt, &a.in6);
r = sd_ndisc_router_prefix_get_address(rt, &a);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
if ((!set_isempty(link->network->ndisc_allow_listed_prefix) &&
!set_contains(link->network->ndisc_allow_listed_prefix, &a.in6)) ||
set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) {
!set_contains(link->network->ndisc_allow_listed_prefix, &a)) ||
set_contains(link->network->ndisc_deny_listed_prefix, &a)) {
if (DEBUG_LOGGING) {
_cleanup_free_ char *b = NULL;
(void) in_addr_to_string(AF_INET6, &a, &b);
(void) in6_addr_to_string(&a, &b);
if (!set_isempty(link->network->ndisc_allow_listed_prefix))
log_link_debug(link, "Prefix '%s' is not in allow list, ignoring", strna(b));
else
@ -1187,7 +1234,7 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
}
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
union in_addr_union router;
struct in6_addr router;
uint64_t flags;
NDiscAddress *na;
NDiscRoute *nr;
@ -1198,17 +1245,17 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
assert(link->manager);
assert(rt);
r = sd_ndisc_router_get_address(rt, &router.in6);
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
if ((!set_isempty(link->network->ndisc_allow_listed_router) &&
!set_contains(link->network->ndisc_allow_listed_router, &router.in6)) ||
set_contains(link->network->ndisc_deny_listed_router, &router.in6)) {
!set_contains(link->network->ndisc_allow_listed_router, &router)) ||
set_contains(link->network->ndisc_deny_listed_router, &router)) {
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
(void) in_addr_to_string(AF_INET6, &router, &buf);
(void) in6_addr_to_string(&router, &buf);
if (!set_isempty(link->network->ndisc_allow_listed_router))
log_link_debug(link, "Router '%s' is not in allow list, ignoring", strna(buf));
else
@ -1218,11 +1265,11 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
}
SET_FOREACH(na, link->ndisc_addresses)
if (IN6_ARE_ADDR_EQUAL(&na->router, &router.in6))
if (in6_addr_equal(&na->router, &router))
na->marked = true;
SET_FOREACH(nr, link->ndisc_routes)
if (IN6_ARE_ADDR_EQUAL(&nr->router, &router.in6))
if (in6_addr_equal(&nr->router, &router))
nr->marked = true;
r = sd_ndisc_router_get_flags(rt, &flags);
@ -1235,11 +1282,11 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))
/* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
r = dhcp6_request_information(link, !(flags & ND_RA_FLAG_MANAGED));
else
/* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in managed mode
* even if router does not have M or O flag. */
r = dhcp6_request_address(link, false);
r = dhcp6_request_information(link, false);
if (r < 0 && r != -EBUSY)
return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
else
@ -1267,11 +1314,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return r;
if (link->ndisc_addresses_configured && link->ndisc_routes_configured)
link_check_ready(link);
else
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
return 0;
}

View File

@ -7,6 +7,7 @@
#include "networkd-manager.h"
#include "networkd-neighbor.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "set.h"
Neighbor *neighbor_free(Neighbor *neighbor) {
@ -235,34 +236,12 @@ static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const
"%s neighbor: lladdr: %s, dst: %s",
str, strna(lladdr), strna(dst));
}
static int neighbor_configure(
const Neighbor *neighbor,
Link *link,
link_netlink_message_handler_t callback,
Neighbor **ret) {
static int neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->neighbor_messages > 0);
link->neighbor_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
/* Neighbor may not exist yet. So, do not enter failed state here. */
log_link_message_warning_errno(link, m, r, "Could not set neighbor, ignoring");
if (link->neighbor_messages == 0) {
log_link_debug(link, "Neighbors set");
link->neighbors_configured = true;
link_check_ready(link);
}
return 1;
}
static int neighbor_configure(Neighbor *neighbor, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -271,6 +250,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link) {
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
assert(callback);
log_neighbor_debug(neighbor, "Configuring", link);
@ -291,22 +271,65 @@ static int neighbor_configure(Neighbor *neighbor, Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, neighbor_configure_handler,
r = neighbor_add(link, neighbor, ret);
if (r < 0)
return log_link_error_errno(link, r, "Could not add neighbor: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link->neighbor_messages++;
link_ref(link);
r = neighbor_add(link, neighbor, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Could not add neighbor: %m");
return r;
}
int link_set_neighbors(Link *link) {
static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->static_neighbor_messages > 0);
link->static_neighbor_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set neighbor");
link_enter_failed(link);
return 1;
}
if (link->static_neighbor_messages == 0) {
log_link_debug(link, "Neighbors set");
link->static_neighbors_configured = true;
link_check_ready(link);
}
return 1;
}
static int link_request_neighbor(
Link *link,
Neighbor *neighbor,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
assert(link);
assert(neighbor);
log_neighbor_debug(neighbor, "Requesting", link);
return link_queue_request(link, REQUEST_TYPE_NEIGHBOR, neighbor, consume_object,
message_counter, netlink_handler, ret);
}
int link_request_static_neighbors(Link *link) {
Neighbor *neighbor;
int r;
@ -314,24 +337,20 @@ int link_set_neighbors(Link *link) {
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
if (link->neighbor_messages != 0) {
log_link_debug(link, "Neighbors are configuring.");
return 0;
}
link->neighbors_configured = false;
link->static_neighbors_configured = false;
HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
r = neighbor_configure(neighbor, link);
r = link_request_neighbor(link, neighbor, false, &link->static_neighbor_messages,
static_neighbor_configure_handler, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set neighbor: %m");
return log_link_warning_errno(link, r, "Could not request neighbor: %m");
}
if (link->neighbor_messages == 0) {
link->neighbors_configured = true;
if (link->static_neighbor_messages == 0) {
link->static_neighbors_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting neighbors");
log_link_debug(link, "Requesting neighbors");
link_set_state(link, LINK_STATE_CONFIGURING);
}
@ -343,6 +362,9 @@ static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
assert(m);
assert(link);
assert(link->neighbor_remove_messages > 0);
link->neighbor_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
@ -382,6 +404,7 @@ static int neighbor_remove(Neighbor *neighbor, Link *link) {
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
link->neighbor_remove_messages++;
return 0;
}
@ -437,6 +460,34 @@ int link_drop_neighbors(Link *link) {
return r;
}
int request_process_neighbor(Request *req) {
Neighbor *ret;
int r;
assert(req);
assert(req->link);
assert(req->neighbor);
assert(req->type == REQUEST_TYPE_NEIGHBOR);
if (!link_is_ready_to_configure(req->link, false))
return 0;
if (req->link->neighbor_remove_messages > 0)
return 0;
r = neighbor_configure(req->neighbor, req->link, req->netlink_handler, &ret);
if (r < 0)
return r;
if (req->after_configure) {
r = req->after_configure(req, ret);
if (r < 0)
return r;
}
return 1;
}
int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(neighbor_freep) Neighbor *tmp = NULL;
_cleanup_free_ void *lladdr = NULL;

View File

@ -10,9 +10,10 @@
#include "in-addr-util.h"
#include "networkd-util.h"
typedef Manager Manager;
typedef Network Network;
typedef Link Link;
typedef struct Link Link;
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Request Request;
union lladdr_union {
struct ether_addr mac;
@ -34,10 +35,12 @@ Neighbor *neighbor_free(Neighbor *neighbor);
void network_drop_invalid_neighbors(Network *network);
int link_set_neighbors(Link *link);
int link_drop_neighbors(Link *link);
int link_drop_foreign_neighbors(Link *link);
int link_request_static_neighbors(Link *link);
int request_process_neighbor(Request *req);
int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);

View File

@ -228,7 +228,7 @@ struct Network {
bool dhcp6_pd_manage_temporary_address;
int64_t dhcp6_pd_subnet_id;
uint32_t dhcp6_pd_route_metric;
union in_addr_union dhcp6_pd_token;
struct in6_addr dhcp6_pd_token;
/* Bridge Support */
int use_bpdu;

View File

@ -10,6 +10,8 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "parse-util.h"
#include "set.h"
#include "string-util.h"
@ -356,13 +358,16 @@ static void log_nexthop_debug(const NextHop *nexthop, uint32_t id, const char *s
str, nexthop->id, id, strna(gw), yes_no(nexthop->blackhole));
}
static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int link_nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->nexthop_remove_messages > 0);
/* Note that link may be NULL. */
if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
link->nexthop_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
@ -372,6 +377,22 @@ static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
return 1;
}
static int manager_nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Manager *manager) {
int r;
assert(m);
assert(manager);
assert(manager->nexthop_remove_messages > 0);
manager->nexthop_remove_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ENOENT)
log_message_warning_errno(m, r, "Could not drop nexthop, ignoring");
return 1;
}
static int nexthop_remove(const NextHop *nexthop, Manager *manager, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -396,55 +417,40 @@ static int nexthop_remove(const NextHop *nexthop, Manager *manager, Link *link)
if (r < 0)
return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m");
r = netlink_call_async(manager->rtnl, NULL, req, nexthop_remove_handler,
link_netlink_destroy_callback, link);
if (link)
r = netlink_call_async(manager->rtnl, NULL, req, link_nexthop_remove_handler,
link_netlink_destroy_callback, link);
else
r = netlink_call_async(manager->rtnl, NULL, req, manager_nexthop_remove_handler,
NULL, manager);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link); /* link may be NULL, link_ref() is OK with that */
if (link)
link->nexthop_remove_messages++;
else
manager->nexthop_remove_messages++;
return 0;
}
static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
static int nexthop_configure(
const NextHop *nexthop,
Link *link,
link_netlink_message_handler_t callback,
NextHop **ret) {
assert(link);
assert(link->nexthop_messages > 0);
link->nexthop_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set nexthop");
link_enter_failed(link);
return 1;
}
if (link->nexthop_messages == 0) {
log_link_debug(link, "Nexthops set");
link->static_nexthops_configured = true;
/* Now all nexthops are configured. Let's configure remaining routes. */
r = link_set_routes_with_gateway(link);
if (r < 0)
link_enter_failed(link);
}
return 1;
}
static int nexthop_configure(const NextHop *nexthop, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
int r, k;
assert(link);
assert(link->manager);
assert(link->manager->rtnl);
assert(link->ifindex > 0);
assert(IN_SET(nexthop->family, AF_INET, AF_INET6));
assert(callback);
log_nexthop_debug(nexthop, nexthop->id, "Configuring", link);
@ -482,59 +488,89 @@ static int nexthop_configure(const NextHop *nexthop, Link *link) {
}
}
r = netlink_call_async(link->manager->rtnl, NULL, req, nexthop_handler,
k = nexthop_add(link, nexthop, ret);
if (k < 0)
return log_link_error_errno(link, k, "Could not add nexthop: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
r = nexthop_add(link, nexthop, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Could not add nexthop: %m");
return r;
return k;
}
int link_set_nexthops(Link *link) {
enum {
PHASE_ID, /* First phase: Nexthops with ID */
PHASE_WITHOUT_ID, /* Second phase: Nexthops without ID */
_PHASE_MAX,
} phase;
static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
assert(link->static_nexthop_messages > 0);
link->static_nexthop_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set nexthop");
link_enter_failed(link);
return 1;
}
if (link->static_nexthop_messages == 0) {
log_link_debug(link, "Nexthops set");
link->static_nexthops_configured = true;
link_check_ready(link);
}
return 1;
}
static int link_request_nexthop(
Link *link,
NextHop *nexthop,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
assert(link);
assert(nexthop);
log_nexthop_debug(nexthop, nexthop->id, "Requesting", link);
return link_queue_request(link, REQUEST_TYPE_NEXTHOP, nexthop, consume_object,
message_counter, netlink_handler, ret);
}
int link_request_static_nexthops(Link *link, bool only_ipv4) {
NextHop *nh;
int r;
assert(link);
assert(link->network);
if (link->nexthop_messages != 0) {
log_link_debug(link, "Nexthops are configuring.");
return 0;
}
link->static_nexthops_configured = false;
for (phase = PHASE_ID; phase < _PHASE_MAX; phase++)
HASHMAP_FOREACH(nh, link->network->nexthops_by_section) {
if ((nh->id > 0) != (phase == PHASE_ID))
continue;
HASHMAP_FOREACH(nh, link->network->nexthops_by_section) {
if (only_ipv4 && nh->family != AF_INET)
continue;
r = nexthop_configure(nh, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set nexthop: %m");
link->nexthop_messages++;
}
if (link->nexthop_messages == 0) {
link->static_nexthops_configured = true;
/* Finally, configure routes with gateways. */
return link_set_routes_with_gateway(link);
r = link_request_nexthop(link, nh, false, &link->static_nexthop_messages,
static_nexthop_handler, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request nexthop: %m");
}
log_link_debug(link, "Setting nexthops");
link_set_state(link, LINK_STATE_CONFIGURING);
if (link->static_nexthop_messages == 0) {
link->static_nexthops_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Requesting nexthops");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
@ -657,6 +693,73 @@ int link_drop_nexthops(Link *link) {
return r;
}
static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
assert(link);
assert(nexthop);
if (nexthop->blackhole) {
if (link->manager->nexthop_remove_messages > 0)
return false;
} else {
Link *l;
HASHMAP_FOREACH(l, link->manager->links) {
if (l->address_remove_messages > 0)
return false;
if (l->nexthop_remove_messages > 0)
return false;
if (l->route_remove_messages > 0)
return false;
}
}
if (nexthop->id == 0) {
Request *req;
ORDERED_SET_FOREACH(req, link->manager->request_queue) {
if (req->type != REQUEST_TYPE_NEXTHOP)
continue;
if (req->nexthop->id != 0)
return false; /* first configure nexthop with id. */
}
}
if (nexthop->onlink <= 0 &&
in_addr_is_set(nexthop->family, &nexthop->gw) &&
!manager_address_is_reachable(link->manager, nexthop->family, &nexthop->gw))
return false;
return true;
}
int request_process_nexthop(Request *req) {
NextHop *ret;
int r;
assert(req);
assert(req->link);
assert(req->nexthop);
assert(req->type == REQUEST_TYPE_NEXTHOP);
if (!link_is_ready_to_configure(req->link, false))
return 0;
if (!nexthop_is_ready_to_configure(req->link, req->nexthop))
return 0;
r = nexthop_configure(req->nexthop, req->link, req->netlink_handler, &ret);
if (r < 0)
return r;
if (req->after_configure) {
r = req->after_configure(req, ret);
if (r < 0)
return r;
}
return 1;
}
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(nexthop_freep) NextHop *tmp = NULL;
NextHop *nexthop = NULL;

View File

@ -15,6 +15,7 @@
typedef struct Link Link;
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Request Request;
typedef struct NextHop {
Network *network;
@ -36,10 +37,12 @@ NextHop *nexthop_free(NextHop *nexthop);
void network_drop_invalid_nexthops(Network *network);
int link_set_nexthops(Link *link);
int link_drop_nexthops(Link *link);
int link_drop_foreign_nexthops(Link *link);
int link_request_static_nexthops(Link *link, bool only_ipv4);
int request_process_nexthop(Request *req);
int manager_get_nexthop_by_id(Manager *manager, uint32_t id, NextHop **ret);
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);

View File

@ -0,0 +1,151 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "networkd-address.h"
#include "networkd-manager.h"
#include "networkd-neighbor.h"
#include "networkd-nexthop.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-queue.h"
static void request_free_object(RequestType type, void *object) {
switch(type) {
case REQUEST_TYPE_ADDRESS:
address_free(object);
break;
case REQUEST_TYPE_NEIGHBOR:
neighbor_free(object);
break;
case REQUEST_TYPE_NEXTHOP:
nexthop_free(object);
break;
case REQUEST_TYPE_ROUTE:
route_free(object);
break;
case REQUEST_TYPE_ROUTING_POLICY_RULE:
routing_policy_rule_free(object);
break;
default:
assert_not_reached("invalid request type.");
}
}
Request *request_free(Request *req) {
if (!req)
return NULL;
if (req->on_free)
req->on_free(req);
if (req->consume_object)
request_free_object(req->type, req->object);
if (req->link && req->link->manager)
ordered_set_remove(req->link->manager->request_queue, req);
link_unref(req->link);
return mfree(req);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_free);
void request_drop(Request *req) {
if (req->message_counter)
(*req->message_counter)--;
request_free(req);
}
int link_queue_request(
Link *link,
RequestType type,
void *object,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
_cleanup_(request_freep) Request *req = NULL;
int r;
assert(link);
assert(link->manager);
assert(type >= 0 && type < _REQUEST_TYPE_MAX);
assert(object);
assert(netlink_handler);
req = new(Request, 1);
if (!req) {
if (consume_object)
request_free_object(type, object);
return -ENOMEM;
}
*req = (Request) {
.link = link,
.type = type,
.object = object,
.consume_object = consume_object,
.message_counter = message_counter,
.netlink_handler = netlink_handler,
};
link_ref(link);
r = ordered_set_ensure_put(&link->manager->request_queue, NULL, req);
if (r < 0)
return r;
if (req->message_counter)
(*req->message_counter)++;
if (ret)
*ret = req;
TAKE_PTR(req);
return 0;
}
int manager_process_requests(sd_event_source *s, void *userdata) {
Manager *manager = userdata;
int r;
assert(manager);
for (;;) {
bool processed = false;
Request *req;
ORDERED_SET_FOREACH(req, manager->request_queue) {
switch(req->type) {
case REQUEST_TYPE_ADDRESS:
r = request_process_address(req);
break;
case REQUEST_TYPE_NEIGHBOR:
r = request_process_neighbor(req);
break;
case REQUEST_TYPE_NEXTHOP:
r = request_process_nexthop(req);
break;
case REQUEST_TYPE_ROUTE:
r = request_process_route(req);
break;
case REQUEST_TYPE_ROUTING_POLICY_RULE:
r = request_process_routing_policy_rule(req);
break;
default:
return -EINVAL;
}
if (r < 0)
link_enter_failed(req->link);
if (r > 0) {
ordered_set_remove(manager->request_queue, req);
request_free(req);
processed = true;
}
}
if (!processed)
break;
}
return 0;
}

View File

@ -0,0 +1,60 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-event.h"
#include "networkd-link.h"
typedef struct Address Address;
typedef struct Neighbor Neighbor;
typedef struct NextHop NextHop;
typedef struct Route Route;
typedef struct RoutingPolicyRule RoutingPolicyRule;
typedef struct Request Request;
typedef int (*request_after_configure_handler_t)(Request*, void*);
typedef void (*request_on_free_handler_t)(Request*);
typedef enum RequestType {
REQUEST_TYPE_ADDRESS,
REQUEST_TYPE_NEIGHBOR,
REQUEST_TYPE_NEXTHOP,
REQUEST_TYPE_ROUTE,
REQUEST_TYPE_ROUTING_POLICY_RULE,
_REQUEST_TYPE_MAX,
_REQUEST_TYPE_INVALID = -EINVAL,
} RequestType;
typedef struct Request {
Link *link;
RequestType type;
bool consume_object;
union {
Address *address;
Neighbor *neighbor;
NextHop *nexthop;
Route *route;
RoutingPolicyRule *rule;
void *object;
};
void *userdata;
unsigned *message_counter;
link_netlink_message_handler_t netlink_handler;
request_after_configure_handler_t after_configure;
request_on_free_handler_t on_free;
} Request;
Request *request_free(Request *req);
void request_drop(Request *req);
int link_queue_request(
Link *link,
RequestType type,
void *object,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret);
int manager_process_requests(sd_event_source *s, void *userdata);

View File

@ -9,8 +9,8 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "parse-util.h"
#include "socket-netlink.h"
#include "string-table.h"
@ -288,7 +288,7 @@ Route *route_free(Route *route) {
set_remove(route->manager->routes_foreign, route);
}
ordered_set_free_free(route->multipath_routes);
ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free);
sd_event_source_unref(route->expire);
@ -510,6 +510,44 @@ static void route_copy(Route *dest, const Route *src, const MultipathRoute *m, c
}
}
int route_dup(const Route *src, Route **ret) {
_cleanup_(route_freep) Route *dest = NULL;
MultipathRoute *m;
int r;
assert(src);
assert(ret);
dest = newdup(Route, src, 1);
if (!dest)
return -ENOMEM;
/* Unset all pointers */
dest->network = NULL;
dest->section = NULL;
dest->link = NULL;
dest->manager = NULL;
dest->multipath_routes = NULL;
dest->expire = NULL;
ORDERED_SET_FOREACH(m, src->multipath_routes) {
_cleanup_(multipath_route_freep) MultipathRoute *n = NULL;
r = multipath_route_dup(m, &n);
if (r < 0)
return r;
r = ordered_set_ensure_put(&dest->multipath_routes, NULL, n);
if (r < 0)
return r;
TAKE_PTR(n);
}
*ret = TAKE_PTR(dest);
return 0;
}
static int route_add_internal(Manager *manager, Link *link, Set **routes, const Route *in, Route **ret) {
_cleanup_(route_freep) Route *route = NULL;
int r;
@ -604,13 +642,115 @@ static bool route_type_is_reject(const Route *route) {
return IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW);
}
static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *m) {
_cleanup_free_ char *dst = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL,
int link_has_route(Link *link, const Route *route) {
MultipathRoute *m;
int r;
assert(link);
assert(route);
if (route->nexthop_id > 0) {
_cleanup_(route_freep) Route *tmp = NULL;
NextHop *nh;
if (manager_get_nexthop_by_id(link->manager, route->nexthop_id, &nh) < 0)
return false;
r = route_new(&tmp);
if (r < 0)
return r;
route_copy(tmp, route, NULL, nh);
if (route_type_is_reject(route) || (nh && nh->blackhole))
return route_get(link->manager, NULL, tmp, NULL) >= 0;
else
return route_get(NULL, link, tmp, NULL) >= 0;
}
if (ordered_set_isempty(route->multipath_routes)) {
if (route_type_is_reject(route))
return route_get(link->manager, NULL, route, NULL) >= 0;
else
return route_get(NULL, link, route, NULL) >= 0;
}
ORDERED_SET_FOREACH(m, route->multipath_routes) {
_cleanup_(route_freep) Route *tmp = NULL;
Link *l;
if (m->ifname) {
r = resolve_interface(&link->manager->rtnl, m->ifname);
if (r < 0)
return false;
m->ifindex = r;
if (link_get(link->manager, m->ifindex, &l) < 0)
return false;
} else
l = link;
r = route_new(&tmp);
if (r < 0)
return r;
route_copy(tmp, route, m, NULL);
if (route_get(NULL, l, tmp, NULL) < 0)
return false;
}
return true;
}
static bool route_address_is_reachable(const Route *route, int family, const union in_addr_union *address) {
assert(route);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
if (route->family != family)
return false;
if (!in_addr_is_set(route->family, &route->dst))
return false;
return in_addr_prefix_intersect(
route->family,
&route->dst,
route->dst_prefixlen,
address,
FAMILY_ADDRESS_SIZE(family) * 8) > 0;
}
bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address) {
Link *link;
assert(manager);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
HASHMAP_FOREACH(link, manager->links) {
Route *route;
SET_FOREACH(route, link->routes)
if (route_address_is_reachable(route, family, address))
return true;
SET_FOREACH(route, link->routes_foreign)
if (route_address_is_reachable(route, family, address))
return true;
}
return false;
}
static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) {
_cleanup_free_ char *dst = NULL, *src = NULL, *gw_alloc = NULL, *prefsrc = NULL,
*table = NULL, *scope = NULL, *proto = NULL;
const char *gw = NULL;
assert(route);
assert(str);
assert(m);
assert(manager);
/* link may be NULL. */
@ -621,12 +761,32 @@ static void log_route_debug(const Route *route, const char *str, const Link *lin
(void) in_addr_prefix_to_string(route->family, &route->dst, route->dst_prefixlen, &dst);
if (in_addr_is_set(route->family, &route->src))
(void) in_addr_to_string(route->family, &route->src, &src);
if (in_addr_is_set(route->gw_family, &route->gw))
(void) in_addr_to_string(route->gw_family, &route->gw, &gw);
if (in_addr_is_set(route->gw_family, &route->gw)) {
(void) in_addr_to_string(route->gw_family, &route->gw, &gw_alloc);
gw = gw_alloc;
} else if (route->gateway_from_dhcp_or_ra) {
if (route->gw_family == AF_INET)
gw = "_dhcp4";
else if (route->gw_family == AF_INET6)
gw = "_ipv6ra";
} else {
MultipathRoute *m;
ORDERED_SET_FOREACH(m, route->multipath_routes) {
_cleanup_free_ char *buf = NULL, *joined = NULL;
union in_addr_union a = m->gateway.address;
(void) in_addr_to_string(m->gateway.family, &a, &buf);
joined = strjoin(gw_alloc, gw_alloc ? "," : "", strna(buf), m->ifname ? "@" : "", strempty(m->ifname));
if (joined)
free_and_replace(gw_alloc, joined);
}
gw = gw_alloc;
}
if (in_addr_is_set(route->family, &route->prefsrc))
(void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
(void) route_scope_to_string_alloc(route->scope, &scope);
(void) manager_get_route_table_to_string(m, route->table, &table);
(void) manager_get_route_table_to_string(manager, route->table, &table);
(void) route_protocol_full_to_string_alloc(route->protocol, &proto);
log_link_debug(link,
@ -743,18 +903,42 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req
return 0;
}
static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int link_route_remove_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
int r;
assert(m);
assert(link);
assert(link->route_remove_messages > 0);
assert(error_msg);
/* Note that link may be NULL. */
if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
link->route_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
log_link_message_warning_errno(link, m, r, error_msg);
return 1;
}
static int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_route_remove_handler_internal(rtnl, m, link, "Could not drop route, ignoring");
}
static int manager_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Manager *manager) {
int r;
assert(m);
assert(manager);
assert(manager->route_remove_messages > 0);
manager->route_remove_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
log_message_warning_errno(m, r, "Could not drop route, ignoring");
return 1;
}
@ -774,7 +958,6 @@ int route_remove(
if (!manager)
manager = link->manager;
/* link may be NULL! */
log_route_debug(route, "Removing", link, manager);
@ -803,18 +986,29 @@ int route_remove(
if (r < 0)
return r;
r = netlink_call_async(manager->rtnl, NULL, req,
callback ?: route_remove_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
if (link) {
r = netlink_call_async(manager->rtnl, NULL, req,
callback ?: link_route_remove_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link); /* link may be NULL, link_ref() is OK with that */
link_ref(link);
link->route_remove_messages++;
} else {
r = netlink_call_async(manager->rtnl, NULL, req,
manager_route_remove_handler,
NULL, manager);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
manager->route_remove_messages++;
}
return 0;
}
static bool link_has_route(const Link *link, const Route *route) {
static bool link_has_static_route(const Link *link, const Route *route) {
Route *net_route;
assert(link);
@ -830,7 +1024,7 @@ static bool link_has_route(const Link *link, const Route *route) {
return false;
}
static bool links_have_route(const Manager *manager, const Route *route, const Link *except) {
static bool links_have_static_route(const Manager *manager, const Route *route, const Link *except) {
Link *link;
assert(manager);
@ -839,7 +1033,7 @@ static bool links_have_route(const Manager *manager, const Route *route, const L
if (link == except)
continue;
if (link_has_route(link, route))
if (link_has_static_route(link, route))
return true;
}
@ -863,7 +1057,7 @@ static int manager_drop_routes_internal(Manager *manager, bool foreign, const Li
continue;
/* The route will be configured later, or already configured by a link. */
if (links_have_route(manager, route, except))
if (links_have_static_route(manager, route, except))
continue;
/* The existing links do not have the route. Let's drop this now. It may be
@ -915,7 +1109,7 @@ int link_drop_foreign_routes(Link *link) {
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
continue;
if (link_has_route(link, route))
if (link_has_static_route(link, route))
k = route_add(NULL, link, route, NULL, NULL, NULL);
else
k = route_remove(route, NULL, link, NULL);
@ -1094,14 +1288,36 @@ static int append_nexthops(const Route *route, sd_netlink_message *req) {
return 0;
}
int route_configure(
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
int r;
assert(m);
assert(link);
assert(error_msg);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set route with gateway");
link_enter_failed(link);
return 0;
}
return 1;
}
static int route_configure(
const Route *route,
Link *link,
link_netlink_message_handler_t callback,
Route **ret) {
unsigned *ret_n_routes,
Route ***ret_routes) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
Route *nr;
_cleanup_free_ Route **routes = NULL;
unsigned n_routes = 0; /* avoid false maybe-uninitialized warning */
int r, k;
assert(link);
@ -1110,6 +1326,7 @@ int route_configure(
assert(link->ifindex > 0);
assert(IN_SET(route->family, AF_INET, AF_INET6));
assert(callback);
assert(!!ret_n_routes == !!ret_routes);
if (route_get(link->manager, link, route, NULL) <= 0 &&
set_size(link->routes) >= routes_max())
@ -1192,21 +1409,36 @@ int route_configure(
if (route->nexthop_id != 0 ||
in_addr_is_set(route->gw_family, &route->gw) ||
ordered_set_isempty(route->multipath_routes)) {
k = route_add_and_setup_timer(link, route, NULL, &nr);
if (ret_routes) {
n_routes = 1;
routes = new(Route*, n_routes);
if (!routes)
return log_oom();
}
k = route_add_and_setup_timer(link, route, NULL, routes);
if (k < 0)
return k;
} else {
MultipathRoute *m;
Route **p;
r = append_nexthops(route, req);
if (r < 0)
return log_link_error_errno(link, r, "Could not append RTA_MULTIPATH attribute: %m");
assert(!ret);
if (ret_routes) {
n_routes = ordered_set_size(route->multipath_routes);
routes = new(Route*, n_routes);
if (!routes)
return log_oom();
}
k = 0;
p = routes;
ORDERED_SET_FOREACH(m, route->multipath_routes) {
r = route_add_and_setup_timer(link, route, m, NULL);
r = route_add_and_setup_timer(link, route, m, ret_routes ? p++ : NULL);
if (r < 0)
return r;
if (r > 0)
@ -1221,32 +1453,28 @@ int route_configure(
link_ref(link);
if (ret)
*ret = nr;
if (ret_routes) {
*ret_n_routes = n_routes;
*ret_routes = TAKE_PTR(routes);
}
return k;
}
static int route_handler_with_gateway(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
assert(link->route_messages > 0);
assert(link->static_route_messages > 0);
link->route_messages--;
link->static_route_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = route_configure_handler_internal(rtnl, m, link, "Could not set route");
if (r <= 0)
return r;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set route with gateway");
link_enter_failed(link);
return 1;
}
if (link->route_messages == 0) {
log_link_debug(link, "Routes with gateway set");
if (link->static_route_messages == 0) {
log_link_debug(link, "Routes set");
link->static_routes_configured = true;
link_check_ready(link);
}
@ -1254,140 +1482,157 @@ static int route_handler_with_gateway(sd_netlink *rtnl, sd_netlink_message *m, L
return 1;
}
static int route_handler_without_gateway(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
int link_request_route(
Link *link,
Route *route,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
assert(link);
assert(link->route_messages > 0);
link->route_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set route without gateway");
link_enter_failed(link);
return 1;
}
if (link->route_messages == 0) {
log_link_debug(link, "Routes set without gateway");
/* Now, we can talk to gateways, let's configure nexthops. */
r = link_set_nexthops(link);
if (r < 0)
link_enter_failed(link);
}
return 1;
}
static bool route_has_gateway(const Route *route) {
assert(link->manager);
assert(route);
if (in_addr_is_set(route->gw_family, &route->gw))
return true;
if (!ordered_set_isempty(route->multipath_routes))
return true;
if (route->nexthop_id > 0)
return true;
return false;
log_route_debug(route, "Requesting", link, link->manager);
return link_queue_request(link, REQUEST_TYPE_ROUTE, route, consume_object,
message_counter, netlink_handler, ret);
}
static int link_set_routes_internal(Link *link, bool with_gateway) {
Route *rt;
int link_request_static_routes(Link *link, bool only_ipv4) {
Route *route;
int r;
assert(link);
assert(link->network);
HASHMAP_FOREACH(rt, link->network->routes_by_section) {
if (rt->gateway_from_dhcp_or_ra)
link->static_routes_configured = false;
HASHMAP_FOREACH(route, link->network->routes_by_section) {
if (route->gateway_from_dhcp_or_ra)
continue;
if (route_has_gateway(rt) != with_gateway)
if (only_ipv4 && route->family != AF_INET)
continue;
r = route_configure(rt, link, with_gateway ? route_handler_with_gateway : route_handler_without_gateway, NULL);
r = link_request_route(link, route, false, &link->static_route_messages,
static_route_handler, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set routes: %m");
link->route_messages++;
return r;
}
return 0;
}
int link_set_routes_with_gateway(Link *link) {
int r;
assert(link);
assert(link->network);
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
/* During configuring addresses, the link lost its carrier. As networkd is dropping
* the addresses now, let's not configure the routes either. */
return 0;
/* Finally, add routes that needs a gateway. */
r = link_set_routes_internal(link, true);
if (r < 0)
return r;
if (link->route_messages == 0) {
if (link->static_route_messages == 0) {
link->static_routes_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting routes with gateway");
log_link_debug(link, "Requesting routes");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
int link_set_routes(Link *link) {
static int route_is_ready_to_configure(const Route *route, Link *link) {
MultipathRoute *m;
NextHop *nh = NULL;
int r;
assert(route);
assert(link);
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
link->static_routes_configured = false;
if (route->nexthop_id > 0 &&
manager_get_nexthop_by_id(link->manager, route->nexthop_id, &nh) < 0)
return false;
if (!link->addresses_ready)
return 0;
if (route_type_is_reject(route) || (nh && nh->blackhole)) {
if (nh && link->manager->nexthop_remove_messages > 0)
return false;
if (link->manager->route_remove_messages > 0)
return false;
} else {
Link *l;
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
/* During configuring addresses, the link lost its carrier. As networkd is dropping
* the addresses now, let's not configure the routes either. */
return 0;
if (link->route_messages != 0) {
log_link_debug(link, "Static routes are configuring.");
return 0;
HASHMAP_FOREACH(l, link->manager->links) {
if (l->address_remove_messages > 0)
return false;
if (l->nexthop_remove_messages > 0)
return false;
if (l->route_remove_messages > 0)
return false;
}
}
r = link_set_routing_policy_rules(link);
if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
r = manager_has_address(link->manager, route->family, &route->prefsrc, route->family == AF_INET6);
if (r <= 0)
return r;
}
if (route->gateway_onlink <= 0 &&
in_addr_is_set(route->gw_family, &route->gw) > 0 &&
!manager_address_is_reachable(link->manager, route->gw_family, &route->gw))
return false;
ORDERED_SET_FOREACH(m, route->multipath_routes) {
union in_addr_union a = m->gateway.address;
if (route->gateway_onlink <= 0 &&
!manager_address_is_reachable(link->manager, m->gateway.family, &a))
return false;
if (m->ifname) {
Link *l;
r = resolve_interface(&link->manager->rtnl, m->ifname);
if (r < 0)
return false;
m->ifindex = r;
if (link_get(link->manager, m->ifindex, &l) < 0)
return false;
if (!link_is_ready_to_configure(l, true))
return false;
}
}
return true;
}
int request_process_route(Request *req) {
_cleanup_free_ Route **routes = NULL;
unsigned n_routes;
int r;
assert(req);
assert(req->link);
assert(req->route);
assert(req->type == REQUEST_TYPE_ROUTE);
if (!link_is_ready_to_configure(req->link, false))
return 0;
r = route_is_ready_to_configure(req->route, req->link);
if (r <= 0)
return r;
r = route_configure(req->route, req->link, req->netlink_handler,
req->after_configure ? &n_routes : NULL,
req->after_configure ? &routes : NULL);
if (r < 0)
return r;
/* First, add the routes that enable us to talk to gateways. */
r = link_set_routes_internal(link, false);
if (r < 0)
return r;
if (req->after_configure) {
assert(n_routes > 0);
if (link->route_messages == 0)
/* If no route is configured, then configure nexthops. */
return link_set_nexthops(link);
for (unsigned i = 0; i < n_routes; i++) {
r = req->after_configure(req, routes[i]);
if (r < 0)
return r;
}
}
log_link_debug(link, "Setting routes without gateway");
link_set_state(link, LINK_STATE_CONFIGURING);
return 0;
return 1;
}
static int process_route_one(Manager *manager, Link *link, uint16_t type, const Route *tmp, const MultipathRoute *m) {
@ -2460,13 +2705,14 @@ int config_parse_multipath_route(
void *data,
void *userdata) {
_cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
_cleanup_free_ char *word = NULL, *buf = NULL;
_cleanup_free_ MultipathRoute *m = NULL;
_cleanup_free_ char *word = NULL;
Network *network = userdata;
const char *p, *ip, *dev;
union in_addr_union a;
int family, r;
const char *p;
char *dev;
assert(filename);
assert(section);
@ -2484,7 +2730,7 @@ int config_parse_multipath_route(
}
if (isempty(rvalue)) {
n->multipath_routes = ordered_set_free_free(n->multipath_routes);
n->multipath_routes = ordered_set_free_with_destructor(n->multipath_routes, multipath_route_free);
return 0;
}
@ -2504,15 +2750,14 @@ int config_parse_multipath_route(
dev = strchr(word, '@');
if (dev) {
buf = strndup(word, dev - word);
if (!buf)
return log_oom();
ip = buf;
dev++;
} else
ip = word;
*dev++ = '\0';
r = in_addr_from_string_auto(ip, &family, &a);
m->ifname = strdup(dev);
if (!m->ifname)
return log_oom();
}
r = in_addr_from_string_auto(word, &family, &a);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
@ -2521,16 +2766,6 @@ int config_parse_multipath_route(
m->gateway.address = a;
m->gateway.family = family;
if (dev) {
r = resolve_interface(NULL, dev);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid interface name or index, ignoring assignment: %s", dev);
return 0;
}
m->ifindex = r;
}
if (!isempty(p)) {
r = safe_atou32(p, &m->weight);
if (r < 0) {

View File

@ -3,7 +3,6 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include "sd-netlink.h"
@ -14,6 +13,7 @@
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Request Request;
typedef struct Route {
Network *network;
@ -71,18 +71,31 @@ extern const struct hash_ops route_hash_ops;
int route_new(Route **ret);
Route *route_free(Route *route);
DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
int route_dup(const Route *src, Route **ret);
int route_configure(const Route *route, Link *link, link_netlink_message_handler_t callback, Route **ret);
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int link_route_remove_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int route_remove(const Route *route, Manager *manager, Link *link, link_netlink_message_handler_t callback);
int link_set_routes(Link *link);
int link_set_routes_with_gateway(Link *link);
int link_has_route(Link *link, const Route *route);
bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address);
int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link);
uint32_t link_get_dhcp_route_table(const Link *link);
uint32_t link_get_ipv6_accept_ra_route_table(const Link *link);
int link_request_route(
Link *link,
Route *route,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret);
int link_request_static_routes(Link *link, bool only_ipv4);
int request_process_route(Request *req);
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
int network_add_ipv4ll_route(Network *network);

View File

@ -12,6 +12,8 @@
#include "ip-protocol-list.h"
#include "netlink-util.h"
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-util.h"
#include "parse-util.h"
@ -109,45 +111,35 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
return 0;
}
static int routing_policy_rule_copy(RoutingPolicyRule *dest, const RoutingPolicyRule *src) {
_cleanup_free_ char *iif = NULL, *oif = NULL;
static int routing_policy_rule_dup(const RoutingPolicyRule *src, RoutingPolicyRule **ret) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *dest = NULL;
assert(dest);
assert(src);
assert(ret);
dest = newdup(RoutingPolicyRule, src, 1);
if (!dest)
return -ENOMEM;
/* Unset all pointers */
dest->manager = NULL;
dest->network = NULL;
dest->section = NULL;
dest->iif = dest->oif = NULL;
if (src->iif) {
iif = strdup(src->iif);
if (!iif)
dest->iif = strdup(src->iif);
if (!dest->iif)
return -ENOMEM;
}
if (src->oif) {
oif = strdup(src->oif);
if (!oif)
dest->oif = strdup(src->oif);
if (!dest->oif)
return -ENOMEM;
}
dest->family = src->family;
dest->from = src->from;
dest->from_prefixlen = src->from_prefixlen;
dest->to = src->to;
dest->to_prefixlen = src->to_prefixlen;
dest->invert_rule = src->invert_rule;
dest->tos = src->tos;
dest->type = src->type;
dest->fwmark = src->fwmark;
dest->fwmask = src->fwmask;
dest->priority = src->priority;
dest->table = src->table;
dest->iif = TAKE_PTR(iif);
dest->oif = TAKE_PTR(oif);
dest->ipproto = src->ipproto;
dest->protocol = src->protocol;
dest->sport = src->sport;
dest->dport = src->dport;
dest->uid_range = src->uid_range;
dest->suppress_prefixlen = src->suppress_prefixlen;
*ret = TAKE_PTR(dest);
return 0;
}
@ -323,7 +315,7 @@ static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *rule, Ro
return -ENOENT;
}
static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) {
static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
RoutingPolicyRule *existing;
bool is_new = false;
@ -331,19 +323,12 @@ static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, int
assert(m);
assert(in);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(in->family == AF_UNSPEC || in->family == family);
assert(IN_SET(in->family, AF_INET, AF_INET6));
r = routing_policy_rule_new(&rule);
r = routing_policy_rule_dup(in, &rule);
if (r < 0)
return r;
r = routing_policy_rule_copy(rule, in);
if (r < 0)
return r;
rule->family = family;
r = routing_policy_rule_get(m, rule, &existing);
if (r == -ENOENT) {
/* Rule does not exist, use a new one. */
@ -390,11 +375,11 @@ static int routing_policy_rule_consume_foreign(Manager *m, RoutingPolicyRule *ru
return 1;
}
static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, int family, const char *str, const Link *link, const Manager *m) {
static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const char *str, const Link *link, const Manager *m) {
_cleanup_free_ char *from = NULL, *to = NULL, *table = NULL;
assert(rule);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(IN_SET(rule->family, AF_INET, AF_INET6));
assert(str);
assert(m);
@ -403,8 +388,8 @@ static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, int fam
if (!DEBUG_LOGGING)
return;
(void) in_addr_prefix_to_string(family, &rule->from, rule->from_prefixlen, &from);
(void) in_addr_prefix_to_string(family, &rule->to, rule->to_prefixlen, &to);
(void) in_addr_prefix_to_string(rule->family, &rule->from, rule->from_prefixlen, &from);
(void) in_addr_prefix_to_string(rule->family, &rule->to, rule->to_prefixlen, &to);
(void) manager_get_route_table_to_string(m, rule->table, &table);
log_link_debug(link,
@ -534,10 +519,14 @@ static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule
return 0;
}
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Manager *manager) {
int r;
assert(m);
assert(manager);
assert(manager->routing_policy_rule_remove_messages > 0);
manager->routing_policy_rule_remove_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0)
@ -555,7 +544,7 @@ static int routing_policy_rule_remove(const RoutingPolicyRule *rule, Manager *ma
assert(manager->rtnl);
assert(IN_SET(rule->family, AF_INET, AF_INET6));
log_routing_policy_rule_debug(rule, rule->family, "Removing", NULL, manager);
log_routing_policy_rule_debug(rule, "Removing", NULL, manager);
r = sd_rtnl_message_new_routing_policy_rule(manager->rtnl, &m, RTM_DELRULE, rule->family);
if (r < 0)
@ -565,58 +554,37 @@ static int routing_policy_rule_remove(const RoutingPolicyRule *rule, Manager *ma
if (r < 0)
return r;
r = sd_netlink_call_async(manager->rtnl, NULL, m,
routing_policy_rule_remove_handler,
NULL, NULL, 0, __func__);
r = netlink_call_async(manager->rtnl, NULL, m,
routing_policy_rule_remove_handler,
NULL, manager);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
manager->routing_policy_rule_remove_messages++;
return 0;
}
static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
static int routing_policy_rule_configure(
const RoutingPolicyRule *rule,
Link *link,
link_netlink_message_handler_t callback,
RoutingPolicyRule **ret) {
assert(rtnl);
assert(m);
assert(link);
assert(link->ifname);
assert(link->routing_policy_rule_messages > 0);
link->routing_policy_rule_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
link_enter_failed(link);
return 1;
}
if (link->routing_policy_rule_messages == 0) {
log_link_debug(link, "Routing policy rule configured");
link->routing_policy_rules_configured = true;
link_check_ready(link);
}
return 1;
}
static int routing_policy_rule_configure_internal(const RoutingPolicyRule *rule, int family, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
assert(rule);
assert(IN_SET(rule->family, AF_INET, AF_INET6));
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
assert(callback);
log_routing_policy_rule_debug(rule, family, "Configuring", link, link->manager);
log_routing_policy_rule_debug(rule, "Configuring", link, link->manager);
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, family);
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_NEWRULE message: %m");
@ -624,43 +592,20 @@ static int routing_policy_rule_configure_internal(const RoutingPolicyRule *rule,
if (r < 0)
return r;
r = netlink_call_async(link->manager->rtnl, NULL, m,
routing_policy_rule_handler,
r = routing_policy_rule_add(link->manager, rule, ret);
if (r < 0)
return log_link_error_errno(link, r, "Could not add rule: %m");
r = netlink_call_async(link->manager->rtnl, NULL, m, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
link->routing_policy_rule_messages++;
r = routing_policy_rule_add(link->manager, rule, family, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Could not add rule: %m");
return r;
}
static int routing_policy_rule_configure(const RoutingPolicyRule *rule, Link *link) {
int r;
if (IN_SET(rule->family, AF_INET, AF_INET6))
return routing_policy_rule_configure_internal(rule, rule->family, link);
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)) {
r = routing_policy_rule_configure_internal(rule, AF_INET, link);
if (r < 0)
return r;
}
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) {
r = routing_policy_rule_configure_internal(rule, AF_INET6, link);
if (r < 0)
return r;
}
return 0;
}
static int links_have_routing_policy_rule(const Manager *m, const RoutingPolicyRule *rule, const Link *except) {
Link *link;
int r;
@ -685,11 +630,7 @@ static int links_have_routing_policy_rule(const Manager *m, const RoutingPolicyR
/* The case Family=both. */
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_new(&tmp);
if (r < 0)
return r;
r = routing_policy_rule_copy(tmp, link_rule);
r = routing_policy_rule_dup(link_rule, &tmp);
if (r < 0)
return r;
@ -735,36 +676,153 @@ int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const L
return r;
}
int link_set_routing_policy_rules(Link *link) {
static int static_routing_policy_rule_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->ifname);
assert(link->static_routing_policy_rule_messages > 0);
link->static_routing_policy_rule_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
link_enter_failed(link);
return 1;
}
if (link->static_routing_policy_rule_messages == 0) {
log_link_debug(link, "Routing policy rule configured");
link->static_routing_policy_rules_configured = true;
link_check_ready(link);
}
return 1;
}
static int link_request_routing_policy_rule(
Link *link,
RoutingPolicyRule *rule,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
assert(link);
assert(link->manager);
assert(rule);
log_routing_policy_rule_debug(rule, "Requesting", link, link->manager);
return link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, rule, consume_object,
message_counter, netlink_handler, ret);
}
static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
int r;
if (IN_SET(rule->family, AF_INET, AF_INET6))
return link_request_routing_policy_rule(link, rule, false,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_dup(rule, &tmp);
if (r < 0)
return r;
tmp->family = AF_INET;
r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
if (r < 0)
return r;
}
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_dup(rule, &tmp);
if (r < 0)
return r;
tmp->family = AF_INET6;
r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
if (r < 0)
return r;
}
return 0;
}
int link_request_static_routing_policy_rules(Link *link) {
RoutingPolicyRule *rule;
int r;
assert(link);
assert(link->network);
if (link->routing_policy_rule_messages != 0) {
log_link_debug(link, "Routing policy rules are configuring.");
return 0;
}
link->routing_policy_rules_configured = false;
link->static_routing_policy_rules_configured = false;
HASHMAP_FOREACH(rule, link->network->rules_by_section) {
r = routing_policy_rule_configure(rule, link);
r = link_request_static_routing_policy_rule(link, rule);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set routing policy rule: %m");
return log_link_warning_errno(link, r, "Could not request routing policy rule: %m");
}
if (link->routing_policy_rule_messages == 0)
link->routing_policy_rules_configured = true;
else {
log_link_debug(link, "Setting routing policy rules");
if (link->static_routing_policy_rule_messages == 0) {
link->static_routing_policy_rules_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Requesting routing policy rules");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
int request_process_routing_policy_rule(Request *req) {
RoutingPolicyRule *ret = NULL; /* avoid false maybe-uninitialized warning */
int r;
assert(req);
assert(req->link);
assert(req->rule);
assert(req->type == REQUEST_TYPE_ROUTING_POLICY_RULE);
if (!link_is_ready_to_configure(req->link, false))
return 0;
if (req->link->manager->routing_policy_rule_remove_messages > 0)
return 0;
r = routing_policy_rule_configure(req->rule, req->link, req->netlink_handler, &ret);
if (r < 0)
return r;
if (req->after_configure) {
r = req->after_configure(req, ret);
if (r < 0)
return r;
}
return 1;
}
static const RoutingPolicyRule kernel_rules[] = {
{ .family = AF_INET, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
{ .family = AF_INET, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
@ -977,11 +1035,11 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
switch (type) {
case RTM_NEWRULE:
if (rule)
log_routing_policy_rule_debug(tmp, tmp->family, "Received remembered", NULL, m);
log_routing_policy_rule_debug(tmp, "Received remembered", NULL, m);
else if (!m->manage_foreign_routes)
log_routing_policy_rule_debug(tmp, tmp->family, "Ignoring received foreign", NULL, m);
log_routing_policy_rule_debug(tmp, "Ignoring received foreign", NULL, m);
else {
log_routing_policy_rule_debug(tmp, tmp->family, "Remembering foreign", NULL, m);
log_routing_policy_rule_debug(tmp, "Remembering foreign", NULL, m);
r = routing_policy_rule_consume_foreign(m, TAKE_PTR(tmp));
if (r < 0)
log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
@ -989,10 +1047,10 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
break;
case RTM_DELRULE:
if (rule) {
log_routing_policy_rule_debug(tmp, tmp->family, "Forgetting", NULL, m);
log_routing_policy_rule_debug(tmp, "Forgetting", NULL, m);
routing_policy_rule_free(rule);
} else
log_routing_policy_rule_debug(tmp, tmp->family, "Kernel removed unknown", NULL, m);
log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
break;
default:

View File

@ -4,16 +4,15 @@
#include <inttypes.h>
#include <linux/fib_rules.h>
#include <stdbool.h>
#include <stdio.h>
#include "conf-parser.h"
#include "in-addr-util.h"
#include "networkd-util.h"
#include "set.h"
typedef struct Network Network;
typedef struct Link Link;
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Request Request;
typedef struct RoutingPolicyRule {
Manager *manager;
@ -55,7 +54,8 @@ RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule);
void network_drop_invalid_routing_policy_rules(Network *network);
int link_set_routing_policy_rules(Link *link);
int link_request_static_routing_policy_rules(Link *link);
int request_process_routing_policy_rule(Request *req);
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except);

View File

@ -977,7 +977,7 @@ static int config_parse_label(
/* Nota bene: the empty label is a totally valid one. Let's hence not follow our usual rule of
* assigning the empty string to reset to default here, but really accept it as label to set. */
r = specifier_printf(rvalue, specifier_table, NULL, &resolved);
r = specifier_printf(rvalue, GPT_LABEL_MAX, specifier_table, NULL, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in Label=, ignoring: %s", rvalue);
@ -1142,7 +1142,7 @@ static int config_parse_copy_files(
if (!isempty(p))
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Too many arguments: %s", rvalue);
r = specifier_printf(source, specifier_table, NULL, &resolved_source);
r = specifier_printf(source, PATH_MAX-1, specifier_table, NULL, &resolved_source);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in CopyFiles= source, ignoring: %s", rvalue);
@ -1153,7 +1153,7 @@ static int config_parse_copy_files(
if (r < 0)
return 0;
r = specifier_printf(target, specifier_table, NULL, &resolved_target);
r = specifier_printf(target, PATH_MAX-1, specifier_table, NULL, &resolved_target);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in CopyFiles= target, ignoring: %s", resolved_target);
@ -1202,7 +1202,7 @@ static int config_parse_copy_blocks(
return 0;
}
r = specifier_printf(rvalue, specifier_table, NULL, &d);
r = specifier_printf(rvalue, PATH_MAX-1, specifier_table, NULL, &d);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in CopyBlocks= source path, ignoring: %s", rvalue);
@ -1250,7 +1250,7 @@ static int config_parse_make_dirs(
if (r == 0)
return 0;
r = specifier_printf(word, specifier_table, NULL, &d);
r = specifier_printf(word, PATH_MAX-1, specifier_table, NULL, &d);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in MakeDirectories= parameter, ignoring: %s", word);

View File

@ -255,7 +255,7 @@ int config_parse_dnssd_service_name(
return 0;
}
r = specifier_printf(rvalue, specifier_table, NULL, &name);
r = specifier_printf(rvalue, DNS_LABEL_MAX, specifier_table, NULL, &name);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid service instance name template '%s', ignoring assignment: %m", rvalue);

View File

@ -170,7 +170,7 @@ int dnssd_render_instance_name(DnssdService *s, char **ret_name) {
assert(s);
assert(s->name_template);
r = specifier_printf(s->name_template, specifier_table, s, &name);
r = specifier_printf(s->name_template, DNS_LABEL_MAX, specifier_table, s, &name);
if (r < 0)
return log_debug_errno(r, "Failed to replace specifiers: %m");

View File

@ -1097,18 +1097,27 @@ uint32_t manager_find_mtu(Manager *m) {
uint32_t mtu = 0;
Link *l;
/* If we don't know on which link a DNS packet would be
* delivered, let's find the largest MTU that works on all
* interfaces we know of */
/* If we don't know on which link a DNS packet would be delivered, let's find the largest MTU that
* works on all interfaces we know of that have an IP address asociated */
HASHMAP_FOREACH(l, m->links) {
if (l->mtu <= 0)
/* Let's filter out links without IP addresses (e.g. AF_CAN links and suchlike) */
if (!l->addresses)
continue;
/* Safety check: MTU shorter than what we need for the absolutely shortest DNS request? Then
* let's ignore this link. */
if (l->mtu < MIN(UDP4_PACKET_HEADER_SIZE + DNS_PACKET_HEADER_SIZE,
UDP6_PACKET_HEADER_SIZE + DNS_PACKET_HEADER_SIZE))
continue;
if (mtu <= 0 || l->mtu < mtu)
mtu = l->mtu;
}
if (mtu == 0) /* found nothing? then let's assume the typical Ethernet MTU for lack of anything more precise */
return 1500;
return mtu;
}

View File

@ -18,7 +18,7 @@
# Some examples of DNS servers which may be used for DNS= and FallbackDNS=:
# Cloudflare: 1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com 2606:4700:4700::1111#cloudflare-dns.com 2606:4700:4700::1001#cloudflare-dns.com
# Google: 8.8.8.8#dns.google 8.8.4.4#dns.google 2001:4860:4860::8888#dns.google 2001:4860:4860::8844#dns.google
# Quad9: 9.9.9.9#dns.quad9.net 2620:fe::fe#dns.quad9.net
# Quad9: 9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
#DNS=
#FallbackDNS=@DNS_SERVERS@
#Domains=

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "af-list.h"
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-unit-util.h"
@ -879,14 +880,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
address_family = eq ? word : NULL;
if (address_family) {
if (!STR_IN_SET(address_family, "IPv4", "IPv6"))
family = af_from_ipv4_ipv6(address_family);
if (family == AF_UNSPEC)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Only IPv4 and IPv6 protocols are supported");
if (streq(address_family, "IPv4"))
family = AF_INET;
else
family = AF_INET6;
"Only \"ipv4\" and \"ipv6\" protocols are supported");
}
user_port = eq ? eq : word;

View File

@ -985,7 +985,7 @@ bool dns_service_name_is_valid(const char *name) {
l = strlen(name);
if (l <= 0)
return false;
if (l > 63)
if (l > DNS_LABEL_MAX)
return false;
return true;

View File

@ -104,7 +104,7 @@ int gpt_partition_label_valid(const char *s) {
if (!recoded)
return -ENOMEM;
return char16_strlen(recoded) <= 36;
return char16_strlen(recoded) <= GPT_LABEL_MAX;
}
bool gpt_partition_type_is_root(sd_id128_t id) {

View File

@ -115,6 +115,9 @@
#define GPT_FLAG_NO_AUTO (1ULL << 63)
#define GPT_FLAG_GROWFS (1ULL << 59)
/* maximum length of gpt label */
#define GPT_LABEL_MAX 36
const char *gpt_partition_type_uuid_to_string(sd_id128_t id);
const char *gpt_partition_type_uuid_to_string_harder(
sd_id128_t id,

View File

@ -103,7 +103,7 @@ static int specifier_last_component(char specifier, const void *data, const void
return 0;
}
int install_full_printf(const UnitFileInstallInfo *i, const char *format, char **ret) {
int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, char **ret) {
/* This is similar to unit_name_printf() */
const Specifier table[] = {
@ -123,5 +123,5 @@ int install_full_printf(const UnitFileInstallInfo *i, const char *format, char *
assert(format);
assert(ret);
return specifier_printf(format, table, i, ret);
return specifier_printf(format, max_length, table, i, ret);
}

View File

@ -2,5 +2,12 @@
#pragma once
#include "install.h"
#include "unit-name.h"
int install_full_printf(const UnitFileInstallInfo *i, const char *format, char **ret);
int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, char **ret);
static inline int install_name_printf(const UnitFileInstallInfo *i, const char *format, char **ret) {
return install_full_printf_internal(i, format, UNIT_NAME_MAX, ret);
}
static inline int install_path_printf(const UnitFileInstallInfo *i, const char *format, char **ret) {
return install_full_printf_internal(i, format, PATH_MAX-1, ret);
}

View File

@ -1143,7 +1143,7 @@ static int config_parse_also(
if (r == 0)
break;
r = install_full_printf(info, word, &printed);
r = install_name_printf(info, word, &printed);
if (r < 0)
return r;
@ -1190,7 +1190,7 @@ static int config_parse_default_instance(
return log_syntax(unit, LOG_WARNING, filename, line, 0,
"DefaultInstance= only makes sense for template units, ignoring.");
r = install_full_printf(i, rvalue, &printed);
r = install_name_printf(i, rvalue, &printed);
if (r < 0)
return r;
@ -1816,7 +1816,7 @@ static int install_info_symlink_alias(
STRV_FOREACH(s, i->aliases) {
_cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
q = install_full_printf(i, *s, &dst);
q = install_path_printf(i, *s, &dst);
if (q < 0)
return q;
@ -1891,7 +1891,7 @@ static int install_info_symlink_wants(
STRV_FOREACH(s, list) {
_cleanup_free_ char *path = NULL, *dst = NULL;
q = install_full_printf(i, *s, &dst);
q = install_name_printf(i, *s, &dst);
if (q < 0)
return q;

View File

@ -29,9 +29,9 @@
* and "%" used for escaping. */
#define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%"
int specifier_printf(const char *text, const Specifier table[], const void *userdata, char **_ret) {
int specifier_printf(const char *text, size_t max_length, const Specifier table[], const void *userdata, char **ret) {
size_t l, allocated = 0;
_cleanup_free_ char *ret = NULL;
_cleanup_free_ char *result = NULL;
char *t;
const char *f;
bool percent = false;
@ -41,11 +41,11 @@ int specifier_printf(const char *text, const Specifier table[], const void *user
assert(table);
l = strlen(text);
if (!GREEDY_REALLOC(ret, allocated, l + 1))
if (!GREEDY_REALLOC(result, allocated, l + 1))
return -ENOMEM;
t = ret;
t = result;
for (f = text; *f; f++, l--)
for (f = text; *f != '\0'; f++, l--) {
if (percent) {
if (*f == '%')
*(t++) = '%';
@ -64,13 +64,13 @@ int specifier_printf(const char *text, const Specifier table[], const void *user
if (r < 0)
return r;
j = t - ret;
j = t - result;
k = strlen(w);
if (!GREEDY_REALLOC(ret, allocated, j + k + l + 1))
if (!GREEDY_REALLOC(result, allocated, j + k + l + 1))
return -ENOMEM;
memcpy(ret + j, w, k);
t = ret + j + k;
memcpy(result + j, w, k);
t = result + j + k;
} else if (strchr(POSSIBLE_SPECIFIERS, *f))
/* Oops, an unknown specifier. */
return -EBADSLT;
@ -86,19 +86,26 @@ int specifier_printf(const char *text, const Specifier table[], const void *user
else
*(t++) = *f;
if ((size_t) (t - result) > max_length)
return -ENAMETOOLONG;
}
/* If string ended with a stray %, also end with % */
if (percent)
if (percent) {
*(t++) = '%';
if ((size_t) (t - result) > max_length)
return -ENAMETOOLONG;
}
*(t++) = 0;
/* Try to deallocate unused bytes, but don't sweat it too much */
if ((size_t)(t - ret) < allocated) {
t = realloc(ret, t - ret);
if ((size_t)(t - result) < allocated) {
t = realloc(result, t - result);
if (t)
ret = t;
result = t;
}
*_ret = TAKE_PTR(ret);
*ret = TAKE_PTR(result);
return 0;
}
@ -124,7 +131,7 @@ int specifier_machine_id(char specifier, const void *data, const void *userdata,
if (r < 0)
return r;
n = new(char, 33);
n = new(char, SD_ID128_STRING_MAX);
if (!n)
return -ENOMEM;
@ -141,7 +148,7 @@ int specifier_boot_id(char specifier, const void *data, const void *userdata, ch
if (r < 0)
return r;
n = new(char, 33);
n = new(char, SD_ID128_STRING_MAX);
if (!n)
return -ENOMEM;

View File

@ -11,7 +11,7 @@ typedef struct Specifier {
const void *data;
} Specifier;
int specifier_printf(const char *text, const Specifier table[], const void *userdata, char **ret);
int specifier_printf(const char *text, size_t max_length, const Specifier table[], const void *userdata, char **ret);
int specifier_string(char specifier, const void *data, const void *userdata, char **ret);

View File

@ -1210,9 +1210,8 @@ int varlink_close(Varlink *v) {
varlink_set_state(v, VARLINK_DISCONNECTED);
/* Let's take a reference first, since varlink_detach_server() might drop the final ref from the
* disconnect callback, which would invalidate the pointer we are holding before we can call
* varlink_clear(). */
/* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref
* which would destroy us before we can call varlink_clear() */
varlink_ref(v);
varlink_detach_server(v);
varlink_clear(v);
@ -1225,32 +1224,15 @@ Varlink* varlink_close_unref(Varlink *v) {
if (!v)
return NULL;
/* A reference is given to us to be destroyed. But when calling varlink_close(), a callback might
* also drop a reference. We allow this, and will hold a temporary reference to the object to make
* sure that the object still exists when control returns to us. If there's just one reference
* remaining after varlink_close(), even though there were at least two right before, we'll handle
* that gracefully instead of crashing.
*
* In other words, this call drops the donated reference, but if the internal call to varlink_close()
* dropped a reference to, we don't drop the reference afain. This allows the caller to say:
* global_object->varlink = varlink_close_unref(global_object->varlink);
* even though there is some callback which has access to global_object and may drop the reference
* stored in global_object->varlink. Without this step, the same code would have to be written as:
* Varlink *t = TAKE_PTR(global_object->varlink);
* varlink_close_unref(t);
*/
/* n_ref >= 1 */
varlink_ref(v); /* n_ref >= 2 */
varlink_close(v); /* n_ref >= 1 */
if (v->n_ref > 1)
v->n_ref--; /* n_ref >= 1 */
(void) varlink_close(v);
return varlink_unref(v);
}
Varlink* varlink_flush_close_unref(Varlink *v) {
if (v)
varlink_flush(v);
if (!v)
return NULL;
(void) varlink_flush(v);
return varlink_close_unref(v);
}

View File

@ -2,6 +2,7 @@
#include <sys/mount.h>
#include "af-list.h"
#include "bus-error.h"
#include "bus-locator.h"
#include "bus-map-properties.h"
@ -1710,22 +1711,25 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
return 1;
} else if (STR_IN_SET(name, "SocketBindAllow", "SocketBindDeny")) {
uint16_t nr_ports, port_min;
const char *family;
int af;
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(iqq)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(iqq)", &af, &nr_ports, &port_min)) > 0) {
family = af == AF_INET ? "IPv4:" : af == AF_INET6 ? "IPv6:" : "";
const char *family, *colon;
family = strempty(af_to_ipv4_ipv6(af));
colon = isempty(family) ? "" : ":";
if (nr_ports == 0)
bus_print_property_valuef(name, expected_value, flags, "%sany", family);
bus_print_property_valuef(name, expected_value, flags, "%s%sany", family, colon);
else if (nr_ports == 1)
bus_print_property_valuef(
name, expected_value, flags, "%s%hu", family, port_min);
name, expected_value, flags, "%s%s%hu", family, colon, port_min);
else
bus_print_property_valuef(
name, expected_value, flags, "%s%hu-%hu", family, port_min,
name, expected_value, flags, "%s%s%hu-%hu", family, colon, port_min,
(uint16_t) (port_min + nr_ports - 1));
}
if (r < 0)

View File

@ -206,7 +206,7 @@ int sd_dhcp_client_set_fallback_lease_lifetime(
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_client_is_running(const sd_dhcp_client *client);
int sd_dhcp_client_is_running(sd_dhcp_client *client);
int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client);
int sd_dhcp_client_send_release(sd_dhcp_client *client);

View File

@ -46,36 +46,36 @@ typedef enum sd_dhcp_lease_server_type_t {
_SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE),
} sd_dhcp_lease_server_type_t;
int sd_dhcp_lease_get_address(const sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_lifetime(const sd_dhcp_lease *lease, uint32_t *lifetime);
int sd_dhcp_lease_get_t1(const sd_dhcp_lease *lease, uint32_t *t1);
int sd_dhcp_lease_get_t2(const sd_dhcp_lease *lease, uint32_t *t2);
int sd_dhcp_lease_get_broadcast(const sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_netmask(const sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_router(const sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_next_server(const sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_server_identifier(const sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_servers(const sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
int sd_dhcp_lease_get_dns(const sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_ntp(const sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_sip(const sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_pop3(const sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_smtp(const sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_lpr(const sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_mtu(const sd_dhcp_lease *lease, uint16_t *mtu);
int sd_dhcp_lease_get_domainname(const sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_search_domains(const sd_dhcp_lease *lease, char ***domains);
int sd_dhcp_lease_get_hostname(const sd_dhcp_lease *lease, const char **hostname);
int sd_dhcp_lease_get_root_path(const sd_dhcp_lease *lease, const char **root_path);
int sd_dhcp_lease_get_routes(const sd_dhcp_lease *lease, sd_dhcp_route ***routes);
int sd_dhcp_lease_get_vendor_specific(const sd_dhcp_lease *lease, const void **data, size_t *data_len);
int sd_dhcp_lease_get_client_id(const sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
int sd_dhcp_lease_get_timezone(const sd_dhcp_lease *lease, const char **timezone);
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime);
int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1);
int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2);
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes);
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len);
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
int sd_dhcp_route_get_destination(const sd_dhcp_route *route, struct in_addr *destination);
int sd_dhcp_route_get_destination_prefix_length(const sd_dhcp_route *route, uint8_t *length);
int sd_dhcp_route_get_gateway(const sd_dhcp_route *route, struct in_addr *gateway);
int sd_dhcp_route_get_option(const sd_dhcp_route *route);
int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination);
int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length);
int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway);
int sd_dhcp_route_get_option(sd_dhcp_route *route);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref);

View File

@ -73,8 +73,8 @@ int sd_netlink_call(sd_netlink *nl, sd_netlink_message *message, uint64_t timeou
sd_netlink_message **reply);
int sd_netlink_read(sd_netlink *nl, uint32_t serial, uint64_t timeout, sd_netlink_message **reply);
int sd_netlink_get_events(const sd_netlink *nl);
int sd_netlink_get_timeout(const sd_netlink *nl, uint64_t *timeout);
int sd_netlink_get_events(sd_netlink *nl);
int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout);
int sd_netlink_process(sd_netlink *nl, sd_netlink_message **ret);
int sd_netlink_wait(sd_netlink *nl, uint64_t timeout);
@ -137,33 +137,33 @@ sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m);
sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m);
int sd_netlink_message_request_dump(sd_netlink_message *m, int dump);
int sd_netlink_message_is_error(const sd_netlink_message *m);
int sd_netlink_message_get_errno(const sd_netlink_message *m);
int sd_netlink_message_get_type(const sd_netlink_message *m, uint16_t *type);
int sd_netlink_message_is_error(sd_netlink_message *m);
int sd_netlink_message_get_errno(sd_netlink_message *m);
int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type);
int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags);
int sd_netlink_message_is_broadcast(const sd_netlink_message *m);
int sd_netlink_message_is_broadcast(sd_netlink_message *m);
/* rtnl */
int sd_rtnl_message_get_family(const sd_netlink_message *m, int *family);
int sd_rtnl_message_get_family(sd_netlink_message *m, int *family);
int sd_rtnl_message_new_addr(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int family);
int sd_rtnl_message_new_addr_update(sd_netlink *nl, sd_netlink_message **ret, int index, int family);
int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags);
int sd_rtnl_message_addr_get_family(const sd_netlink_message *m, int *family);
int sd_rtnl_message_addr_get_prefixlen(const sd_netlink_message *m, unsigned char *prefixlen);
int sd_rtnl_message_addr_get_scope(const sd_netlink_message *m, unsigned char *scope);
int sd_rtnl_message_addr_get_flags(const sd_netlink_message *m, unsigned char *flags);
int sd_rtnl_message_addr_get_ifindex(const sd_netlink_message *m, int *ifindex);
int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family);
int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen);
int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope);
int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags);
int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex);
int sd_rtnl_message_new_link(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index);
int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change);
int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type);
int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family);
int sd_rtnl_message_link_get_ifindex(const sd_netlink_message *m, int *ifindex);
int sd_rtnl_message_link_get_flags(const sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_link_get_type(const sd_netlink_message *m, unsigned short *type);
int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex);
int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type);
int sd_rtnl_message_new_route(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, int rtm_family, unsigned char rtm_protocol);
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
@ -172,46 +172,46 @@ int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags);
int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table);
int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type);
int sd_rtnl_message_route_get_flags(const sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_route_get_family(const sd_netlink_message *m, int *family);
int sd_rtnl_message_route_get_protocol(const sd_netlink_message *m, unsigned char *protocol);
int sd_rtnl_message_route_get_scope(const sd_netlink_message *m, unsigned char *scope);
int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, unsigned char *tos);
int sd_rtnl_message_route_get_table(const sd_netlink_message *m, unsigned char *table);
int sd_rtnl_message_route_get_dst_prefixlen(const sd_netlink_message *m, unsigned char *dst_len);
int sd_rtnl_message_route_get_src_prefixlen(const sd_netlink_message *m, unsigned char *src_len);
int sd_rtnl_message_route_get_type(const sd_netlink_message *m, unsigned char *type);
int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol);
int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope);
int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos);
int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table);
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len);
int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len);
int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type);
int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nhmsg_type, int nh_family, unsigned char nh_protocol);
int sd_rtnl_message_nexthop_set_flags(sd_netlink_message *m, uint8_t flags);
int sd_rtnl_message_nexthop_get_family(const sd_netlink_message *m, uint8_t *family);
int sd_rtnl_message_nexthop_get_protocol(const sd_netlink_message *m, uint8_t *protocol);
int sd_rtnl_message_nexthop_get_family(sd_netlink_message *m, uint8_t *family);
int sd_rtnl_message_nexthop_get_protocol(sd_netlink_message *m, uint8_t *protocol);
int sd_rtnl_message_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int nda_family);
int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags);
int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state);
int sd_rtnl_message_neigh_get_family(const sd_netlink_message *m, int *family);
int sd_rtnl_message_neigh_get_ifindex(const sd_netlink_message *m, int *index);
int sd_rtnl_message_neigh_get_state(const sd_netlink_message *m, uint16_t *state);
int sd_rtnl_message_neigh_get_flags(const sd_netlink_message *m, uint8_t *flags);
int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family);
int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index);
int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state);
int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags);
int sd_rtnl_message_new_addrlabel(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifindex, int ifal_family);
int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_addrlabel_get_prefixlen(const sd_netlink_message *m, unsigned char *prefixlen);
int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen);
int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family);
int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, uint8_t tos);
int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, uint8_t *tos);
int sd_rtnl_message_routing_policy_rule_get_tos(sd_netlink_message *m, uint8_t *tos);
int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, uint8_t table);
int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, uint8_t *table);
int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, uint8_t *table);
int sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(sd_netlink_message *m, uint8_t len);
int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(const sd_netlink_message *m, uint8_t *len);
int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(sd_netlink_message *m, uint8_t *len);
int sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(sd_netlink_message *m, uint8_t len);
int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(const sd_netlink_message *m, uint8_t *len);
int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(sd_netlink_message *m, uint8_t *len);
int sd_rtnl_message_routing_policy_rule_set_fib_type(sd_netlink_message *m, uint8_t type);
int sd_rtnl_message_routing_policy_rule_get_fib_type(const sd_netlink_message *m, uint8_t *type);
int sd_rtnl_message_routing_policy_rule_get_fib_type(sd_netlink_message *m, uint8_t *type);
int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, uint32_t flags);
int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, uint32_t *flags);
int sd_rtnl_message_routing_policy_rule_get_flags(sd_netlink_message *m, uint32_t *flags);
int sd_rtnl_message_new_qdisc(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int tcm_family, int tcm_ifindex);
int sd_rtnl_message_set_qdisc_parent(sd_netlink_message *m, uint32_t parent);
@ -252,7 +252,7 @@ int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m);
/* genl */
int sd_genl_socket_open(sd_netlink **nl);
int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **m);
int sd_genl_message_get_family(const sd_netlink *nl, const sd_netlink_message *m, sd_genl_family_t *family);
int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *family);
/* slot */
sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *nl);
@ -261,11 +261,11 @@ sd_netlink_slot *sd_netlink_slot_unref(sd_netlink_slot *nl);
sd_netlink *sd_netlink_slot_get_netlink(sd_netlink_slot *slot);
void *sd_netlink_slot_get_userdata(sd_netlink_slot *slot);
void *sd_netlink_slot_set_userdata(sd_netlink_slot *slot, void *userdata);
int sd_netlink_slot_get_destroy_callback(const sd_netlink_slot *slot, sd_netlink_destroy_t *callback);
int sd_netlink_slot_get_destroy_callback(sd_netlink_slot *slot, sd_netlink_destroy_t *callback);
int sd_netlink_slot_set_destroy_callback(sd_netlink_slot *slot, sd_netlink_destroy_t callback);
int sd_netlink_slot_get_floating(const sd_netlink_slot *slot);
int sd_netlink_slot_get_floating(sd_netlink_slot *slot);
int sd_netlink_slot_set_floating(sd_netlink_slot *slot, int b);
int sd_netlink_slot_get_description(const sd_netlink_slot *slot, const char **description);
int sd_netlink_slot_get_description(sd_netlink_slot *slot, const char **description);
int sd_netlink_slot_set_description(sd_netlink_slot *slot, const char *description);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);

View File

@ -1492,7 +1492,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
name = mfree(name);
if (name) {
r = specifier_printf(name, specifier_table, NULL, &resolved_name);
r = specifier_printf(name, NAME_MAX, specifier_table, NULL, &resolved_name);
if (r < 0)
return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, name);
@ -1507,7 +1507,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
id = mfree(id);
if (id) {
r = specifier_printf(id, specifier_table, NULL, &resolved_id);
r = specifier_printf(id, PATH_MAX-1, specifier_table, NULL, &resolved_id);
if (r < 0)
return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, name);
@ -1518,7 +1518,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
description = mfree(description);
if (description) {
r = specifier_printf(description, specifier_table, NULL, &resolved_description);
r = specifier_printf(description, LONG_LINE_MAX, specifier_table, NULL, &resolved_description);
if (r < 0)
return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, description);
@ -1534,7 +1534,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
home = mfree(home);
if (home) {
r = specifier_printf(home, specifier_table, NULL, &resolved_home);
r = specifier_printf(home, PATH_MAX-1, specifier_table, NULL, &resolved_home);
if (r < 0)
return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, home);
@ -1550,7 +1550,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
shell = mfree(shell);
if (shell) {
r = specifier_printf(shell, specifier_table, NULL, &resolved_shell);
r = specifier_printf(shell, PATH_MAX-1, specifier_table, NULL, &resolved_shell);
if (r < 0)
return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, shell);

View File

@ -512,7 +512,7 @@ static void test_install_printf(void) {
_cleanup_free_ char \
*d1 = strdup(i.name), \
*d2 = strdup(i.path); \
assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
assert_se(install_name_printf(&src, pattern, &t) >= 0 || !result); \
memzero(i.name, strlen(i.name)); \
memzero(i.path, strlen(i.path)); \
assert_se(d1 && d2); \

View File

@ -141,8 +141,8 @@ int main(int argc, char *argv[]) {
assert_se(manager_startup(m, NULL, NULL) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("2000"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("IPv6:2001-2002"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("IPv4:6666", "6667"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("ipv6:2001-2002"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("ipv4:6666", "6667"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("6667", "6668", ""), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "7777", STRV_MAKE_EMPTY, STRV_MAKE_EMPTY) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "8888", STRV_MAKE("any"), STRV_MAKE("any")) >= 0);

View File

@ -56,6 +56,38 @@ static const Specifier specifier_table[] = {
{}
};
static void test_specifier_printf(void) {
static const Specifier table[] = {
{ 'X', specifier_string, (char*) "AAAA" },
{ 'Y', specifier_string, (char*) "BBBB" },
COMMON_SYSTEM_SPECIFIERS,
{}
};
_cleanup_free_ char *w = NULL;
int r;
log_info("/* %s */", __func__);
r = specifier_printf("xxx a=%X b=%Y yyy", SIZE_MAX, table, NULL, &w);
assert_se(r >= 0);
assert_se(w);
puts(w);
assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
free(w);
r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", SIZE_MAX, table, NULL, &w);
assert_se(r >= 0);
assert_se(w);
puts(w);
w = mfree(w);
specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", SIZE_MAX, table, NULL, &w);
if (w)
puts(w);
}
static void test_specifiers(void) {
log_info("/* %s */", __func__);
@ -65,7 +97,7 @@ static void test_specifiers(void) {
xsprintf(spec, "%%%c", s->specifier);
assert_se(specifier_printf(spec, specifier_table, NULL, &resolved) >= 0);
assert_se(specifier_printf(spec, SIZE_MAX, specifier_table, NULL, &resolved) >= 0);
log_info("%%%c → %s", s->specifier, resolved);
}
@ -76,6 +108,7 @@ int main(int argc, char *argv[]) {
test_specifier_escape();
test_specifier_escape_strv();
test_specifier_printf();
test_specifiers();
return 0;

View File

@ -3,42 +3,9 @@
#include "alloc-util.h"
#include "escape.h"
#include "nulstr-util.h"
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
static void test_specifier_printf(void) {
static const Specifier table[] = {
{ 'X', specifier_string, (char*) "AAAA" },
{ 'Y', specifier_string, (char*) "BBBB" },
COMMON_SYSTEM_SPECIFIERS,
{}
};
_cleanup_free_ char *w = NULL;
int r;
log_info("/* %s */", __func__);
r = specifier_printf("xxx a=%X b=%Y yyy", table, NULL, &w);
assert_se(r >= 0);
assert_se(w);
puts(w);
assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
free(w);
r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", table, NULL, &w);
assert_se(r >= 0);
assert_se(w);
puts(w);
w = mfree(w);
specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", table, NULL, &w);
if (w)
puts(w);
}
static void test_str_in_set(void) {
log_info("/* %s */", __func__);
@ -1022,7 +989,6 @@ static void test_strv_fnmatch(void) {
}
int main(int argc, char *argv[]) {
test_specifier_printf();
test_str_in_set();
test_strptr_in_set();
test_startswith_set();

View File

@ -2522,7 +2522,7 @@ static int specifier_expansion_from_arg(Item *i) {
if (r < 0)
return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument);
r = specifier_printf(unescaped, specifier_table, NULL, &resolved);
r = specifier_printf(unescaped, PATH_MAX-1, specifier_table, NULL, &resolved);
if (r < 0)
return r;
@ -2532,7 +2532,7 @@ static int specifier_expansion_from_arg(Item *i) {
case SET_XATTR:
case RECURSIVE_SET_XATTR:
STRV_FOREACH(xattr, i->xattrs) {
r = specifier_printf(*xattr, specifier_table, NULL, &resolved);
r = specifier_printf(*xattr, SIZE_MAX, specifier_table, NULL, &resolved);
if (r < 0)
return r;
@ -2706,7 +2706,7 @@ static int parse_line(
i.append_or_force = append_or_force;
i.allow_failure = allow_failure;
r = specifier_printf(path, specifier_table, NULL, &i.path);
r = specifier_printf(path, PATH_MAX-1, specifier_table, NULL, &i.path);
if (r == -ENXIO)
return log_unresolvable_specifier(fname, line);
if (r < 0) {

View File

@ -1,13 +1,13 @@
#!/usr/bin/env bash
set -e
set -eo pipefail
out="$1"
systemd_efi="$2"
boot_stub="$3"
splash_bmp="$4"
if [ -z "$out" -o -z "$systemd_efi" -o -z "$boot_stub" -o -z "$splash_bmp" ]; then
exit 1
fi
out="${1:?}"
systemd_efi="${2:?}"
boot_stub="${3:?}"
splash_bmp="${4:?}"
efi_dir="$(bootctl -p)"
entry_dir="${efi_dir}/$(cat /etc/machine-id)/$(uname -r)"
# create GPT table with EFI System Partition
rm -f "$out"
@ -15,15 +15,17 @@ dd if=/dev/null of="$out" bs=1M seek=512 count=1 status=none
parted --script "$out" "mklabel gpt" "mkpart ESP fat32 1MiB 511MiB" "set 1 boot on"
# create FAT32 file system
LOOP=$(losetup --show -f -P "$out")
mkfs.vfat -F32 ${LOOP}p1
LOOP="$(losetup --show -f -P "$out")"
mkfs.vfat -F32 "${LOOP}p1"
mkdir -p mnt
mount ${LOOP}p1 mnt
mount "${LOOP}p1" mnt
mkdir -p mnt/EFI/{BOOT,systemd}
cp "$systemd_efi" mnt/EFI/BOOT/BOOTX64.efi
[ -e /boot/shellx64.efi ] && cp /boot/shellx64.efi mnt/
if [ -e /boot/shellx64.efi ]; then
cp /boot/shellx64.efi mnt/
fi
mkdir mnt/EFI/Linux
echo -n "foo=yes bar=no root=/dev/fakeroot debug rd.break=initqueue" >mnt/cmdline.txt
@ -31,8 +33,8 @@ objcopy \
--add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \
--add-section .cmdline=mnt/cmdline.txt --change-section-vma .cmdline=0x30000 \
--add-section .splash="$splash_bmp" --change-section-vma .splash=0x40000 \
--add-section .linux=/boot/$(cat /etc/machine-id)/$(uname -r)/linux --change-section-vma .linux=0x2000000 \
--add-section .initrd=/boot/$(cat /etc/machine-id)/$(uname -r)/initrd --change-section-vma .initrd=0x3000000 \
--add-section .linux="${entry_dir}/linux" --change-section-vma .linux=0x2000000 \
--add-section .initrd="${entry_dir}/initrd" --change-section-vma .initrd=0x3000000 \
"$boot_stub" mnt/EFI/Linux/linux-test.efi
# install entries
@ -48,4 +50,4 @@ echo -e "title Test6\nlinux /test6\n" > mnt/loader/entries/test6.conf
sync
umount mnt
rmdir mnt
losetup -d $LOOP
losetup -d "$LOOP"

View File

@ -2784,20 +2784,16 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
expect_up = initial_up
next_up = not expect_up
# if initial expected state is down, must wait for setup_state to reach configuring
# so systemd-networkd considers it 'activated'
setup_state = None if initial_up else 'configuring'
for iteration in range(4):
with self.subTest(iteration=iteration, expect_up=expect_up):
operstate = 'routable' if expect_up else 'off'
setup_state = 'configured' if expect_up else None
self.wait_operstate('test1', operstate, setup_state=setup_state, setup_timeout=20)
setup_state = None
if expect_up:
self.assertIn('UP', check_output('ip link show test1'))
self.assertIn('192.168.10.30/24', check_output('ip address show test1'))
self.assertIn('default via 192.168.10.1', check_output('ip route show'))
self.assertIn('default via 192.168.10.1', check_output('ip route show dev test1'))
else:
self.assertIn('DOWN', check_output('ip link show test1'))
@ -2900,6 +2896,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertEqual(rc, 0)
time.sleep(1)
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output('ip nexthop list dev veth99')
print(output)
self.assertEqual(output, '')
@ -2913,6 +2911,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertEqual(rc, 0)
time.sleep(1)
self.wait_online(['veth99:routable', 'veth-peer:routable'])
rc = call('ip link del veth99')
self.assertEqual(rc, 0)
time.sleep(2)