1
0
mirror of https://github.com/systemd/systemd synced 2026-03-26 16:54:53 +01:00

Compare commits

..

69 Commits

Author SHA1 Message Date
Bastien Nocera
1feeb15a0c hwdb: Allow end-users root-less access to USB analyzers
Procotol analyzers are external devices used to capture traffic over a
wire so that it could be analysed. End-users at the console should be
able to access those devices without requiring root access.

This change obsoletes the need to install Total Phase's "Linux drivers",
which are really just udev rules and hotplug usermap files to do that:
https://www.totalphase.com/products/usb-drivers-linux/
2021-08-30 18:09:36 +02:00
Bastien Nocera
be2c603ecb udev: Import hwdb matches for USB devices
Import hwdb matches for USB devices (not interfaces) which don't usually
have a modalias so that it's possible to, for example, make them
available for unprivileged users.
2021-08-30 18:09:36 +02:00
Yu Watanabe
827d1ba730 core: fix typo: they -> the 2021-08-30 22:25:54 +09:00
Lennart Poettering
aecc04f180 hwdb: remove double empty line in --help text 2021-08-30 22:25:04 +09:00
jlempen
93d2e0b6b0 Add matrix for the Chuwi SurBook Mini (CWI540) 2021-08-30 12:16:52 +02:00
José Expósito
c5e9aeca0a
hwdb: add a generic rule for trackpoints (#20543)
Check for "TrackPoint" in the device name and add the
ID_INPUT_POINTINGSTICK property.

In reference to libinput issue:
https://gitlab.freedesktop.org/libinput/libinput/-/issues/651
2021-08-30 18:30:42 +10:00
Yu Watanabe
4917c15af7
Merge pull request #20057 from yuwata/sd-netlink-genl-cleanups
sd-netlink: cleanups for generic netlink
2021-08-29 22:37:31 +09:00
Yu Watanabe
98be429243 sd-netlink: make type_system_get_*() and friends return value directly 2021-08-29 18:10:47 +09:00
Yu Watanabe
e1578f608b sd-netlink: introduce sd_genl_add_match()
By using this, we can listen multicast messages for generic netlink.
2021-08-29 18:10:47 +09:00
Yu Watanabe
3f60e4488c sd-netlink: split sd_netlink_add_match() into two parts
This also makes netlink_slot_disconnect() correctly unref multicast
groups.
2021-08-29 18:10:47 +09:00
Yu Watanabe
ef90beb1c5 sd-netlink: introduce sd_genl_message_get_command() 2021-08-29 18:10:47 +09:00
Yu Watanabe
44f1072a9d sd-netlink: determine header size of genl message by using CTRL_ATTR_HDRSIZE attribute
Fortunately, all genl families we currently use do not require additional
header size.
2021-08-29 18:10:47 +09:00
Yu Watanabe
52313394ba sd-netlink: read protocol version of each genl family 2021-08-29 18:10:47 +09:00
Yu Watanabe
56fdc16da8 sd-netlink: drop sd_genl_family_t and introduce GenericNetlinkFamily
Kernel manages each genl family by its name, e.g. "nlctrl" or WG_GENL_NAME,
and its ID (used for nlmsg_type) is determined dynamically when the
corresponding module is loaded.

This commit makes sd-netlink follow the same way; now, sd_genl_family_t
is dropped, and sd_genl_message_new() takes a genl family name. Each
genl family is resolved when it is used first time, and its information
is stored in GenericNetlinkFamily.
2021-08-29 18:10:43 +09:00
Yu Watanabe
1cedca05e4 sd-netlink: split message_new() into two parts and introduces message_new_full() 2021-08-29 18:01:26 +09:00
Yu Watanabe
699c3708df sd-netlink: introduce several macros to define type system 2021-08-29 18:01:26 +09:00
Yu Watanabe
e6dd298935 sd-netlink: drop redundant string table lookup functions to handle type system union 2021-08-29 18:01:26 +09:00
Yu Watanabe
fae9ee25a4 sd-netlink: split type system for nfnl
This makes the root type system for nfnl indexed by subsystem, and
itroduces a next level type system for each subsystem. The second
level type systems are indexed by message types correspond to each
subsystem.
2021-08-29 18:01:26 +09:00
Yu Watanabe
07acd0d90b sd-netlink: drop 'flags' argument from sd_nfnl_nft_message_new_table() 2021-08-29 18:01:26 +09:00
Yu Watanabe
c08ab4a013 sd-netlink: wrap long function declarations 2021-08-29 18:01:26 +09:00
Yu Watanabe
9a9c8f3fcc sd-netlink: add several missing attributes 2021-08-29 18:01:26 +09:00
Yu Watanabe
1370925bc7 basic: copy genetlink.h to repository 2021-08-29 18:01:26 +09:00
Yu Watanabe
aee6309b97 sd-netlink: introduce basic_type_system
Preparation for later commits.
2021-08-29 18:01:26 +09:00
Yu Watanabe
d757e6bdf0 sd-netlink: unify two spurious type system root for genl 2021-08-29 18:01:26 +09:00
Yu Watanabe
9270ec60bc sd-netlink: drop genl type system indexed by command
All type systems of currently supported genl families do not depend on
commands. Hence, at least tentatively, let's drop the tables.

Note that type system for genl ethtool depends on commands. Let's
reintroduce a mechanism to support the deps when we support ethtool on
netlink.
2021-08-29 18:01:26 +09:00
Yu Watanabe
e6d58c2f71 sd-netlink: rename several type systems for generic netlink 2021-08-29 18:01:26 +09:00
Yu Watanabe
021273b782 sd-netlink: split netlink-types.[ch] into small files
Also renames several files.
2021-08-29 18:01:22 +09:00
Yu Watanabe
b5beb9b0f5 sd-netlink: make several type systems static 2021-08-29 17:18:11 +09:00
Yu Watanabe
0dac2688a4 sd-netlink: move type systems 2021-08-29 17:18:11 +09:00
Yu Watanabe
b019c545e9 sd-netlink: introduce two helper functions for type system union 2021-08-29 17:18:11 +09:00
Yu Watanabe
ea073c8fce sd-netlink: rename functions 2021-08-29 17:18:04 +09:00
Yu Watanabe
49eb0a6889 sd-netlink: make type_get_type_system{,_union}() return value directly 2021-08-29 17:14:07 +09:00
Yu Watanabe
c737abd31b sd-netlink: make message_seal() accept already sealed messages
The function can be idempotent. It is not necessary to refuse already
sealed messages.
2021-08-29 17:14:07 +09:00
Yu Watanabe
409856d328 sd-netlink: rename variables, arguments, and functions
Most changes are 'rtnl' -> 'nl' where the function is not only for rtnl.
2021-08-29 17:14:03 +09:00
Yu Watanabe
0c45a60f8e test: add usual log messages in test-netlink 2021-08-29 17:11:40 +09:00
Yu Watanabe
9d7fbec1e5 sd-netlink: drop unused type 2021-08-29 17:11:40 +09:00
Lennart Poettering
9c53de8bc5 update TODO 2021-08-28 07:15:12 +02:00
Daan De Meyer
6e5485617e core: Add information on which condition failed to the job done message
When a job is skipped, it's useful to know exactly which condition failed so
let's add this information to the error message.

To avoid having to dynamically generate a format string, we special case the
formatting of condition failed messages.
2021-08-28 06:46:37 +02:00
Lennart Poettering
d52cc0a531 core: Unit's condition_result field is a boolean
Let's only assign boolean values to a boolean variable.

Unit's condition_result is not of type ConditionResult, slightly
confusingly. Let's hence not assign one of ConditionResult's values to
it, but simple booleans.

This effectively doesn't make a difference, since CONDITION_ERROR is
true when cast to bool. But it's still ugly to rely on that. And
confusing.
2021-08-27 21:46:10 +01:00
Kevin Orr
a3a5446b76 Fix another crash due to missing NHDR 2021-08-27 10:01:14 +02:00
Lennart Poettering
fb9bd82443
Merge pull request #20547 from poettering/home-4k
homed: round fs offset and sizes to multiples of 4K
2021-08-27 09:59:44 +02:00
Yu Watanabe
a9cd516f6c
Merge pull request #20553 from weblate/weblate-systemd-master
Translations update from Weblate
2021-08-27 03:09:29 +09:00
Jan Kuparinen
433a610626 po: Translated using Weblate (Finnish)
Currently translated at 9.5% (18 of 189 strings)

Co-authored-by: Jan Kuparinen <copper_fin@hotmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/master/fi/
Translation: systemd/main
2021-08-26 20:05:20 +02:00
Adolfo Jayme Barrientos
18a5c90f29 po: Translated using Weblate (Spanish)
Currently translated at 89.4% (169 of 189 strings)

Co-authored-by: Adolfo Jayme Barrientos <fitoschido@gmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/master/es/
Translation: systemd/main
2021-08-26 20:05:20 +02:00
Lennart Poettering
b8643ee2ea Revert "core: Add information on which condition failed to job skipped format string"
This reverts commit c97bef458b6e59079c9613ec755c1c6513c1c655.
2021-08-27 00:36:07 +09:00
Frantisek Sumsal
061f0084eb cryptsetup: drop an unused variable
This fixes compilation with new-enough libcryptsetup (2.4.0+) & clang:

```
$ CC=clang CXX=clang++ meson build --werror -Dlibcryptsetup-plugins=true
...
$ ninja -C build
...
../src/cryptsetup/cryptsetup-tokens/luks2-fido2.c:23:53: error: unused variable 'v' [-Werror,-Wunused-variable]
        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
...
```
2021-08-26 13:13:08 +01:00
Wind/owZ
f7327a485b hwdb: Add sensor rule for Hometech Wi101
This commit was done to add sensor rule for Hometech Wi101. Note that this rule might be too general and need fixes. I couldn't test this on any other device since this one is the only one I have.

Co-authored-by: Simeonlps <Simeonlps@users.noreply.github.com>
Signed-off-by: Wind/owZ <windowz414@gnuweeb.org>
2021-08-26 10:27:10 +01:00
I-dont-need-name
6f2353a2ce
hwdb: Add force-release for HP Omen 15 calculator key. (#20538)
* Add force-release for HP Omen 15 calculator key.

The key doesn't create release event so I have come up with this fix to make it work properly.
2021-08-26 10:25:32 +01:00
Daan De Meyer
c97bef458b core: Add information on which condition failed to job skipped format string
When a job is skipped, it's useful to know exactly which condition failed so
let's add this information to the error message. Because we now return an
allocated string from job_done_message_format(), make sure we strdup() the
other formats as well so the caller can safely free the string returned by
job_done_message_format().
2021-08-26 10:24:13 +01:00
Tom Yan
c918b70a4d network: default LinkLocalAddresssing= to no for link stacked with a passthru mode MACVLAN/MACVTAP
For similar reason to the case of a bridge slave: we don't want any IP configuration for it.
2021-08-26 06:11:41 +09:00
Yu Watanabe
cacf882ff3
Merge pull request #20541 from yuwata/udev-coalesce-follow-up
udev: follow-ups for coalesce feature support
2021-08-26 06:05:29 +09:00
Yu Watanabe
d11ff2a4f1
Merge pull request #20515 from yuwata/pid1-mount-apivfs-no
pid1: make find_executable() work with MountAPIVFS=no
2021-08-26 06:05:03 +09:00
Yu Watanabe
ebab417cfb
Merge pull request #20531 from DaanDeMeyer/fix-17433
core: Check unit start rate limiting earlier
2021-08-26 06:04:40 +09:00
Lennart Poettering
bf55142a7e update TODO 2021-08-25 22:29:21 +02:00
Lennart Poettering
04190cf1cf homed: always align home file systems to 4K boundaries
Let's carefully align all home file systems to 4K sector boundaries.
It's the safest thing to do, to ensure good perfomance on 4K sector
drives, i.e. today's hardware.

Yes, this means we'll waste 3.5K when resizing home dirs, but I think we
can live with that.

This ensures both the offsets where we start and the sizes of the file
systems/partitions/disk images are multiples of 4K always, both when
creating a new image and when resizing things.

Note that previously we aligned everything to 1024, but weren't quite as
careful.
2021-08-25 22:29:07 +02:00
Yu Watanabe
ee7512404b udev/net: initialize coalesce tristate variables
Otherwise, 99-default.link may introduce something like the
following warnings:
----
Aug 26 03:23:59 systemd-udevd[519]: wlan0: Could not set coalesce settings, ignoring: Operation not supported
Aug 26 03:24:00 systemd-udevd[547]: wlp59s0: Could not set coalesce settings, ignoring: Operation not supported
----

Follow-up for 6c35ea5ef0231d519ff24d43a57a72cebab6a121.
2021-08-26 03:36:18 +09:00
Yu Watanabe
72328a5977 ethtool: move function
I'd like to locate all conf parsers at end of file.
2021-08-26 03:32:39 +09:00
Yu Watanabe
42867dfeef test-execute: add a testcase for MountAPIVFS=no 2021-08-26 02:54:37 +09:00
Daan De Meyer
9727f2427f core: Check unit start rate limiting earlier
Fixes #17433. Currently, if any of the validations we do before we
check start rate limiting fail, we can still enter a busy loop as
no rate limiting gets applied. A common occurence of this scenario
is path units triggering a service that fails a condition check.

To fix the issue, we simply move up start rate limiting checks to
be the first thing we do when starting a unit. To achieve this,
we add a new method to the unit vtable and implement it for the
relevant unit types so that we can do the start rate limit checks
earlier on.
2021-08-25 13:26:14 +01:00
Sho Iizuka
e447ffe4da NEWS: net.ipv4.tcp_ecn = 1 was reverted at v240
Turning on ECN was reverted by 1e190df.
2021-08-25 09:08:23 +01:00
Luca Boccassi
63814220a0
Merge pull request #20530 from keszybz/typos-and-meson
Typos and meson
2021-08-24 21:54:22 +01:00
Daan De Meyer
a243128d1f core: Remove circular include
service.h includes socket.h and socket.h includes service.h. Move
service.h include from socket.h to socket.c to remove the circular
dependency.
2021-08-24 16:19:03 +01:00
Zbigniew Jędrzejewski-Szmek
f064b40ec9 meson: capitalize the last instance of "efi"
All the others in this section use "EFI"…
2021-08-24 15:39:17 +02:00
Zbigniew Jędrzejewski-Szmek
c8cab396a0 man: adjust the description of extension-release.* 2021-08-24 15:39:17 +02:00
Zbigniew Jędrzejewski-Szmek
98579f19e7 docs: adjust sentece, fix minor typo
The verity partition types are per-architecture already, and they contain the
hash data independently of whether we are on a given architecture. (Or in other
words, we would make *use* this partition on some architecture, but the
contents always *exists*.)
2021-08-24 15:39:17 +02:00
Zbigniew Jędrzejewski-Szmek
6a15846d10 man: fix minor grammar issue
The usual: "searched" vs. "searched for".
2021-08-24 14:53:26 +02:00
Yu Watanabe
aa2727517e test-execute: logs can_share flag 2021-08-24 02:04:24 +09:00
Yu Watanabe
93413acd3e path-util: make find_executable() work without /proc mounted
Follow-up for 888f65ace6296ed61285d31db846babf1c11885e.

Hopefully fixes #20514.
2021-08-24 02:04:24 +09:00
Yu Watanabe
ded8039abe path-util: split out common part in find_executable_full() 2021-08-24 02:04:24 +09:00
81 changed files with 3746 additions and 3167 deletions

3
NEWS
View File

@ -3867,6 +3867,9 @@ CHANGES WITH 240:
Consult the kernel documentation for details on this sysctl: Consult the kernel documentation for details on this sysctl:
https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
* The v239 change to turn on "net.ipv4.tcp_ecn" by default has been
reverted.
* CPUAccounting=yes no longer enables the CPU controller when using * CPUAccounting=yes no longer enables the CPU controller when using
kernel 4.15+ and the unified cgroup hierarchy, as required accounting kernel 4.15+ and the unified cgroup hierarchy, as required accounting

76
TODO
View File

@ -83,6 +83,8 @@ Janitorial Clean-ups:
Features: Features:
* PAM: pick auf one authentication token from credentials
* tpm2: figure out if we need to do anything for TPM2 parameter encryption? And * tpm2: figure out if we need to do anything for TPM2 parameter encryption? And
if so, what precisely? if so, what precisely?
@ -92,8 +94,6 @@ Features:
data in the image, make sure the image filename actually matches this, so data in the image, make sure the image filename actually matches this, so
that images cannot be misused. that images cannot be misused.
* use credentials logic/TPM2 logic to store homed signing key
* New udev block device symlink names: * New udev block device symlink names:
/dev/disk/by-parttypelabel/<pttype>/<ptlabel>. Use case: if pt label is used /dev/disk/by-parttypelabel/<pttype>/<ptlabel>. Use case: if pt label is used
as partition image version string, this is a safe way to reference a specific as partition image version string, this is a safe way to reference a specific
@ -1199,48 +1199,36 @@ Features:
- when homed is in use, maybe start the user session manager in a mount namespace with MS_SLAVE, - when homed is in use, maybe start the user session manager in a mount namespace with MS_SLAVE,
so that mounts propagate down but not up - eg, user A setting up a backup volume so that mounts propagate down but not up - eg, user A setting up a backup volume
doesn't mean user B sees it doesn't mean user B sees it
- use credentials logic/TPM2 logic to store homed signing key
* homed: during login resize fs automatically towards size goal. Specifically, - during login resize fs automatically towards size goal. Specifically,
resize to diskSize if possible, but leave a certain amount (configured by a resize to diskSize if possible, but leave a certain amount (configured by a
new value diskLeaveFreeSize) of space free on the backing fs. new value diskLeaveFreeSize) of space free on the backing fs.
- permit multiple user record signing keys to be used locally, and pick
* homed: permit multiple user record signing keys to be used locally, and pick the right one for signing records automatically depending on a pre-existing
the right one for signing records automatically depending on a pre-existing signature
signature - add a way to "adopt" a home directory, i.e. strip foreign signatures
and insert a local signature instead.
* homed: add a way to "adopt" a home directory, i.e. strip foreign signatures - as an extension to the directory+subvolume backend: if located on
and insert a local signature instead. especially marked fs, then sync down password into LUKS header of that fs,
and always verify passwords against it too. Bootstrapping is a problem
* homed: as an extension to the directory+subvolume backend: if located on though: if no one is logged in (or no other user even exists yet), how do you
especially marked fs, then sync down password into LUKS header of that fs, unlock the volume in order to create the first user and add the first pw.
and always verify passwords against it too. Bootstrapping is a problem - support new FS_IOC_ADD_ENCRYPTION_KEY ioctl for setting up fscrypt
though: if no one is logged in (or no other user even exists yet), how do you - maybe pre-create ~/.cache as subvol so that it can have separate quota
unlock the volume in order to create the first user and add the first pw. easily?
- if kernel 5.12 uid mapping mounts exist, use that instead of recursive
* homed: support new FS_IOC_ADD_ENCRYPTION_KEY ioctl for setting up fscrypt chowns.
- add a switch to homectl (maybe called --first-boot) where it will check if
* homed: maybe pre-create ~/.cache as subvol so that it can have separate quota any non-system users exist, and if not prompts interactively for basic user
easily? info, mimicking systemd-firstboot. Then, place this in a service that runs
after systemd-homed, but before gdm and friends, as a simple, barebones
* homed: if kernel 5.12 uid mapping mounts exist, use that instead of recursive fallback logic to get a regular user created on uninitialized systems.
chowns. - store PKCS#11 + FIDO2 token info in LUKS2 header, compatible with
systemd-cryptsetup, so that it can unlock homed volumes
* add a switch to homectl (maybe called --first-boot) where it will check if - try to unmount in regular intervals when home dir was busy when we
any non-system users exist, and if not prompts interactively for basic user tried because idle.
info, mimicking systemd-firstboot. Then, place this in a service that runs - keep an fd to the homedir open at all times, to keep the fs pinned
after systemd-homed, but before gdm and friends, as a simple, barebones (autofs and such) while user is logged in.
fallback logic to get a regular user created on uninitialized systems.
* homed: store PKCS#11 + FIDO2 token info in LUKS2 header, compatible with
systemd-cryptsetup, so that it can unlock homed volumes
* homed: try to unmount in regular intervals when home dir was busy when we
tried because idle.
* homed: keep an fd to the homedir open at all times, to keep the fs pinned
(autofs and such) while user is logged in.
* when we resize disks (homed?) always round up to 4K sectors, not 512K
* add a new switch --auto-definitions=yes/no or so to systemd-repart. If * add a new switch --auto-definitions=yes/no or so to systemd-repart. If
specified, synthesize a definition automatically if we can: enlarge last specified, synthesize a definition automatically if we can: enlarge last

View File

@ -49,7 +49,7 @@ Interface](https://systemd.io/BOOT_LOADER_INTERFACE).
| `77055800-792c-4f94-b39a-98c91b762bb6` | _Root Partition (LoongArch 64-bit)_ | ditto | ditto | | `77055800-792c-4f94-b39a-98c91b762bb6` | _Root Partition (LoongArch 64-bit)_ | ditto | ditto |
| `60d5a7fe-8e7d-435c-b714-3dd8162144e1` | _Root Partition (RISC-V 32-bit)_ | ditto | ditto | | `60d5a7fe-8e7d-435c-b714-3dd8162144e1` | _Root Partition (RISC-V 32-bit)_ | ditto | ditto |
| `72ec70a6-cf74-40e6-bd49-4bda08e8f224` | _Root Partition (RISC-V 64-bit)_ | ditto | ditto | | `72ec70a6-cf74-40e6-bd49-4bda08e8f224` | _Root Partition (RISC-V 64-bit)_ | ditto | ditto |
| `d13c5d3b-b5d1-422a-b29f-9454fdc89d76` | _Root Verity Partition (x86)_ | A dm-verity superblock followed by hash data | On systems with matching architecture, contains dm-verity integrity hash data for the matching root partition. If this feature is used the partition UUID of the root partition should be the first 128bit of the root hash of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the final 128bit of it, so that the root partition and its verity partition can be discovered easily, simply by specifying the root hash. | | `d13c5d3b-b5d1-422a-b29f-9454fdc89d76` | _Root Verity Partition (x86)_ | A dm-verity superblock followed by hash data | Contains dm-verity integrity hash data for the matching root partition. If this feature is used the partition UUID of the root partition should be the first 128 bits of the root hash of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the final 128 bits of it, so that the root partition and its verity partition can be discovered easily, simply by specifying the root hash. |
| `2c7357ed-ebd2-46d9-aec1-23d437ec2bf5` | _Root Verity Partition (x86-64)_ | ditto | ditto | | `2c7357ed-ebd2-46d9-aec1-23d437ec2bf5` | _Root Verity Partition (x86-64)_ | ditto | ditto |
| `7386cdf2-203c-47a9-a498-f2ecce45a2d6` | _Root Verity Partition (32-bit ARM)_ | ditto | ditto | | `7386cdf2-203c-47a9-a498-f2ecce45a2d6` | _Root Verity Partition (32-bit ARM)_ | ditto | ditto |
| `df3300ce-d69f-4c92-978c-9bfb0f38d820` | _Root Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto | | `df3300ce-d69f-4c92-978c-9bfb0f38d820` | _Root Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto |
@ -75,7 +75,7 @@ Interface](https://systemd.io/BOOT_LOADER_INTERFACE).
| `8f1056be-9b05-47c4-81d6-be53128e5b54` | _`/usr/` Verity Partition (RISC-V 64-bit)_ | ditto | ditto | | `8f1056be-9b05-47c4-81d6-be53128e5b54` | _`/usr/` Verity Partition (RISC-V 64-bit)_ | ditto | ditto |
| `933ac7e1-2eb4-4f13-b844-0e14e2aef915` | _Home Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/home`. | | `933ac7e1-2eb4-4f13-b844-0e14e2aef915` | _Home Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/home`. |
| `3b8f8425-20e0-4f3b-907f-1a25a76f98e8` | _Server Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/srv`. | | `3b8f8425-20e0-4f3b-907f-1a25a76f98e8` | _Server Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/srv`. |
| `4d21b016-b534-45c2-a9fb-5c16e091fd2d` | _Variable Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/` — under the condition that its partition UUID matches the first 128 bit of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` (i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). This special requirement is made because `/var/` (unlike the other partition types listed here) is inherently private to a specific installation and cannot possibly be shared between multiple OS installations on the same disk, and thus should be bound to a specific instance of the OS, identified by its machine ID. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`. | | `4d21b016-b534-45c2-a9fb-5c16e091fd2d` | _Variable Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/` — under the condition that its partition UUID matches the first 128 bits of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` (i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). This special requirement is made because `/var/` (unlike the other partition types listed here) is inherently private to a specific installation and cannot possibly be shared between multiple OS installations on the same disk, and thus should be bound to a specific instance of the OS, identified by its machine ID. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`. |
| `7ec6f557-3bc5-4aca-b293-16ef5df639d1` | _Temporary Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/tmp/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/tmp`. Note that the intended mount point is indeed `/var/tmp/`, not `/tmp/`. The latter is typically maintained in memory via <tt>tmpfs</tt> and does not require a partition on disk. In some cases it might be desirable to make `/tmp/` persistent too, in which case it is recommended to make it a symlink or bind mount to `/var/tmp/`, thus not requiring its own partition type UUID. | | `7ec6f557-3bc5-4aca-b293-16ef5df639d1` | _Temporary Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/tmp/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/tmp`. Note that the intended mount point is indeed `/var/tmp/`, not `/tmp/`. The latter is typically maintained in memory via <tt>tmpfs</tt> and does not require a partition on disk. In some cases it might be desirable to make `/tmp/` persistent too, in which case it is recommended to make it a symlink or bind mount to `/var/tmp/`, thus not requiring its own partition type UUID. |
| `0657fd6d-a4ab-43c4-84e5-0933c84b4f4f` | _Swap_ | Swap, optionally in LUKS | All swap partitions on the disk containing the root partition are automatically enabled. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/swap`. This partition type predates the Discoverable Partitions Specification. | | `0657fd6d-a4ab-43c4-84e5-0933c84b4f4f` | _Swap_ | Swap, optionally in LUKS | All swap partitions on the disk containing the root partition are automatically enabled. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/swap`. This partition type predates the Discoverable Partitions Specification. |
| `0fc63daf-8483-4772-8e79-3d69d8477de4` | _Generic Linux Data Partitions_ | Any native, optionally in LUKS | No automatic mounting takes place for other Linux data partitions. This partition type should be used for all partitions that carry Linux file systems. The installer needs to mount them explicitly via entries in <tt>/etc/fstab</tt>. Optionally, these partitions may be encrypted with LUKS. This partition type predates the Discoverable Partitions Specification. | | `0fc63daf-8483-4772-8e79-3d69d8477de4` | _Generic Linux Data Partitions_ | Any native, optionally in LUKS | No automatic mounting takes place for other Linux data partitions. This partition type should be used for all partitions that carry Linux file systems. The installer needs to mount them explicitly via entries in <tt>/etc/fstab</tt>. Optionally, these partitions may be encrypted with LUKS. This partition type predates the Discoverable Partitions Specification. |

View File

@ -709,6 +709,10 @@ evdev:name:gpio-keys:phys:gpio-keys/input0:ev:3:dmi:*:svnHewlett-Packard:pnHPStr
evdev:name:gpio-keys:phys:gpio-keys/input0:ev:23:dmi:*:svnHewlett-Packard:pnHPStream7Tablet:* evdev:name:gpio-keys:phys:gpio-keys/input0:ev:23:dmi:*:svnHewlett-Packard:pnHPStream7Tablet:*
KEYBOARD_KEY_0=unknown KEYBOARD_KEY_0=unknown
# HP Omen 15
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnOMENLaptop15*:pvr*
KEYBOARD_KEY_a1=!calc
########################################################## ##########################################################
# Huawei # Huawei
########################################################## ##########################################################

View File

@ -240,6 +240,10 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:*
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:* sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
# Chuwi SurBook Mini (CWI540)
sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnC3W6_AP108_4GB:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
######################################### #########################################
# Connect # Connect
######################################### #########################################
@ -403,6 +407,16 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd03/20/201
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
ACCEL_LOCATION=base ACCEL_LOCATION=base
#########################################
# Hometech
########################################
# Nobody bothered to use Linux on any device of this manufacturer
# so current marks might be too general and need fixes.
# These values are based on Wi101 model.
sensor:modalias:acpi:BMA250E*:dmi:*:svnInsyde*:pni101c:*
ACCEL_MOUNT_MATRIX=0,1,0;-1,0,0;-1,0,0
######################################### #########################################
# HP # HP
######################################### #########################################

View File

@ -1,31 +0,0 @@
# This file is part of systemd.
#
# Database for protocol analysers that should be accessible to the seat owner
#
# Permitted keys:
# Specify if a device is a protocol analyser
# ID_PROTOCOL_ANALYSER=1|0
###########################################################
# Total Phase
###########################################################
# Aarvark I2C/SPI Host Adapter
usb:v0403pe0d0d*
ID_PROTOCOL_ANALYSER=1
# Beagle Protocol Analyzers
usb:v1679p2001d*
ID_PROTOCOL_ANALYSER=1
# Cheetah SPI Host Adapter
usb:v1679p2002d*
ID_PROTOCOL_ANALYSER=1
# Komodo CAN Duo Interface
usb:v1679p3001d*
ID_PROTOCOL_ANALYSER=1
# Power Delivery Analyzers
usb:v1679p6003d*
usb:v0483pdf11d*
ID_PROTOCOL_ANALYSER=1

31
hwdb.d/70-analyzers.hwdb Normal file
View File

@ -0,0 +1,31 @@
# This file is part of systemd.
#
# Database for protocol analyzers that should be accessible to the seat owner
#
# Permitted keys:
# Specify if a device is a protocol analyzer
# ID_PROTOCOL_ANALYZER=1|0
###########################################################
# Total Phase
###########################################################
# Aarvark I2C/SPI Host Adapter
usb_device:v0403pe0d0*
ID_PROTOCOL_ANALYZER=1
# Beagle Protocol Analyzers
usb_device:v1679p2001*
ID_PROTOCOL_ANALYZER=1
# Cheetah SPI Host Adapter
usb_device:v1679p2002*
ID_PROTOCOL_ANALYZER=1
# Komodo CAN Duo Interface
usb_device:v1679p3001*
ID_PROTOCOL_ANALYZER=1
# Power Delivery Analyzers
usb_device:v1679p6003*
usb_device:v0483pdf11*
ID_PROTOCOL_ANALYZER=1

View File

@ -43,6 +43,7 @@
# udevadm info /dev/input/eventXX. # udevadm info /dev/input/eventXX.
# #
# Allowed properties are: # Allowed properties are:
# ID_INPUT_POINTINGSTICK
# POINTINGSTICK_CONST_ACCEL (deprecated) # POINTINGSTICK_CONST_ACCEL (deprecated)
# POINTINGSTICK_SENSITIVITY # POINTINGSTICK_SENSITIVITY
# #
@ -78,6 +79,12 @@
# Sort by brand, model # Sort by brand, model
##########################################
# Generic
##########################################
evdev:name:*[tT]rack[pP]oint*:*
ID_INPUT_POINTINGSTICK=1
######################################### #########################################
# Dell # Dell
######################################### #########################################

View File

@ -27,7 +27,7 @@ hwdb_files_test = files('''
60-keyboard.hwdb 60-keyboard.hwdb
60-seat.hwdb 60-seat.hwdb
60-sensor.hwdb 60-sensor.hwdb
70-analysers.hwdb 70-analyzers.hwdb
70-joystick.hwdb 70-joystick.hwdb
70-mouse.hwdb 70-mouse.hwdb
70-pointingstick.hwdb 70-pointingstick.hwdb

View File

@ -80,6 +80,7 @@ TYPES = {'mouse': ('usb', 'bluetooth', 'ps2', '*'),
GENERAL_MATCHES = {'acpi', GENERAL_MATCHES = {'acpi',
'bluetooth', 'bluetooth',
'usb', 'usb',
'usb_device',
'pci', 'pci',
'sdio', 'sdio',
'vmbus', 'vmbus',
@ -147,7 +148,7 @@ def property_grammar():
('ID_INPUT_TOUCHPAD', Or((Literal('0'), Literal('1')))), ('ID_INPUT_TOUCHPAD', Or((Literal('0'), Literal('1')))),
('ID_INPUT_TOUCHSCREEN', Or((Literal('0'), Literal('1')))), ('ID_INPUT_TOUCHSCREEN', Or((Literal('0'), Literal('1')))),
('ID_INPUT_TRACKBALL', Or((Literal('0'), Literal('1')))), ('ID_INPUT_TRACKBALL', Or((Literal('0'), Literal('1')))),
('ID_PROTOCOL_ANALYSER', Or((Literal('0'), Literal('1')))), ('ID_PROTOCOL_ANALYZER', Or((Literal('0'), Literal('1')))),
('POINTINGSTICK_SENSITIVITY', INTEGER), ('POINTINGSTICK_SENSITIVITY', INTEGER),
('POINTINGSTICK_CONST_ACCEL', REAL), ('POINTINGSTICK_CONST_ACCEL', REAL),
('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))), ('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))),
@ -207,9 +208,10 @@ def check_matches(groups):
matches = sum((group[0] for group in groups), []) matches = sum((group[0] for group in groups), [])
# This is a partial check. The other cases could be also done, but those # This is a partial check. The other cases could be also done, but those
# two are most commonly wrong. # three are most commonly wrong.
grammars = { 'usb' : 'v' + upperhex_word(4) + Optional('p' + upperhex_word(4)), grammars = { 'usb' : 'v' + upperhex_word(4) + Optional('p' + upperhex_word(4)),
'pci' : 'v' + upperhex_word(8) + Optional('d' + upperhex_word(8)), 'usb_device' : 'v' + upperhex_word(4) + Optional('p' + upperhex_word(4)),
'pci' : 'v' + upperhex_word(8) + Optional('d' + upperhex_word(8)),
} }
for match in matches: for match in matches:

View File

@ -93,30 +93,36 @@
main system. Additionally, the presence of that file means that the system is in the initrd phase. main system. Additionally, the presence of that file means that the system is in the initrd phase.
<filename>/etc/os-release</filename> should be symlinked to <filename>/etc/initrd-release</filename> <filename>/etc/os-release</filename> should be symlinked to <filename>/etc/initrd-release</filename>
(or vice versa), so programs that only look for <filename>/etc/os-release</filename> (as described (or vice versa), so programs that only look for <filename>/etc/os-release</filename> (as described
above) work correctly. The rest of this document that talks about <filename>os-release</filename> above) work correctly.</para>
should be understood to apply to <filename>initrd-release</filename> too.</para>
<para>The rest of this document that talks about <filename>os-release</filename> should be understood
to apply to <filename>initrd-release</filename> too.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title><filename>/usr/lib/extension-release.d/extension-release.<replaceable>IMAGE</replaceable></filename></title> <title><filename>/usr/lib/extension-release.d/extension-release.<replaceable>IMAGE</replaceable></filename></title>
<para><filename>/usr/lib/extension-release.d/extension-release.<replaceable>IMAGE</replaceable></filename> <para><filename>/usr/lib/extension-release.d/extension-release.<replaceable>IMAGE</replaceable></filename>
for extension images plays the same role as <filename>os-release</filename> in the main system, and follows the plays the same role for extension images as <filename>os-release</filename> for the main system, and
same syntax and rules as described in the <ulink url="https://systemd.io/PORTABLE_SERVICES">Portable Services Documentation</ulink>. follows the syntax and rules as described in the <ulink
The purpose of this file is to allow the operating system to correctly match an extension image url="https://systemd.io/PORTABLE_SERVICES">Portable Services Documentation</ulink>. The purpose of this
to a base OS image, This is typically implemented by first checking that the <varname>ID=</varname> file is to identify the extension and to allow the operating system to verify that the extension image
options match, and if they do either <varname>SYSEXT_LEVEL=</varname> has to match too (preferred), or matches the base OS. This is typically implemented by checking that the <varname>ID=</varname> options
as a fallback if that is not present <varname>VERSION_ID=</varname> is checked. This ensures that ABI/API match, and either <varname>SYSEXT_LEVEL=</varname> exists and matches too, or if it is not present,
between the layers matches and no incompatible images are merged in an overlay. <varname>VERSION_ID=</varname> exists and matches. This ensures ABI/API compatibility between the
It is preferred that the <filename>extension-release.<replaceable>IMAGE</replaceable></filename> filename is suffixed layers and prevents merging of an incompatible image in an overlay.</para>
with the exact file name of the image that contains it, so that all such files in every layer of an overlay are visible.
But for the purpose of parsing metadata, in case it is not possible to guarantee that an image file name is stable <para>In the <filename>extension-release.<replaceable>IMAGE</replaceable></filename> filename, the
and doesn't change between the build and the deployment phases, the first and only file which name starts with <replaceable>IMAGE</replaceable> part must exactly match the file name of the containing image with the
<filename>extension-release.</filename>, is located in the same directory and is tagged with a suffix removed. In case it is not possible to guarantee that an image file name is stable and doesn't
<varname>user.extension-release.strict</varname> <citerefentry><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry> change between the build and the deployment phases, it is possible to relax this check: if exactly one
set to the string <literal>0</literal>, will be parsed instead, if the one with the expected name cannot be found. file whose name matches <literal><filename>extension-release.*</filename></literal> is present in this
The rest of this document that talks about <filename>os-release</filename> should be understood to apply to directory, and the file is tagged with a <varname>user.extension-release.strict</varname>
<filename>extension-release</filename> too.</para> <citerefentry><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry> set to the
string <literal>0</literal>, it will be used instead.</para>
<para>The rest of this document that talks about <filename>os-release</filename> should be understood
to apply to <filename>extension-release</filename> too.</para>
</refsect2> </refsect2>
</refsect1> </refsect1>

View File

@ -92,7 +92,7 @@
<para>During boot OS extension images are activated automatically, if the <para>During boot OS extension images are activated automatically, if the
<filename>systemd-sysext.service</filename> is enabled. Note that this service runs only after the <filename>systemd-sysext.service</filename> is enabled. Note that this service runs only after the
underlying file systems where system extensions are searched are mounted. This means they are not underlying file systems where system extensions may be located have been mounted. This means they are not
suitable for shipping resources that are processed by subsystems running in earliest boot. Specifically, suitable for shipping resources that are processed by subsystems running in earliest boot. Specifically,
OS extension images are not suitable for shipping system services or OS extension images are not suitable for shipping system services or
<citerefentry><refentrytitle>systemd-sysusers</refentrytitle><manvolnum>8</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd-sysusers</refentrytitle><manvolnum>8</manvolnum></citerefentry>

View File

@ -427,7 +427,8 @@
has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually
happen in parallel with repeated attempts to acquire a DHCPv4 lease).</para> happen in parallel with repeated attempts to acquire a DHCPv4 lease).</para>
<para>Defaults to <option>no</option> when <varname>Bridge=yes</varname> is set, and <para>Defaults to <option>no</option> when <varname>Bridge=</varname> is set or when the specified
<varname>MACVLAN=</varname>/<varname>MACVTAP=</varname> has <varname>Mode=passthru</varname>, or
<option>ipv6</option> otherwise.</para> <option>ipv6</option> otherwise.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -3830,7 +3830,7 @@ summary({
# LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS} # LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
if conf.get('ENABLE_EFI') == 1 if conf.get('ENABLE_EFI') == 1
summary({'efi arch' : efi_arch}, summary({'EFI arch' : efi_arch},
section : 'Extensible Firmware Interface') section : 'Extensible Firmware Interface')
if have_gnu_efi if have_gnu_efi

180
po/es.po
View File

@ -4,15 +4,15 @@
# Alex Puchades <alex94puchades@gmail.com>, 2015. # Alex Puchades <alex94puchades@gmail.com>, 2015.
# Daniel Mustieles <daniel.mustieles@gmail.com>, 2015. # Daniel Mustieles <daniel.mustieles@gmail.com>, 2015.
# Álex Puchades <alex94puchades@gmail.com>, 2015. # Álex Puchades <alex94puchades@gmail.com>, 2015.
# Adolfo Jayme Barrientos <fitoschido@gmail.com>, 2020. # Adolfo Jayme Barrientos <fitoschido@gmail.com>, 2020, 2021.
# Emilio Herrera <ehespinosa57@gmail.com>, 2021. # Emilio Herrera <ehespinosa57@gmail.com>, 2021.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: systemd master\n" "Project-Id-Version: systemd master\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-08 17:48+0100\n" "POT-Creation-Date: 2021-01-08 17:48+0100\n"
"PO-Revision-Date: 2021-06-08 09:04+0000\n" "PO-Revision-Date: 2021-08-26 18:05+0000\n"
"Last-Translator: Emilio Herrera <ehespinosa57@gmail.com>\n" "Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
"Language-Team: Spanish <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: Spanish <https://translate.fedoraproject.org/projects/systemd/"
"master/es/>\n" "master/es/>\n"
"Language: es\n" "Language: es\n"
@ -20,7 +20,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.6.2\n" "X-Generator: Weblate 4.8\n"
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
@ -96,40 +96,37 @@ msgstr "Comprobar las credenciales de un área home"
msgid "" msgid ""
"Authentication is required to check credentials against a user's home area." "Authentication is required to check credentials against a user's home area."
msgstr "" msgstr ""
"Se requiere autenticación para comprobar las credenciales contra un área " "Necesita autenticarse para comprobar las credenciales del espacio personal "
"home de usuario." "de un usuario."
#: src/home/org.freedesktop.home1.policy:43 #: src/home/org.freedesktop.home1.policy:43
msgid "Update a home area" msgid "Update a home area"
msgstr "Actualizar un área home" msgstr "Actualizar un espacio personal"
#: src/home/org.freedesktop.home1.policy:44 #: src/home/org.freedesktop.home1.policy:44
msgid "Authentication is required to update a user's home area." msgid "Authentication is required to update a user's home area."
msgstr "Se requiere autenticación para actualizar un área home de usuario." msgstr ""
"Necesita autenticarse para actualizar el espacio personal de un usuario."
#: src/home/org.freedesktop.home1.policy:53 #: src/home/org.freedesktop.home1.policy:53
msgid "Resize a home area" msgid "Resize a home area"
msgstr "" msgstr "Redimensionar un espacio personal"
#: src/home/org.freedesktop.home1.policy:54 #: src/home/org.freedesktop.home1.policy:54
#, fuzzy
#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to resize a user's home area." msgid "Authentication is required to resize a user's home area."
msgstr "Se requiere autenticación para establecer un muro de texto" msgstr ""
"Necesita autenticarse para redimensionar el espacio personal de un usuario."
#: src/home/org.freedesktop.home1.policy:63 #: src/home/org.freedesktop.home1.policy:63
msgid "Change password of a home area" msgid "Change password of a home area"
msgstr "" msgstr "Cambiar contraseña de un espacio personal"
#: src/home/org.freedesktop.home1.policy:64 #: src/home/org.freedesktop.home1.policy:64
#, fuzzy
#| msgid ""
#| "Authentication is required to manage active sessions, users and seats."
msgid "" msgid ""
"Authentication is required to change the password of a user's home area." "Authentication is required to change the password of a user's home area."
msgstr "" msgstr ""
"Se requiere autenticación para administrar las sesiones activas, usuarios y " "Necesita autenticarse para cambiar la contraseña del espacio personal de un "
"puestos de trabajo." "usuario."
#: src/hostname/org.freedesktop.hostname1.policy:20 #: src/hostname/org.freedesktop.hostname1.policy:20
msgid "Set hostname" msgid "Set hostname"
@ -161,13 +158,11 @@ msgstr "Necesita autenticarse para establecer la información de sistema local."
#: src/hostname/org.freedesktop.hostname1.policy:51 #: src/hostname/org.freedesktop.hostname1.policy:51
msgid "Get product UUID" msgid "Get product UUID"
msgstr "" msgstr "Obtener UUID del producto"
#: src/hostname/org.freedesktop.hostname1.policy:52 #: src/hostname/org.freedesktop.hostname1.policy:52
#, fuzzy
#| msgid "Authentication is required to reload '$(unit)'."
msgid "Authentication is required to get product UUID." msgid "Authentication is required to get product UUID."
msgstr "Se requiere autenticación para recargar '$(unit)'." msgstr "Necesita autenticarse para obtener el UUID de un producto."
#: src/import/org.freedesktop.import1.policy:22 #: src/import/org.freedesktop.import1.policy:22
msgid "Import a VM or container image" msgid "Import a VM or container image"
@ -582,13 +577,12 @@ msgstr "Necesita autenticarse para bloquear/desbloquear sesiones activas."
#: src/login/org.freedesktop.login1.policy:352 #: src/login/org.freedesktop.login1.policy:352
msgid "Set the reboot \"reason\" in the kernel" msgid "Set the reboot \"reason\" in the kernel"
msgstr "" msgstr "Establecer la «razón» de reinicio en el núcleo"
#: src/login/org.freedesktop.login1.policy:353 #: src/login/org.freedesktop.login1.policy:353
#, fuzzy
#| msgid "Authentication is required to set the system timezone."
msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgid "Authentication is required to set the reboot \"reason\" in the kernel."
msgstr "Se requiere autenticación para establecer la zona horaria del sistema." msgstr ""
"Necesita autenticarse para establecer la «razón» de reinicio en el núcleo."
#: src/login/org.freedesktop.login1.policy:363 #: src/login/org.freedesktop.login1.policy:363
#, fuzzy #, fuzzy
@ -607,35 +601,27 @@ msgstr ""
#: src/login/org.freedesktop.login1.policy:374 #: src/login/org.freedesktop.login1.policy:374
msgid "Indicate to the boot loader to boot to the boot loader menu" msgid "Indicate to the boot loader to boot to the boot loader menu"
msgstr "" msgstr "Indicar al cargador de arranque que inicie el menú de selección"
#: src/login/org.freedesktop.login1.policy:375 #: src/login/org.freedesktop.login1.policy:375
#, fuzzy
#| msgid ""
#| "Authentication is required to indicate to the firmware to boot to setup "
#| "interface."
msgid "" msgid ""
"Authentication is required to indicate to the boot loader to boot to the " "Authentication is required to indicate to the boot loader to boot to the "
"boot loader menu." "boot loader menu."
msgstr "" msgstr ""
"Se requiere autenticación para indicar al firmware que arranque la interfaz " "Necesita autenticarse para indicar al cargador de arranque que inicie el "
"de configuración." "menú de selección."
#: src/login/org.freedesktop.login1.policy:385 #: src/login/org.freedesktop.login1.policy:385
msgid "Indicate to the boot loader to boot a specific entry" msgid "Indicate to the boot loader to boot a specific entry"
msgstr "" msgstr "Indicar al cargador de arranque que inicie una entrada concreta"
#: src/login/org.freedesktop.login1.policy:386 #: src/login/org.freedesktop.login1.policy:386
#, fuzzy
#| msgid ""
#| "Authentication is required to indicate to the firmware to boot to setup "
#| "interface."
msgid "" msgid ""
"Authentication is required to indicate to the boot loader to boot into a " "Authentication is required to indicate to the boot loader to boot into a "
"specific boot loader entry." "specific boot loader entry."
msgstr "" msgstr ""
"Se requiere autenticación para indicar al firmware que arranque la interfaz " "Necesita autenticarse para indicar al cargador de arranque que inicie una "
"de configuración." "entrada concreta."
#: src/login/org.freedesktop.login1.policy:396 #: src/login/org.freedesktop.login1.policy:396
msgid "Set a wall message" msgid "Set a wall message"
@ -647,13 +633,11 @@ msgstr "Necesita autenticarse para establecer un muro de texto"
#: src/login/org.freedesktop.login1.policy:406 #: src/login/org.freedesktop.login1.policy:406
msgid "Change Session" msgid "Change Session"
msgstr "" msgstr "Cambiar sesión"
#: src/login/org.freedesktop.login1.policy:407 #: src/login/org.freedesktop.login1.policy:407
#, fuzzy
#| msgid "Authentication is required to set the local hostname."
msgid "Authentication is required to change the virtual terminal." msgid "Authentication is required to change the virtual terminal."
msgstr "Se requiere autenticación para establecer el nombre del equipo local." msgstr "Necesita autenticarse para cambiar la terminal virtual."
#: src/machine/org.freedesktop.machine1.policy:22 #: src/machine/org.freedesktop.machine1.policy:22
msgid "Log into a local container" msgid "Log into a local container"
@ -665,11 +649,11 @@ msgstr "Necesita autenticarse para conectarse a un contenedor local."
#: src/machine/org.freedesktop.machine1.policy:32 #: src/machine/org.freedesktop.machine1.policy:32
msgid "Log into the local host" msgid "Log into the local host"
msgstr "Conectarse al equipo local" msgstr "Acceder al anfitrión local"
#: src/machine/org.freedesktop.machine1.policy:33 #: src/machine/org.freedesktop.machine1.policy:33
msgid "Authentication is required to log into the local host." msgid "Authentication is required to log into the local host."
msgstr "Necesita autenticarse para conectarse al equipo local." msgstr "Necesita autenticarse para acceder al anfitrión local."
#: src/machine/org.freedesktop.machine1.policy:42 #: src/machine/org.freedesktop.machine1.policy:42
msgid "Acquire a shell in a local container" msgid "Acquire a shell in a local container"
@ -734,173 +718,145 @@ msgstr ""
#: src/network/org.freedesktop.network1.policy:22 #: src/network/org.freedesktop.network1.policy:22
msgid "Set NTP servers" msgid "Set NTP servers"
msgstr "" msgstr "Establecer servidores NTP"
#: src/network/org.freedesktop.network1.policy:23 #: src/network/org.freedesktop.network1.policy:23
#, fuzzy
#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to set NTP servers." msgid "Authentication is required to set NTP servers."
msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." msgstr "Necesita autenticarse para establecer servidores NTP."
#: src/network/org.freedesktop.network1.policy:33 #: src/network/org.freedesktop.network1.policy:33
#: src/resolve/org.freedesktop.resolve1.policy:44 #: src/resolve/org.freedesktop.resolve1.policy:44
msgid "Set DNS servers" msgid "Set DNS servers"
msgstr "" msgstr "Establecer servidores DNS"
#: src/network/org.freedesktop.network1.policy:34 #: src/network/org.freedesktop.network1.policy:34
#: src/resolve/org.freedesktop.resolve1.policy:45 #: src/resolve/org.freedesktop.resolve1.policy:45
#, fuzzy
#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to set DNS servers." msgid "Authentication is required to set DNS servers."
msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." msgstr "Necesita autenticarse para establecer servidores DNS."
#: src/network/org.freedesktop.network1.policy:44 #: src/network/org.freedesktop.network1.policy:44
#: src/resolve/org.freedesktop.resolve1.policy:55 #: src/resolve/org.freedesktop.resolve1.policy:55
msgid "Set domains" msgid "Set domains"
msgstr "" msgstr "Establecer dominios"
#: src/network/org.freedesktop.network1.policy:45 #: src/network/org.freedesktop.network1.policy:45
#: src/resolve/org.freedesktop.resolve1.policy:56 #: src/resolve/org.freedesktop.resolve1.policy:56
#, fuzzy
#| msgid "Authentication is required to stop '$(unit)'."
msgid "Authentication is required to set domains." msgid "Authentication is required to set domains."
msgstr "Se requiere autenticación para detener '$(unit)'." msgstr "Necesita autenticarse para establecer dominios."
#: src/network/org.freedesktop.network1.policy:55 #: src/network/org.freedesktop.network1.policy:55
#: src/resolve/org.freedesktop.resolve1.policy:66 #: src/resolve/org.freedesktop.resolve1.policy:66
msgid "Set default route" msgid "Set default route"
msgstr "" msgstr "Establecer ruta predeterminada"
#: src/network/org.freedesktop.network1.policy:56 #: src/network/org.freedesktop.network1.policy:56
#: src/resolve/org.freedesktop.resolve1.policy:67 #: src/resolve/org.freedesktop.resolve1.policy:67
#, fuzzy
#| msgid "Authentication is required to set the local hostname."
msgid "Authentication is required to set default route." msgid "Authentication is required to set default route."
msgstr "Se requiere autenticación para establecer el nombre del equipo local." msgstr "Necesita autenticarse para establecer la ruta predeterminada."
#: src/network/org.freedesktop.network1.policy:66 #: src/network/org.freedesktop.network1.policy:66
#: src/resolve/org.freedesktop.resolve1.policy:77 #: src/resolve/org.freedesktop.resolve1.policy:77
msgid "Enable/disable LLMNR" msgid "Enable/disable LLMNR"
msgstr "" msgstr "Activar/desactivar LLMNR"
#: src/network/org.freedesktop.network1.policy:67 #: src/network/org.freedesktop.network1.policy:67
#: src/resolve/org.freedesktop.resolve1.policy:78 #: src/resolve/org.freedesktop.resolve1.policy:78
#, fuzzy
#| msgid "Authentication is required to hibernate the system."
msgid "Authentication is required to enable or disable LLMNR." msgid "Authentication is required to enable or disable LLMNR."
msgstr "Se requiere autenticación para hibernar el sistema." msgstr "Necesita autenticarse para activar o desactivar LLMNR."
#: src/network/org.freedesktop.network1.policy:77 #: src/network/org.freedesktop.network1.policy:77
#: src/resolve/org.freedesktop.resolve1.policy:88 #: src/resolve/org.freedesktop.resolve1.policy:88
msgid "Enable/disable multicast DNS" msgid "Enable/disable multicast DNS"
msgstr "" msgstr "Activar/desactivar DNS multidifusión"
#: src/network/org.freedesktop.network1.policy:78 #: src/network/org.freedesktop.network1.policy:78
#: src/resolve/org.freedesktop.resolve1.policy:89 #: src/resolve/org.freedesktop.resolve1.policy:89
#, fuzzy
#| msgid "Authentication is required to log into the local host."
msgid "Authentication is required to enable or disable multicast DNS." msgid "Authentication is required to enable or disable multicast DNS."
msgstr "Se requiere autenticación para conectarse al equipo local." msgstr "Necesita autenticarse para activar o desactivar DNS multidifusión."
#: src/network/org.freedesktop.network1.policy:88 #: src/network/org.freedesktop.network1.policy:88
#: src/resolve/org.freedesktop.resolve1.policy:99 #: src/resolve/org.freedesktop.resolve1.policy:99
msgid "Enable/disable DNS over TLS" msgid "Enable/disable DNS over TLS"
msgstr "" msgstr "Activar/desactivar DNS por TLS"
#: src/network/org.freedesktop.network1.policy:89 #: src/network/org.freedesktop.network1.policy:89
#: src/resolve/org.freedesktop.resolve1.policy:100 #: src/resolve/org.freedesktop.resolve1.policy:100
#, fuzzy
#| msgid "Authentication is required to set the local hostname."
msgid "Authentication is required to enable or disable DNS over TLS." msgid "Authentication is required to enable or disable DNS over TLS."
msgstr "Se requiere autenticación para establecer el nombre del equipo local." msgstr "Necesita autenticarse para activar o desactivar DNS por TLS."
#: src/network/org.freedesktop.network1.policy:99 #: src/network/org.freedesktop.network1.policy:99
#: src/resolve/org.freedesktop.resolve1.policy:110 #: src/resolve/org.freedesktop.resolve1.policy:110
msgid "Enable/disable DNSSEC" msgid "Enable/disable DNSSEC"
msgstr "" msgstr "Activar/desactivar DNSSEC"
#: src/network/org.freedesktop.network1.policy:100 #: src/network/org.freedesktop.network1.policy:100
#: src/resolve/org.freedesktop.resolve1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:111
#, fuzzy
#| msgid "Authentication is required to hibernate the system."
msgid "Authentication is required to enable or disable DNSSEC." msgid "Authentication is required to enable or disable DNSSEC."
msgstr "Se requiere autenticación para hibernar el sistema." msgstr "Necesita autenticarse para activar o desactivar DNSSEC."
#: src/network/org.freedesktop.network1.policy:110 #: src/network/org.freedesktop.network1.policy:110
#: src/resolve/org.freedesktop.resolve1.policy:121 #: src/resolve/org.freedesktop.resolve1.policy:121
msgid "Set DNSSEC Negative Trust Anchors" msgid "Set DNSSEC Negative Trust Anchors"
msgstr "" msgstr "Establecer anclas de confianza negativas de DNSSEC"
#: src/network/org.freedesktop.network1.policy:111 #: src/network/org.freedesktop.network1.policy:111
#: src/resolve/org.freedesktop.resolve1.policy:122 #: src/resolve/org.freedesktop.resolve1.policy:122
#, fuzzy
#| msgid "Authentication is required to set the system locale."
msgid "Authentication is required to set DNSSEC Negative Trust Anchors." msgid "Authentication is required to set DNSSEC Negative Trust Anchors."
msgstr "Se requiere autenticación para establecer la región del sistema." msgstr ""
"Necesita autenticarse para establecer las anclas de confianza negativas de "
"DNSSEC."
#: src/network/org.freedesktop.network1.policy:121 #: src/network/org.freedesktop.network1.policy:121
msgid "Revert NTP settings" msgid "Revert NTP settings"
msgstr "" msgstr "Revertir configuración de NTP"
#: src/network/org.freedesktop.network1.policy:122 #: src/network/org.freedesktop.network1.policy:122
#, fuzzy
#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to reset NTP settings." msgid "Authentication is required to reset NTP settings."
msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." msgstr "Necesita autenticarse para restablecer la configuración de NTP."
#: src/network/org.freedesktop.network1.policy:132 #: src/network/org.freedesktop.network1.policy:132
msgid "Revert DNS settings" msgid "Revert DNS settings"
msgstr "" msgstr "Revertir configuración de DNS"
#: src/network/org.freedesktop.network1.policy:133 #: src/network/org.freedesktop.network1.policy:133
#, fuzzy
#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to reset DNS settings." msgid "Authentication is required to reset DNS settings."
msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." msgstr "Necesita autenticarse para restablecer la configuración de DNS."
#: src/network/org.freedesktop.network1.policy:143 #: src/network/org.freedesktop.network1.policy:143
msgid "DHCP server sends force renew message" msgid "DHCP server sends force renew message"
msgstr "" msgstr "El servidor DCHP envía un mensaje de renovación forzada"
#: src/network/org.freedesktop.network1.policy:144 #: src/network/org.freedesktop.network1.policy:144
#, fuzzy
#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to send force renew message." msgid "Authentication is required to send force renew message."
msgstr "Se requiere autenticación para establecer un muro de texto" msgstr "Necesita autenticarse para enviar el mensaje de renovación forzada."
#: src/network/org.freedesktop.network1.policy:154 #: src/network/org.freedesktop.network1.policy:154
msgid "Renew dynamic addresses" msgid "Renew dynamic addresses"
msgstr "" msgstr "Renovar direcciones dinámicas"
#: src/network/org.freedesktop.network1.policy:155 #: src/network/org.freedesktop.network1.policy:155
#, fuzzy
#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to renew dynamic addresses." msgid "Authentication is required to renew dynamic addresses."
msgstr "Se requiere autenticación para establecer un muro de texto" msgstr "Necesita autenticarse para renovar las direcciones dinámicas."
#: src/network/org.freedesktop.network1.policy:165 #: src/network/org.freedesktop.network1.policy:165
msgid "Reload network settings" msgid "Reload network settings"
msgstr "" msgstr "Recargar configuración de red"
#: src/network/org.freedesktop.network1.policy:166 #: src/network/org.freedesktop.network1.policy:166
#, fuzzy
#| msgid "Authentication is required to reload the systemd state."
msgid "Authentication is required to reload network settings." msgid "Authentication is required to reload network settings."
msgstr "Se requiere autenticación para recargar el estado de systemd." msgstr "Necesita autenticarse para recargar la configuración de red."
#: src/network/org.freedesktop.network1.policy:176 #: src/network/org.freedesktop.network1.policy:176
msgid "Reconfigure network interface" msgid "Reconfigure network interface"
msgstr "" msgstr "Reconfigurar interfaz de red"
#: src/network/org.freedesktop.network1.policy:177 #: src/network/org.freedesktop.network1.policy:177
#, fuzzy
#| msgid "Authentication is required to reboot the system."
msgid "Authentication is required to reconfigure network interface." msgid "Authentication is required to reconfigure network interface."
msgstr "Se requiere autenticación para reiniciar el sistema." msgstr "Necesita autenticarse para reconfigurar la interfaz de red."
#: src/portable/org.freedesktop.portable1.policy:13 #: src/portable/org.freedesktop.portable1.policy:13
msgid "Inspect a portable service image" msgid "Inspect a portable service image"
msgstr "" msgstr "Inspeccionar una imagen de servicio portátil"
#: src/portable/org.freedesktop.portable1.policy:14 #: src/portable/org.freedesktop.portable1.policy:14
#, fuzzy #, fuzzy
@ -912,7 +868,7 @@ msgstr ""
#: src/portable/org.freedesktop.portable1.policy:23 #: src/portable/org.freedesktop.portable1.policy:23
msgid "Attach or detach a portable service image" msgid "Attach or detach a portable service image"
msgstr "" msgstr "Adjuntar o desadjuntar una imagen de servicio portátil"
#: src/portable/org.freedesktop.portable1.policy:24 #: src/portable/org.freedesktop.portable1.policy:24
#, fuzzy #, fuzzy
@ -925,7 +881,7 @@ msgstr ""
#: src/portable/org.freedesktop.portable1.policy:34 #: src/portable/org.freedesktop.portable1.policy:34
msgid "Delete or modify portable service image" msgid "Delete or modify portable service image"
msgstr "" msgstr "Eliminar o modificar imagen de servicio portátil"
#: src/portable/org.freedesktop.portable1.policy:35 #: src/portable/org.freedesktop.portable1.policy:35
#, fuzzy #, fuzzy
@ -938,7 +894,7 @@ msgstr ""
#: src/resolve/org.freedesktop.resolve1.policy:22 #: src/resolve/org.freedesktop.resolve1.policy:22
msgid "Register a DNS-SD service" msgid "Register a DNS-SD service"
msgstr "" msgstr "Registrar un servicio DNS-SD"
#: src/resolve/org.freedesktop.resolve1.policy:23 #: src/resolve/org.freedesktop.resolve1.policy:23
#, fuzzy #, fuzzy
@ -948,7 +904,7 @@ msgstr "Se requiere autenticación para establecer un muro de texto"
#: src/resolve/org.freedesktop.resolve1.policy:33 #: src/resolve/org.freedesktop.resolve1.policy:33
msgid "Unregister a DNS-SD service" msgid "Unregister a DNS-SD service"
msgstr "" msgstr "Desregistrar un servicio DNS-SD"
#: src/resolve/org.freedesktop.resolve1.policy:34 #: src/resolve/org.freedesktop.resolve1.policy:34
#, fuzzy #, fuzzy
@ -958,7 +914,7 @@ msgstr "Se requiere autenticación para establecer un muro de texto"
#: src/resolve/org.freedesktop.resolve1.policy:132 #: src/resolve/org.freedesktop.resolve1.policy:132
msgid "Revert name resolution settings" msgid "Revert name resolution settings"
msgstr "" msgstr "Revertir configuración de resolución de nombres"
#: src/resolve/org.freedesktop.resolve1.policy:133 #: src/resolve/org.freedesktop.resolve1.policy:133
#, fuzzy #, fuzzy

View File

@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: systemd\n" "Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-08 17:48+0100\n" "POT-Creation-Date: 2021-01-08 17:48+0100\n"
"PO-Revision-Date: 2021-08-23 18:04+0000\n" "PO-Revision-Date: 2021-08-26 18:05+0000\n"
"Last-Translator: Jan Kuparinen <copper_fin@hotmail.com>\n" "Last-Translator: Jan Kuparinen <copper_fin@hotmail.com>\n"
"Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/"
"master/fi/>\n" "master/fi/>\n"
@ -20,46 +20,52 @@ msgstr ""
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
msgstr "" msgstr "Lähetä tunnuslause takaisin järjestelmään"
#: src/core/org.freedesktop.systemd1.policy.in:23 #: src/core/org.freedesktop.systemd1.policy.in:23
msgid "" msgid ""
"Authentication is required to send the entered passphrase back to the system." "Authentication is required to send the entered passphrase back to the system."
msgstr "" msgstr ""
"Todennus vaaditaan jotta syötetty tunnuslause lähetetään takaisin "
"järjestelmään."
#: src/core/org.freedesktop.systemd1.policy.in:33 #: src/core/org.freedesktop.systemd1.policy.in:33
msgid "Manage system services or other units" msgid "Manage system services or other units"
msgstr "" msgstr "Hallinnoi järjestelmäpalveluja tai muita yksiköitä"
#: src/core/org.freedesktop.systemd1.policy.in:34 #: src/core/org.freedesktop.systemd1.policy.in:34
msgid "Authentication is required to manage system services or other units." msgid "Authentication is required to manage system services or other units."
msgstr "" msgstr ""
"Todennus vaaditaan järjestelmäpalvelujen tai muiden yksiköiden hallintaan."
#: src/core/org.freedesktop.systemd1.policy.in:43 #: src/core/org.freedesktop.systemd1.policy.in:43
msgid "Manage system service or unit files" msgid "Manage system service or unit files"
msgstr "" msgstr "Hallitse järjestelmäpalvelu- tai yksikkötiedostoja"
#: src/core/org.freedesktop.systemd1.policy.in:44 #: src/core/org.freedesktop.systemd1.policy.in:44
msgid "Authentication is required to manage system service or unit files." msgid "Authentication is required to manage system service or unit files."
msgstr "" msgstr ""
"Todennus vaaditaan järjestelmän palvelu- tai yksikkötiedostojen hallintaan."
#: src/core/org.freedesktop.systemd1.policy.in:54 #: src/core/org.freedesktop.systemd1.policy.in:54
msgid "Set or unset system and service manager environment variables" msgid "Set or unset system and service manager environment variables"
msgstr "" msgstr "Aseta tai poista järjestelmän ja palvelunhallinnan ympäristömuuttujia"
#: src/core/org.freedesktop.systemd1.policy.in:55 #: src/core/org.freedesktop.systemd1.policy.in:55
msgid "" msgid ""
"Authentication is required to set or unset system and service manager " "Authentication is required to set or unset system and service manager "
"environment variables." "environment variables."
msgstr "" msgstr ""
"Todennus vaaditaan järjestelmän ja palvelunhallinnan ympäristömuuttujien "
"asettamiseen tai poistamiseen."
#: src/core/org.freedesktop.systemd1.policy.in:64 #: src/core/org.freedesktop.systemd1.policy.in:64
msgid "Reload the systemd state" msgid "Reload the systemd state"
msgstr "" msgstr "Lataa järjestelmätila uudelleen"
#: src/core/org.freedesktop.systemd1.policy.in:65 #: src/core/org.freedesktop.systemd1.policy.in:65
msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to reload the systemd state."
msgstr "" msgstr "Todennus vaaditaan, jotta järjestelmätila voidaan ladata uudelleen."
#: src/home/org.freedesktop.home1.policy:13 #: src/home/org.freedesktop.home1.policy:13
msgid "Create a home area" msgid "Create a home area"
@ -67,24 +73,25 @@ msgstr "Luo kotialue"
#: src/home/org.freedesktop.home1.policy:14 #: src/home/org.freedesktop.home1.policy:14
msgid "Authentication is required to create a user's home area." msgid "Authentication is required to create a user's home area."
msgstr "" msgstr "Todennus vaaditaan käyttäjän kotialueen luomiseksi."
#: src/home/org.freedesktop.home1.policy:23 #: src/home/org.freedesktop.home1.policy:23
msgid "Remove a home area" msgid "Remove a home area"
msgstr "" msgstr "Poista kotialue"
#: src/home/org.freedesktop.home1.policy:24 #: src/home/org.freedesktop.home1.policy:24
msgid "Authentication is required to remove a user's home area." msgid "Authentication is required to remove a user's home area."
msgstr "" msgstr "Todennus vaaditaan käyttäjän kotialueen poistamiseksi."
#: src/home/org.freedesktop.home1.policy:33 #: src/home/org.freedesktop.home1.policy:33
msgid "Check credentials of a home area" msgid "Check credentials of a home area"
msgstr "" msgstr "Tarkista kotialueen valtuudet"
#: src/home/org.freedesktop.home1.policy:34 #: src/home/org.freedesktop.home1.policy:34
msgid "" msgid ""
"Authentication is required to check credentials against a user's home area." "Authentication is required to check credentials against a user's home area."
msgstr "" msgstr ""
"Todennus vaaditaan, jotta käyttäjän kotialueen valtuuksia voi tarkistaa."
#: src/home/org.freedesktop.home1.policy:43 #: src/home/org.freedesktop.home1.policy:43
msgid "Update a home area" msgid "Update a home area"

View File

@ -12,6 +12,7 @@ SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}" ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="hwdb 'usb_device:v$attr{idVendor}p$attr{idProduct}:name:$attr{product}:'"
ACTION!="add", GOTO="default_end" ACTION!="add", GOTO="default_end"

102
src/basic/linux/genetlink.h Normal file
View File

@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI__LINUX_GENERIC_NETLINK_H
#define _UAPI__LINUX_GENERIC_NETLINK_H
#include <linux/types.h>
#include <linux/netlink.h>
#define GENL_NAMSIZ 16 /* length of family name */
#define GENL_MIN_ID NLMSG_MIN_TYPE
#define GENL_MAX_ID 1023
struct genlmsghdr {
__u8 cmd;
__u8 version;
__u16 reserved;
};
#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
#define GENL_ADMIN_PERM 0x01
#define GENL_CMD_CAP_DO 0x02
#define GENL_CMD_CAP_DUMP 0x04
#define GENL_CMD_CAP_HASPOL 0x08
#define GENL_UNS_ADMIN_PERM 0x10
/*
* List of reserved static generic netlink identifiers:
*/
#define GENL_ID_CTRL NLMSG_MIN_TYPE
#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1)
#define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2)
/* must be last reserved + 1 */
#define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3)
/**************************************************************************
* Controller
**************************************************************************/
enum {
CTRL_CMD_UNSPEC,
CTRL_CMD_NEWFAMILY,
CTRL_CMD_DELFAMILY,
CTRL_CMD_GETFAMILY,
CTRL_CMD_NEWOPS,
CTRL_CMD_DELOPS,
CTRL_CMD_GETOPS,
CTRL_CMD_NEWMCAST_GRP,
CTRL_CMD_DELMCAST_GRP,
CTRL_CMD_GETMCAST_GRP, /* unused */
CTRL_CMD_GETPOLICY,
__CTRL_CMD_MAX,
};
#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
enum {
CTRL_ATTR_UNSPEC,
CTRL_ATTR_FAMILY_ID,
CTRL_ATTR_FAMILY_NAME,
CTRL_ATTR_VERSION,
CTRL_ATTR_HDRSIZE,
CTRL_ATTR_MAXATTR,
CTRL_ATTR_OPS,
CTRL_ATTR_MCAST_GROUPS,
CTRL_ATTR_POLICY,
CTRL_ATTR_OP_POLICY,
CTRL_ATTR_OP,
__CTRL_ATTR_MAX,
};
#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
enum {
CTRL_ATTR_OP_UNSPEC,
CTRL_ATTR_OP_ID,
CTRL_ATTR_OP_FLAGS,
__CTRL_ATTR_OP_MAX,
};
#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
enum {
CTRL_ATTR_MCAST_GRP_UNSPEC,
CTRL_ATTR_MCAST_GRP_NAME,
CTRL_ATTR_MCAST_GRP_ID,
__CTRL_ATTR_MCAST_GRP_MAX,
};
enum {
CTRL_ATTR_POLICY_UNSPEC,
CTRL_ATTR_POLICY_DO,
CTRL_ATTR_POLICY_DUMP,
__CTRL_ATTR_POLICY_DUMP_MAX,
CTRL_ATTR_POLICY_DUMP_MAX = __CTRL_ATTR_POLICY_DUMP_MAX - 1
};
#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
#endif /* _UAPI__LINUX_GENERIC_NETLINK_H */

View File

@ -83,6 +83,7 @@ basic_sources = files('''
linux/can/vxcan.h linux/can/vxcan.h
linux/fib_rules.h linux/fib_rules.h
linux/fou.h linux/fou.h
linux/genetlink.h
linux/hdlc/ioctl.h linux/hdlc/ioctl.h
linux/if.h linux/if.h
linux/if_addr.h linux/if_addr.h

View File

@ -630,9 +630,52 @@ static int check_x_access(const char *path, int *ret_fd) {
return r; return r;
r = access_fd(fd, X_OK); r = access_fd(fd, X_OK);
if (r == -ENOSYS) {
/* /proc is not mounted. Fallback to access(). */
if (access(path, X_OK) < 0)
return -errno;
} else if (r < 0)
return r;
if (ret_fd)
*ret_fd = TAKE_FD(fd);
return 0;
}
static int find_executable_impl(const char *name, const char *root, char **ret_filename, int *ret_fd) {
_cleanup_close_ int fd = -1;
_cleanup_free_ char *path_name = NULL;
int r;
assert(name);
/* Function chase_symlinks() is invoked only when root is not NULL, as using it regardless of
* root value would alter the behavior of existing callers for example: /bin/sleep would become
* /usr/bin/sleep when find_executables is called. Hence, this function should be invoked when
* needed to avoid unforeseen regression or other complicated changes. */
if (root) {
r = chase_symlinks(name,
root,
CHASE_PREFIX_ROOT,
&path_name,
/* ret_fd= */ NULL); /* prefix root to name in case full paths are not specified */
if (r < 0)
return r;
name = path_name;
}
r = check_x_access(name, ret_fd ? &fd : NULL);
if (r < 0) if (r < 0)
return r; return r;
if (ret_filename) {
r = path_make_absolute_cwd(name, ret_filename);
if (r < 0)
return r;
}
if (ret_fd) if (ret_fd)
*ret_fd = TAKE_FD(fd); *ret_fd = TAKE_FD(fd);
@ -645,43 +688,8 @@ int find_executable_full(const char *name, const char *root, bool use_path_envva
assert(name); assert(name);
if (is_path(name)) { if (is_path(name))
_cleanup_close_ int fd = -1; return find_executable_impl(name, root, ret_filename, ret_fd);
_cleanup_free_ char *path_name = NULL;
/* Function chase_symlinks() is invoked only when root is not NULL,
* as using it regardless of root value would alter the behavior
* of existing callers for example: /bin/sleep would become
* /usr/bin/sleep when find_executables is called. Hence, this function
* should be invoked when needed to avoid unforeseen regression or other
* complicated changes. */
if (root) {
r = chase_symlinks(name,
root,
CHASE_PREFIX_ROOT,
&path_name,
/* ret_fd= */ NULL); /* prefix root to name in case full paths are not specified */
if (r < 0)
return r;
name = path_name;
}
r = check_x_access(name, ret_fd ? &fd : NULL);
if (r < 0)
return r;
if (ret_filename) {
r = path_make_absolute_cwd(name, ret_filename);
if (r < 0)
return r;
}
if (ret_fd)
*ret_fd = TAKE_FD(fd);
return 0;
}
if (use_path_envvar) if (use_path_envvar)
/* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the /* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the
@ -695,7 +703,6 @@ int find_executable_full(const char *name, const char *root, bool use_path_envva
/* Resolve a single-component name to a full path */ /* Resolve a single-component name to a full path */
for (;;) { for (;;) {
_cleanup_free_ char *element = NULL; _cleanup_free_ char *element = NULL;
_cleanup_close_ int fd = -1;
r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS); r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0) if (r < 0)
@ -709,24 +716,7 @@ int find_executable_full(const char *name, const char *root, bool use_path_envva
if (!path_extend(&element, name)) if (!path_extend(&element, name))
return -ENOMEM; return -ENOMEM;
if (root) { r = find_executable_impl(element, root, ret_filename, ret_fd);
char *path_name;
r = chase_symlinks(element,
root,
CHASE_PREFIX_ROOT,
&path_name,
/* ret_fd= */ NULL);
if (r < 0) {
if (r != -EACCES)
last_error = r;
continue;
}
free_and_replace(element, path_name);
}
r = check_x_access(element, ret_fd ? &fd : NULL);
if (r < 0) { if (r < 0) {
/* PATH entries which we don't have access to are ignored, as per tradition. */ /* PATH entries which we don't have access to are ignored, as per tradition. */
if (r != -EACCES) if (r != -EACCES)
@ -735,11 +725,6 @@ int find_executable_full(const char *name, const char *root, bool use_path_envva
} }
/* Found it! */ /* Found it! */
if (ret_filename)
*ret_filename = path_simplify(TAKE_PTR(element));
if (ret_fd)
*ret_fd = TAKE_FD(fd);
return 0; return 0;
} }

View File

@ -813,12 +813,6 @@ static int automount_start(Unit *u) {
if (r < 0) if (r < 0)
return r; return r;
r = unit_test_start_limit(u);
if (r < 0) {
automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
return r;
}
r = unit_acquire_invocation_id(u); r = unit_acquire_invocation_id(u);
if (r < 0) if (r < 0)
return r; return r;
@ -1064,6 +1058,21 @@ static bool automount_supported(void) {
return supported; return supported;
} }
static int automount_test_start_limit(Unit *u) {
Automount *a = AUTOMOUNT(u);
int r;
assert(a);
r = unit_test_start_limit(u);
if (r < 0) {
automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
return r;
}
return 0;
}
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success", [AUTOMOUNT_SUCCESS] = "success",
[AUTOMOUNT_FAILURE_RESOURCES] = "resources", [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
@ -1126,4 +1135,6 @@ const UnitVTable automount_vtable = {
[JOB_FAILED] = "Failed to unset automount %s.", [JOB_FAILED] = "Failed to unset automount %s.",
}, },
}, },
.test_start_limit = automount_test_start_limit,
}; };

View File

@ -705,19 +705,51 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult
if (!console_only) { /* Skip printing if output goes to the console, and job_print_status_message() if (!console_only) { /* Skip printing if output goes to the console, and job_print_status_message()
* will actually print something to the console. */ * will actually print something to the console. */
Condition *c;
const char *mid = job_done_mid(t, result); /* mid may be NULL. log_unit_struct() will ignore it. */ const char *mid = job_done_mid(t, result); /* mid may be NULL. log_unit_struct() will ignore it. */
const char *msg_fmt = strjoina("MESSAGE=", format);
DISABLE_WARNING_FORMAT_NONLITERAL; c = t == JOB_START && result == JOB_DONE ? unit_find_failed_condition(u) : NULL;
log_unit_struct(u, job_done_messages[result].log_level, if (c) {
msg_fmt, ident, /* Special case units that were skipped because of a failed condition check so that
"JOB_ID=%" PRIu32, job_id, * we can add more information to the message. */
"JOB_TYPE=%s", job_type_to_string(t), if (c->trigger)
"JOB_RESULT=%s", job_result_to_string(result), log_unit_struct(
LOG_UNIT_INVOCATION_ID(u), u,
mid); job_done_messages[result].log_level,
REENABLE_WARNING; "MESSAGE=%s was skipped because all trigger condition checks failed.",
ident,
"JOB_ID=%" PRIu32, job_id,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_INVOCATION_ID(u),
mid);
else
log_unit_struct(
u,
job_done_messages[result].log_level,
"MESSAGE=%s was skipped because of a failed condition check (%s=%s%s).",
ident,
condition_type_to_string(c->type),
c->negate ? "!" : "",
c->parameter,
"JOB_ID=%" PRIu32, job_id,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_INVOCATION_ID(u),
mid);
} else {
const char *msg_fmt = strjoina("MESSAGE=", format);
DISABLE_WARNING_FORMAT_NONLITERAL;
log_unit_struct(u, job_done_messages[result].log_level,
msg_fmt, ident,
"JOB_ID=%" PRIu32, job_id,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_INVOCATION_ID(u),
mid);
REENABLE_WARNING;
}
} }
if (do_console) { if (do_console) {

View File

@ -4115,7 +4115,7 @@ static void manager_unref_uid_internal(
/* A generic implementation, covering both manager_unref_uid() and manager_unref_gid(), under the assumption /* A generic implementation, covering both manager_unref_uid() and manager_unref_gid(), under the assumption
* that uid_t and gid_t are actually defined the same way, with the same validity rules. * that uid_t and gid_t are actually defined the same way, with the same validity rules.
* *
* We store a hashmap where the UID/GID is they key and the value is a 32bit reference counter, whose highest * We store a hashmap where the key is the UID/GID and the value is a 32bit reference counter, whose highest
* bit is used as flag for marking UIDs/GIDs whose IPC objects to remove when the last reference to the UID/GID * bit is used as flag for marking UIDs/GIDs whose IPC objects to remove when the last reference to the UID/GID
* is dropped. The flag is set to on, once at least one reference from a unit where RemoveIPC= is set is added * is dropped. The flag is set to on, once at least one reference from a unit where RemoveIPC= is set is added
* on a UID/GID. It is reset when the UID's/GID's reference counter drops to 0 again. */ * on a UID/GID. It is reset when the UID's/GID's reference counter drops to 0 again. */

View File

@ -1167,12 +1167,6 @@ static int mount_start(Unit *u) {
assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED)); assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED));
r = unit_test_start_limit(u);
if (r < 0) {
mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
return r;
}
r = unit_acquire_invocation_id(u); r = unit_acquire_invocation_id(u);
if (r < 0) if (r < 0)
return r; return r;
@ -2138,6 +2132,21 @@ static int mount_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&m->exec_context, ret); return exec_context_get_clean_mask(&m->exec_context, ret);
} }
static int mount_test_start_limit(Unit *u) {
Mount *m = MOUNT(u);
int r;
assert(m);
r = unit_test_start_limit(u);
if (r < 0) {
mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
return r;
}
return 0;
}
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
@ -2235,4 +2244,6 @@ const UnitVTable mount_vtable = {
[JOB_TIMEOUT] = "Timed out unmounting %s.", [JOB_TIMEOUT] = "Timed out unmounting %s.",
}, },
}, },
.test_start_limit = mount_test_start_limit,
}; };

View File

@ -590,12 +590,6 @@ static int path_start(Unit *u) {
if (r < 0) if (r < 0)
return r; return r;
r = unit_test_start_limit(u);
if (r < 0) {
path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
return r;
}
r = unit_acquire_invocation_id(u); r = unit_acquire_invocation_id(u);
if (r < 0) if (r < 0)
return r; return r;
@ -812,6 +806,21 @@ static void path_reset_failed(Unit *u) {
p->result = PATH_SUCCESS; p->result = PATH_SUCCESS;
} }
static int path_test_start_limit(Unit *u) {
Path *p = PATH(u);
int r;
assert(p);
r = unit_test_start_limit(u);
if (r < 0) {
path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
return r;
}
return 0;
}
static const char* const path_type_table[_PATH_TYPE_MAX] = { static const char* const path_type_table[_PATH_TYPE_MAX] = {
[PATH_EXISTS] = "PathExists", [PATH_EXISTS] = "PathExists",
[PATH_EXISTS_GLOB] = "PathExistsGlob", [PATH_EXISTS_GLOB] = "PathExistsGlob",
@ -866,4 +875,6 @@ const UnitVTable path_vtable = {
.reset_failed = path_reset_failed, .reset_failed = path_reset_failed,
.bus_set_property = bus_path_set_property, .bus_set_property = bus_path_set_property,
.test_start_limit = path_test_start_limit,
}; };

View File

@ -2436,13 +2436,6 @@ static int service_start(Unit *u) {
assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)); assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
/* Make sure we don't enter a busy loop of some kind. */
r = unit_test_start_limit(u);
if (r < 0) {
service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
return r;
}
r = unit_acquire_invocation_id(u); r = unit_acquire_invocation_id(u);
if (r < 0) if (r < 0)
return r; return r;
@ -4445,6 +4438,22 @@ static const char *service_finished_job(Unit *u, JobType t, JobResult result) {
return NULL; return NULL;
} }
static int service_test_start_limit(Unit *u) {
Service *s = SERVICE(u);
int r;
assert(s);
/* Make sure we don't enter a busy loop of some kind. */
r = unit_test_start_limit(u);
if (r < 0) {
service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
return r;
}
return 0;
}
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
[SERVICE_RESTART_NO] = "no", [SERVICE_RESTART_NO] = "no",
[SERVICE_RESTART_ON_SUCCESS] = "on-success", [SERVICE_RESTART_ON_SUCCESS] = "on-success",
@ -4608,4 +4617,6 @@ const UnitVTable service_vtable = {
}, },
.finished_job = service_finished_job, .finished_job = service_finished_job,
}, },
.test_start_limit = service_test_start_limit,
}; };

View File

@ -34,6 +34,7 @@
#include "process-util.h" #include "process-util.h"
#include "selinux-util.h" #include "selinux-util.h"
#include "serialize.h" #include "serialize.h"
#include "service.h"
#include "signal-util.h" #include "signal-util.h"
#include "smack-util.h" #include "smack-util.h"
#include "socket.h" #include "socket.h"
@ -2512,12 +2513,6 @@ static int socket_start(Unit *u) {
assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED)); assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED));
r = unit_test_start_limit(u);
if (r < 0) {
socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
return r;
}
r = unit_acquire_invocation_id(u); r = unit_acquire_invocation_id(u);
if (r < 0) if (r < 0)
return r; return r;
@ -3424,6 +3419,21 @@ static int socket_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&s->exec_context, ret); return exec_context_get_clean_mask(&s->exec_context, ret);
} }
static int socket_test_start_limit(Unit *u) {
Socket *s = SOCKET(u);
int r;
assert(s);
r = unit_test_start_limit(u);
if (r < 0) {
socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
return r;
}
return 0;
}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "ExecStartPre", [SOCKET_EXEC_START_PRE] = "ExecStartPre",
[SOCKET_EXEC_START_CHOWN] = "ExecStartChown", [SOCKET_EXEC_START_CHOWN] = "ExecStartChown",
@ -3550,4 +3560,6 @@ const UnitVTable socket_vtable = {
[JOB_TIMEOUT] = "Timed out stopping %s.", [JOB_TIMEOUT] = "Timed out stopping %s.",
}, },
}, },
.test_start_limit = socket_test_start_limit,
}; };

View File

@ -5,7 +5,6 @@ typedef struct Socket Socket;
typedef struct SocketPeer SocketPeer; typedef struct SocketPeer SocketPeer;
#include "mount.h" #include "mount.h"
#include "service.h"
#include "socket-util.h" #include "socket-util.h"
#include "unit.h" #include "unit.h"

View File

@ -932,12 +932,6 @@ static int swap_start(Unit *u) {
if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING) if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
return -EAGAIN; return -EAGAIN;
r = unit_test_start_limit(u);
if (r < 0) {
swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
return r;
}
r = unit_acquire_invocation_id(u); r = unit_acquire_invocation_id(u);
if (r < 0) if (r < 0)
return r; return r;
@ -1588,6 +1582,21 @@ static int swap_can_clean(Unit *u, ExecCleanMask *ret) {
return exec_context_get_clean_mask(&s->exec_context, ret); return exec_context_get_clean_mask(&s->exec_context, ret);
} }
static int swap_test_start_limit(Unit *u) {
Swap *s = SWAP(u);
int r;
assert(s);
r = unit_test_start_limit(u);
if (r < 0) {
swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
return r;
}
return 0;
}
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
[SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_ACTIVATE] = "ExecActivate",
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
@ -1683,4 +1692,6 @@ const UnitVTable swap_vtable = {
[JOB_TIMEOUT] = "Timed out deactivating swap %s.", [JOB_TIMEOUT] = "Timed out deactivating swap %s.",
}, },
}, },
.test_start_limit = swap_test_start_limit,
}; };

View File

@ -627,12 +627,6 @@ static int timer_start(Unit *u) {
if (r < 0) if (r < 0)
return r; return r;
r = unit_test_start_limit(u);
if (r < 0) {
timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
return r;
}
r = unit_acquire_invocation_id(u); r = unit_acquire_invocation_id(u);
if (r < 0) if (r < 0)
return r; return r;
@ -890,6 +884,21 @@ static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
return 0; return 0;
} }
static int timer_test_start_limit(Unit *u) {
Timer *t = TIMER(u);
int r;
assert(t);
r = unit_test_start_limit(u);
if (r < 0) {
timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
return r;
}
return 0;
}
static const char* const timer_base_table[_TIMER_BASE_MAX] = { static const char* const timer_base_table[_TIMER_BASE_MAX] = {
[TIMER_ACTIVE] = "OnActiveSec", [TIMER_ACTIVE] = "OnActiveSec",
[TIMER_BOOT] = "OnBootSec", [TIMER_BOOT] = "OnBootSec",
@ -949,4 +958,6 @@ const UnitVTable timer_vtable = {
.timezone_change = timer_timezone_change, .timezone_change = timer_timezone_change,
.bus_set_property = bus_timer_set_property, .bus_set_property = bus_timer_set_property,
.test_start_limit = timer_test_start_limit,
}; };

View File

@ -1727,7 +1727,7 @@ static bool unit_test_condition(Unit *u) {
r = manager_get_effective_environment(u->manager, &env); r = manager_get_effective_environment(u->manager, &env);
if (r < 0) { if (r < 0) {
log_unit_error_errno(u, r, "Failed to determine effective environment: %m"); log_unit_error_errno(u, r, "Failed to determine effective environment: %m");
u->condition_result = CONDITION_ERROR; u->condition_result = true;
} else } else
u->condition_result = condition_test_list( u->condition_result = condition_test_list(
u->conditions, u->conditions,
@ -1857,6 +1857,13 @@ int unit_start(Unit *u) {
assert(u); assert(u);
/* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
if (UNIT_VTABLE(u)->test_start_limit) {
int r = UNIT_VTABLE(u)->test_start_limit(u);
if (r < 0)
return r;
}
/* If this is already started, then this will succeed. Note that this will even succeed if this unit /* If this is already started, then this will succeed. Note that this will even succeed if this unit
* is not startable by the user. This is relied on to detect when we need to wait for units and when * is not startable by the user. This is relied on to detect when we need to wait for units and when
* waiting is finished. */ * waiting is finished. */
@ -5841,6 +5848,25 @@ int unit_thaw_vtable_common(Unit *u) {
return unit_cgroup_freezer_action(u, FREEZER_THAW); return unit_cgroup_freezer_action(u, FREEZER_THAW);
} }
Condition *unit_find_failed_condition(Unit *u) {
Condition *c, *failed_trigger = NULL;
bool has_succeeded_trigger = false;
if (u->condition_result)
return NULL;
LIST_FOREACH(conditions, c, u->conditions)
if (c->trigger) {
if (c->result == CONDITION_SUCCEEDED)
has_succeeded_trigger = true;
else if (!failed_trigger)
failed_trigger = c;
} else if (c->result != CONDITION_SUCCEEDED)
return c;
return failed_trigger && !has_succeeded_trigger ? failed_trigger : NULL;
}
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = { static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive", [COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed", [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",

View File

@ -658,6 +658,10 @@ typedef struct UnitVTable {
* of this type will immediately fail. */ * of this type will immediately fail. */
bool (*supported)(void); bool (*supported)(void);
/* If this function is set, it's invoked first as part of starting a unit to allow start rate
* limiting checks to occur before we do anything else. */
int (*test_start_limit)(Unit *u);
/* The strings to print in status messages */ /* The strings to print in status messages */
UnitStatusMessageFormats status_message_formats; UnitStatusMessageFormats status_message_formats;
@ -980,6 +984,8 @@ void unit_thawed(Unit *u);
int unit_freeze_vtable_common(Unit *u); int unit_freeze_vtable_common(Unit *u);
int unit_thaw_vtable_common(Unit *u); int unit_thaw_vtable_common(Unit *u);
Condition *unit_find_failed_condition(Unit *u);
/* Macros which append UNIT= or USER_UNIT= to the message */ /* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full_errno_zerook(unit, level, error, ...) \ #define log_unit_full_errno_zerook(unit, level, error, ...) \

View File

@ -299,6 +299,8 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
program_header->p_offset, program_header->p_offset,
program_header->p_filesz, program_header->p_filesz,
ELF_T_NHDR); ELF_T_NHDR);
if (!data)
continue;
Elf *memelf = elf_memory(data->d_buf, data->d_size); Elf *memelf = elf_memory(data->d_buf, data->d_size);
if (!memelf) if (!memelf)

View File

@ -20,7 +20,6 @@ int acquire_luks2_key(
int r; int r;
Fido2EnrollFlags required; Fido2EnrollFlags required;
size_t cid_size, salt_size, decrypted_key_size; size_t cid_size, salt_size, decrypted_key_size;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_free_ void *cid = NULL, *salt = NULL; _cleanup_free_ void *cid = NULL, *salt = NULL;
_cleanup_free_ char *rp_id = NULL; _cleanup_free_ char *rp_id = NULL;
_cleanup_(erase_and_freep) void *decrypted_key = NULL; _cleanup_(erase_and_freep) void *decrypted_key = NULL;
@ -53,7 +52,7 @@ int acquire_luks2_key(
required, required,
&decrypted_key, &decrypted_key,
&decrypted_key_size); &decrypted_key_size);
if (r == -ENOLCK) /* libcryptsetup returns -ENOANO also on wrong pin */ if (r == -ENOLCK) /* libcryptsetup returns -ENOANO also on wrong PIN */
r = -ENOANO; r = -ENOANO;
if (r < 0) if (r < 0)
return r; return r;
@ -61,7 +60,7 @@ int acquire_luks2_key(
/* Before using this key as passphrase we base64 encode it, for compat with homed */ /* Before using this key as passphrase we base64 encode it, for compat with homed */
r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
if (r < 0) if (r < 0)
return crypt_log_error_errno(cd, r, "Can not base64 encode key: %m"); return crypt_log_error_errno(cd, r, "Failed to base64 encode key: %m");
*ret_keyslot_passphrase = TAKE_PTR(base64_encoded); *ret_keyslot_passphrase = TAKE_PTR(base64_encoded);
*ret_keyslot_passphrase_size = strlen(*ret_keyslot_passphrase); *ret_keyslot_passphrase_size = strlen(*ret_keyslot_passphrase);

View File

@ -38,10 +38,18 @@
#include "strv.h" #include "strv.h"
#include "tmpfile-util.h" #include "tmpfile-util.h"
/* Round down to the nearest 1K size. Note that Linux generally handles block devices with 512 blocks only, /* Round down to the nearest 4K size. Given that newer hardware generally prefers 4K sectors, let's align our
* but actually doesn't accept uneven numbers in many cases. To avoid any confusion around this we'll * partitions to that too. In the worst case we'll waste 3.5K per partition that way, but I think I can live
* strictly round disk sizes down to the next 1K boundary. */ * with that. */
#define DISK_SIZE_ROUND_DOWN(x) ((x) & ~UINT64_C(1023)) #define DISK_SIZE_ROUND_DOWN(x) ((x) & ~UINT64_C(4095))
/* Rounds up to the nearest 4K boundary. Returns UINT64_MAX on overflow */
#define DISK_SIZE_ROUND_UP(x) \
({ \
uint64_t _x = (x); \
_x > UINT64_MAX - 4095U ? UINT64_MAX : (_x + 4095U) & ~UINT64_C(4095); \
})
int run_mark_dirty(int fd, bool b) { int run_mark_dirty(int fd, bool b) {
char x = '1'; char x = '1';
@ -1620,7 +1628,7 @@ static int make_partition_table(
_cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL; _cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL;
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL; _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
_cleanup_free_ char *path = NULL, *disk_uuid_as_string = NULL; _cleanup_free_ char *path = NULL, *disk_uuid_as_string = NULL;
uint64_t offset, size; uint64_t offset, size, first_lba, start, last_lba, end;
sd_id128_t disk_uuid; sd_id128_t disk_uuid;
int r; int r;
@ -1660,17 +1668,31 @@ static int make_partition_table(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set partition type: %m"); return log_error_errno(r, "Failed to set partition type: %m");
r = fdisk_partition_start_follow_default(p, 1);
if (r < 0)
return log_error_errno(r, "Failed to place partition at beginning of space: %m");
r = fdisk_partition_partno_follow_default(p, 1); r = fdisk_partition_partno_follow_default(p, 1);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to place partition at first free partition index: %m"); return log_error_errno(r, "Failed to place partition at first free partition index: %m");
r = fdisk_partition_end_follow_default(p, 1); first_lba = fdisk_get_first_lba(c); /* Boundary where usable space starts */
assert(first_lba <= UINT64_MAX/512);
start = DISK_SIZE_ROUND_UP(first_lba * 512); /* Round up to multiple of 4K */
if (start == UINT64_MAX)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Overflow while rounding up start LBA.");
last_lba = fdisk_get_last_lba(c); /* One sector before boundary where usable space ends */
assert(last_lba < UINT64_MAX/512);
end = DISK_SIZE_ROUND_DOWN((last_lba + 1) * 512); /* Round down to multiple of 4K */
if (end <= start)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Resulting partition size zero or negative.");
r = fdisk_partition_set_start(p, start / 512);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to make partition cover all free space: %m"); return log_error_errno(r, "Failed to place partition at offset %" PRIu64 ": %m", start);
r = fdisk_partition_set_size(p, (end - start) / 512);
if (r < 0)
return log_error_errno(r, "Failed to end partition at offset %" PRIu64 ": %m", end);
r = fdisk_partition_set_name(p, label); r = fdisk_partition_set_name(p, label);
if (r < 0) if (r < 0)
@ -2692,6 +2714,8 @@ int home_resize_luks(
new_image_size = old_image_size; /* we can't resize physical block devices */ new_image_size = old_image_size; /* we can't resize physical block devices */
} else { } else {
uint64_t new_image_size_rounded;
r = stat_verify_regular(&st); r = stat_verify_regular(&st);
if (r < 0) if (r < 0)
return log_error_errno(r, "Image %s is not a block device nor regular file: %m", ip); return log_error_errno(r, "Image %s is not a block device nor regular file: %m", ip);
@ -2702,11 +2726,16 @@ int home_resize_luks(
* apply onto the loopback file as a whole. When we operate on block devices we instead apply * apply onto the loopback file as a whole. When we operate on block devices we instead apply
* to the partition itself only. */ * to the partition itself only. */
new_image_size = DISK_SIZE_ROUND_DOWN(h->disk_size); new_image_size_rounded = DISK_SIZE_ROUND_DOWN(h->disk_size);
if (new_image_size == old_image_size) {
if (old_image_size == h->disk_size ||
old_image_size == new_image_size_rounded) {
/* If exact match, or a match after we rounded down, don't do a thing */
log_info("Image size already matching, skipping operation."); log_info("Image size already matching, skipping operation.");
return 0; return 0;
} }
new_image_size = new_image_size_rounded;
} }
r = home_prepare_luks(h, already_activated, whole_disk, cache, setup, &header_home); r = home_prepare_luks(h, already_activated, whole_disk, cache, setup, &header_home);
@ -2730,15 +2759,21 @@ int home_resize_luks(
if (new_image_size <= partition_table_extra) if (new_image_size <= partition_table_extra)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "New size smaller than partition table metadata."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "New size smaller than partition table metadata.");
new_partition_size = new_image_size - partition_table_extra; new_partition_size = DISK_SIZE_ROUND_DOWN(new_image_size - partition_table_extra);
} else { } else {
uint64_t new_partition_size_rounded;
assert(S_ISBLK(st.st_mode)); assert(S_ISBLK(st.st_mode));
new_partition_size = DISK_SIZE_ROUND_DOWN(h->disk_size); new_partition_size_rounded = DISK_SIZE_ROUND_DOWN(h->disk_size);
if (new_partition_size == setup->partition_size) {
if (h->disk_size == setup->partition_size ||
new_partition_size_rounded == setup->partition_size) {
log_info("Partition size already matching, skipping operation."); log_info("Partition size already matching, skipping operation.");
return 0; return 0;
} }
new_partition_size = new_partition_size_rounded;
} }
if ((UINT64_MAX - setup->partition_offset) < new_partition_size || if ((UINT64_MAX - setup->partition_offset) < new_partition_size ||
@ -2752,7 +2787,7 @@ int home_resize_luks(
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "New size smaller than crypto payload offset?"); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "New size smaller than crypto payload offset?");
old_fs_size = (setup->partition_size / 512U - crypto_offset) * 512U; old_fs_size = (setup->partition_size / 512U - crypto_offset) * 512U;
new_fs_size = (new_partition_size / 512U - crypto_offset) * 512U; new_fs_size = DISK_SIZE_ROUND_DOWN((new_partition_size / 512U - crypto_offset) * 512U);
/* Before we start doing anything, let's figure out if we actually can */ /* Before we start doing anything, let's figure out if we actually can */
resize_type = can_resize_fs(setup->root_fd, old_fs_size, new_fs_size); resize_type = can_resize_fs(setup->root_fd, old_fs_size, new_fs_size);

View File

@ -43,7 +43,7 @@ static int help(void) {
" --version Show package version\n" " --version Show package version\n"
" -s --strict When updating, return non-zero exit value on any parsing error\n" " -s --strict When updating, return non-zero exit value on any parsing error\n"
" --usr Generate in " UDEVLIBEXECDIR " instead of /etc/udev\n" " --usr Generate in " UDEVLIBEXECDIR " instead of /etc/udev\n"
" -r --root=PATH Alternative root path in the filesystem\n\n" " -r --root=PATH Alternative root path in the filesystem\n"
"\nSee the %s for details.\n", "\nSee the %s for details.\n",
program_invocation_short_name, program_invocation_short_name,
ansi_highlight(), ansi_highlight(),

View File

@ -132,19 +132,23 @@ libsystemd_sources = files('''
sd-device/sd-device.c sd-device/sd-device.c
sd-hwdb/hwdb-internal.h sd-hwdb/hwdb-internal.h
sd-hwdb/sd-hwdb.c sd-hwdb/sd-hwdb.c
sd-netlink/generic-netlink.c sd-netlink/netlink-genl.c
sd-netlink/generic-netlink.h sd-netlink/netlink-genl.h
sd-netlink/netlink-internal.h sd-netlink/netlink-internal.h
sd-netlink/netlink-message-nfnl.c
sd-netlink/netlink-message-rtnl.c
sd-netlink/netlink-message.c sd-netlink/netlink-message.c
sd-netlink/netlink-slot.c sd-netlink/netlink-slot.c
sd-netlink/netlink-slot.h sd-netlink/netlink-slot.h
sd-netlink/netlink-socket.c sd-netlink/netlink-socket.c
sd-netlink/netlink-types-genl.c
sd-netlink/netlink-types-internal.h
sd-netlink/netlink-types-nfnl.c
sd-netlink/netlink-types-rtnl.c
sd-netlink/netlink-types.c sd-netlink/netlink-types.c
sd-netlink/netlink-types.h sd-netlink/netlink-types.h
sd-netlink/netlink-util.c sd-netlink/netlink-util.c
sd-netlink/netlink-util.h sd-netlink/netlink-util.h
sd-netlink/nfnl-message.c
sd-netlink/rtnl-message.c
sd-netlink/sd-netlink.c sd-netlink/sd-netlink.c
sd-network/network-util.c sd-network/network-util.c
sd-network/network-util.h sd-network/network-util.h

View File

@ -1,179 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/genetlink.h>
#include "sd-netlink.h"
#include "alloc-util.h"
#include "generic-netlink.h"
#include "netlink-internal.h"
typedef struct {
const char* name;
uint8_t version;
} genl_family;
static const genl_family genl_families[] = {
[SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
[SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
[SD_GENL_FOU] = { .name = "fou", .version = 1 },
[SD_GENL_L2TP] = { .name = "l2tp", .version = 1 },
[SD_GENL_MACSEC] = { .name = "macsec", .version = 1 },
[SD_GENL_NL80211] = { .name = "nl80211", .version = 1 },
[SD_GENL_BATADV] = { .name = "batadv", .version = 1 },
};
int sd_genl_socket_open(sd_netlink **ret) {
return netlink_open_family(ret, NETLINK_GENERIC);
}
static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *genl_cmd_type, *nl_type;
const NLTypeSystem *type_system;
size_t size;
int r;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(ret);
r = type_system_get_type(&genl_family_type_system_root, &genl_cmd_type, family);
if (r < 0)
return r;
r = message_new_empty(nl, &m);
if (r < 0)
return r;
size = NLMSG_SPACE(sizeof(struct genlmsghdr));
m->hdr = malloc0(size);
if (!m->hdr)
return -ENOMEM;
m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
type_get_type_system(genl_cmd_type, &type_system);
r = type_system_get_type(type_system, &nl_type, cmd);
if (r < 0)
return r;
m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = nlmsg_type;
type_get_type_system(nl_type, &m->containers[0].type_system);
*(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) {
.cmd = cmd,
.version = genl_families[family].version,
};
*ret = TAKE_PTR(m);
return 0;
}
static int lookup_nlmsg_type(sd_netlink *nl, sd_genl_family_t family, uint16_t *ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
uint16_t u;
void *v;
int r;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(ret);
if (family == SD_GENL_ID_CTRL) {
*ret = GENL_ID_CTRL;
return 0;
}
v = hashmap_get(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family));
if (v) {
*ret = PTR_TO_UINT(v);
return 0;
}
r = genl_message_new(nl, SD_GENL_ID_CTRL, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
if (r < 0)
return r;
r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name);
if (r < 0)
return r;
r = sd_netlink_call(nl, req, 0, &reply);
if (r < 0)
return r;
r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &u);
if (r < 0)
return r;
r = hashmap_ensure_put(&nl->genl_family_to_nlmsg_type, NULL, INT_TO_PTR(family), UINT_TO_PTR(u));
if (r < 0)
return r;
r = hashmap_ensure_put(&nl->nlmsg_type_to_genl_family, NULL, UINT_TO_PTR(u), INT_TO_PTR(family));
if (r < 0)
return r;
*ret = u;
return 0;
}
int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret) {
uint16_t nlmsg_type = 0; /* Unnecessary initialization to appease gcc */
int r;
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(ret, -EINVAL);
r = lookup_nlmsg_type(nl, family, &nlmsg_type);
if (r < 0)
return r;
return genl_message_new(nl, family, nlmsg_type, cmd, ret);
}
int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t nlmsg_type, sd_genl_family_t *ret) {
void *p;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(ret);
if (nlmsg_type == NLMSG_ERROR)
*ret = SD_GENL_ERROR;
else if (nlmsg_type == NLMSG_DONE)
*ret = SD_GENL_DONE;
else if (nlmsg_type == GENL_ID_CTRL)
*ret = SD_GENL_ID_CTRL;
else {
p = hashmap_get(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(nlmsg_type));
if (!p)
return -EOPNOTSUPP;
*ret = PTR_TO_INT(p);
}
return 0;
}
int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *ret) {
uint16_t nlmsg_type;
int r;
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(m, -EINVAL);
assert_return(ret, -EINVAL);
r = sd_netlink_message_get_type(m, &nlmsg_type);
if (r < 0)
return r;
return nlmsg_type_to_genl_family(nl, nlmsg_type, ret);
}

View File

@ -1,6 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-netlink.h"
int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family_t *ret);

View File

@ -0,0 +1,473 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/genetlink.h>
#include "sd-netlink.h"
#include "alloc-util.h"
#include "netlink-genl.h"
#include "netlink-internal.h"
#include "netlink-types.h"
typedef struct GenericNetlinkFamily {
sd_netlink *genl;
const NLTypeSystem *type_system;
uint16_t id; /* a.k.a nlmsg_type */
char *name;
uint32_t version;
uint32_t additional_header_size;
Hashmap *multicast_group_by_name;
} GenericNetlinkFamily;
static const GenericNetlinkFamily nlctrl_static = {
.id = GENL_ID_CTRL,
.name = (char*) CTRL_GENL_NAME,
.version = 0x01,
};
static GenericNetlinkFamily *genl_family_free(GenericNetlinkFamily *f) {
if (!f)
return NULL;
if (f->genl) {
if (f->id > 0)
hashmap_remove(f->genl->genl_family_by_id, UINT_TO_PTR(f->id));
if (f->name)
hashmap_remove(f->genl->genl_family_by_name, f->name);
}
free(f->name);
hashmap_free(f->multicast_group_by_name);
return mfree(f);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(GenericNetlinkFamily*, genl_family_free);
void genl_clear_family(sd_netlink *nl) {
assert(nl);
nl->genl_family_by_name = hashmap_free_with_destructor(nl->genl_family_by_name, genl_family_free);
nl->genl_family_by_id = hashmap_free_with_destructor(nl->genl_family_by_id, genl_family_free);
}
static int genl_family_new(
sd_netlink *nl,
const char *expected_family_name,
const NLTypeSystem *type_system,
sd_netlink_message *message,
const GenericNetlinkFamily **ret) {
_cleanup_(genl_family_freep) GenericNetlinkFamily *f = NULL;
const char *family_name;
uint8_t cmd;
int r;
assert(nl);
assert(expected_family_name);
assert(type_system);
assert(message);
assert(ret);
f = new(GenericNetlinkFamily, 1);
if (!f)
return -ENOMEM;
*f = (GenericNetlinkFamily) {
.type_system = type_system,
};
if (sd_netlink_message_is_error(message)) {
int e;
/* Kernel does not support the genl family? To prevent from resolving the family name
* again, let's store the family with zero id to indicate that. */
e = sd_netlink_message_get_errno(message);
if (e >= 0) /* Huh? */
e = -EOPNOTSUPP;
f->name = strdup(expected_family_name);
if (!f->name)
return e;
if (hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f) < 0)
return e;
f->genl = nl;
TAKE_PTR(f);
return e;
}
r = sd_genl_message_get_family_name(nl, message, &family_name);
if (r < 0)
return r;
if (!streq(family_name, CTRL_GENL_NAME))
return -EINVAL;
r = sd_genl_message_get_command(nl, message, &cmd);
if (r < 0)
return r;
if (cmd != CTRL_CMD_NEWFAMILY)
return -EINVAL;
r = sd_netlink_message_read_u16(message, CTRL_ATTR_FAMILY_ID, &f->id);
if (r < 0)
return r;
r = sd_netlink_message_read_string_strdup(message, CTRL_ATTR_FAMILY_NAME, &f->name);
if (r < 0)
return r;
if (!streq(f->name, expected_family_name))
return -EINVAL;
r = sd_netlink_message_read_u32(message, CTRL_ATTR_VERSION, &f->version);
if (r < 0)
return r;
r = sd_netlink_message_read_u32(message, CTRL_ATTR_HDRSIZE, &f->additional_header_size);
if (r < 0)
return r;
r = sd_netlink_message_enter_container(message, CTRL_ATTR_MCAST_GROUPS);
if (r >= 0) {
for (uint16_t i = 0; i < UINT16_MAX; i++) {
_cleanup_free_ char *group_name = NULL;
uint32_t group_id;
r = sd_netlink_message_enter_array(message, i + 1);
if (r == -ENODATA)
break;
if (r < 0)
return r;
r = sd_netlink_message_read_u32(message, CTRL_ATTR_MCAST_GRP_ID, &group_id);
if (r < 0)
return r;
r = sd_netlink_message_read_string_strdup(message, CTRL_ATTR_MCAST_GRP_NAME, &group_name);
if (r < 0)
return r;
r = sd_netlink_message_exit_container(message);
if (r < 0)
return r;
if (group_id == 0) {
log_debug("sd-netlink: received multicast group '%s' for generic netlink family '%s' with id == 0, ignoring",
group_name, f->name);
continue;
}
r = hashmap_ensure_put(&f->multicast_group_by_name, &string_hash_ops_free, group_name, UINT32_TO_PTR(group_id));
if (r < 0)
return r;
TAKE_PTR(group_name);
}
r = sd_netlink_message_exit_container(message);
if (r < 0)
return r;
}
r = hashmap_ensure_put(&nl->genl_family_by_id, NULL, UINT_TO_PTR(f->id), f);
if (r < 0)
return r;
r = hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f);
if (r < 0) {
hashmap_remove(nl->genl_family_by_id, UINT_TO_PTR(f->id));
return r;
}
f->genl = nl;
*ret = TAKE_PTR(f);
return 0;
}
static const NLTypeSystem *genl_family_get_type_system(const GenericNetlinkFamily *family) {
assert(family);
if (family->type_system)
return family->type_system;
return genl_get_type_system_by_name(family->name);
}
static int genl_message_new(
sd_netlink *nl,
const GenericNetlinkFamily *family,
uint8_t cmd,
sd_netlink_message **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLTypeSystem *type_system;
int r;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(family);
assert(ret);
type_system = genl_family_get_type_system(family);
if (!type_system)
return -EOPNOTSUPP;
r = message_new_full(nl, family->id, type_system,
sizeof(struct genlmsghdr) + family->additional_header_size, &m);
if (r < 0)
return r;
*(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) {
.cmd = cmd,
.version = family->version,
};
*ret = TAKE_PTR(m);
return 0;
}
static int genl_family_get_by_name_internal(
sd_netlink *nl,
const GenericNetlinkFamily *ctrl,
const char *name,
const GenericNetlinkFamily **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
const NLTypeSystem *type_system;
int r;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(ctrl);
assert(name);
assert(ret);
type_system = genl_get_type_system_by_name(name);
if (!type_system)
return -EOPNOTSUPP;
r = genl_message_new(nl, ctrl, CTRL_CMD_GETFAMILY, &req);
if (r < 0)
return r;
r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, name);
if (r < 0)
return r;
r = sd_netlink_call(nl, req, 0, &reply);
if (r < 0)
return r;
return genl_family_new(nl, name, type_system, reply, ret);
}
static int genl_family_get_by_name(sd_netlink *nl, const char *name, const GenericNetlinkFamily **ret) {
const GenericNetlinkFamily *f, *ctrl;
int r;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(name);
assert(ret);
f = hashmap_get(nl->genl_family_by_name, name);
if (f) {
if (f->id == 0) /* kernel does not support the family. */
return -EOPNOTSUPP;
*ret = f;
return 0;
}
if (streq(name, CTRL_GENL_NAME))
return genl_family_get_by_name_internal(nl, &nlctrl_static, CTRL_GENL_NAME, ret);
ctrl = hashmap_get(nl->genl_family_by_name, CTRL_GENL_NAME);
if (!ctrl) {
r = genl_family_get_by_name_internal(nl, &nlctrl_static, CTRL_GENL_NAME, &ctrl);
if (r < 0)
return r;
}
return genl_family_get_by_name_internal(nl, ctrl, name, ret);
}
static int genl_family_get_by_id(sd_netlink *nl, uint16_t id, const GenericNetlinkFamily **ret) {
const GenericNetlinkFamily *f;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(ret);
f = hashmap_get(nl->genl_family_by_id, UINT_TO_PTR(id));
if (f) {
*ret = f;
return 0;
}
if (id == GENL_ID_CTRL) {
*ret = &nlctrl_static;
return 0;
}
return -ENOENT;
}
int genl_get_type_system_and_header_size(
sd_netlink *nl,
uint16_t id,
const NLTypeSystem **ret_type_system,
size_t *ret_header_size) {
const GenericNetlinkFamily *f;
int r;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
r = genl_family_get_by_id(nl, id, &f);
if (r < 0)
return r;
if (ret_type_system) {
const NLTypeSystem *t;
t = genl_family_get_type_system(f);
if (!t)
return -EOPNOTSUPP;
*ret_type_system = t;
}
if (ret_header_size)
*ret_header_size = sizeof(struct genlmsghdr) + f->additional_header_size;
return 0;
}
int sd_genl_message_new(sd_netlink *nl, const char *family_name, uint8_t cmd, sd_netlink_message **ret) {
const GenericNetlinkFamily *family;
int r;
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(family_name, -EINVAL);
assert_return(ret, -EINVAL);
r = genl_family_get_by_name(nl, family_name, &family);
if (r < 0)
return r;
return genl_message_new(nl, family, cmd, ret);
}
int sd_genl_message_get_family_name(sd_netlink *nl, sd_netlink_message *m, const char **ret) {
const GenericNetlinkFamily *family;
uint16_t nlmsg_type;
int r;
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(m, -EINVAL);
assert_return(ret, -EINVAL);
r = sd_netlink_message_get_type(m, &nlmsg_type);
if (r < 0)
return r;
r = genl_family_get_by_id(nl, nlmsg_type, &family);
if (r < 0)
return r;
*ret = family->name;
return 0;
}
int sd_genl_message_get_command(sd_netlink *nl, sd_netlink_message *m, uint8_t *ret) {
struct genlmsghdr *h;
uint16_t nlmsg_type;
size_t size;
int r;
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(m, -EINVAL);
assert_return(m->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(m->hdr, -EINVAL);
assert_return(ret, -EINVAL);
r = sd_netlink_message_get_type(m, &nlmsg_type);
if (r < 0)
return r;
r = genl_get_type_system_and_header_size(nl, nlmsg_type, NULL, &size);
if (r < 0)
return r;
if (m->hdr->nlmsg_len < NLMSG_LENGTH(size))
return -EBADMSG;
h = NLMSG_DATA(m->hdr);
*ret = h->cmd;
return 0;
}
static int genl_family_get_multicast_group_id_by_name(const GenericNetlinkFamily *f, const char *name, uint32_t *ret) {
void *p;
assert(f);
assert(name);
p = hashmap_get(f->multicast_group_by_name, name);
if (!p)
return -ENOENT;
if (ret)
*ret = PTR_TO_UINT32(p);
return 0;
}
int sd_genl_add_match(
sd_netlink *nl,
sd_netlink_slot **ret_slot,
const char *family_name,
const char *multicast_group_name,
uint8_t command,
sd_netlink_message_handler_t callback,
sd_netlink_destroy_t destroy_callback,
void *userdata,
const char *description) {
const GenericNetlinkFamily *f;
uint32_t multicast_group_id;
int r;
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(family_name, -EINVAL);
assert_return(multicast_group_name, -EINVAL);
/* If command == 0, then all commands belonging to the multicast group trigger the callback. */
r = genl_family_get_by_name(nl, family_name, &f);
if (r < 0)
return r;
r = genl_family_get_multicast_group_id_by_name(f, multicast_group_name, &multicast_group_id);
if (r < 0)
return r;
return netlink_add_match_internal(nl, ret_slot, &multicast_group_id, 1, f->id, command,
callback, destroy_callback, userdata, description);
}
int sd_genl_socket_open(sd_netlink **ret) {
return netlink_open_family(ret, NETLINK_GENERIC);
}

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-netlink.h"
#define CTRL_GENL_NAME "nlctrl"
void genl_clear_family(sd_netlink *nl);

View File

@ -10,11 +10,11 @@
#include "prioq.h" #include "prioq.h"
#include "time-util.h" #include "time-util.h"
#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) #define NETLINK_DEFAULT_TIMEOUT_USEC ((usec_t) (25 * USEC_PER_SEC))
#define RTNL_RQUEUE_MAX 64*1024 #define NETLINK_RQUEUE_MAX 64*1024
#define RTNL_CONTAINER_DEPTH 32 #define NETLINK_CONTAINER_DEPTH 32
struct reply_callback { struct reply_callback {
sd_netlink_message_handler_t callback; sd_netlink_message_handler_t callback;
@ -25,7 +25,10 @@ struct reply_callback {
struct match_callback { struct match_callback {
sd_netlink_message_handler_t callback; sd_netlink_message_handler_t callback;
uint32_t *groups;
size_t n_groups;
uint16_t type; uint16_t type;
uint8_t cmd; /* used by genl */
LIST_FIELDS(struct match_callback, match_callbacks); LIST_FIELDS(struct match_callback, match_callbacks);
}; };
@ -95,8 +98,8 @@ struct sd_netlink {
sd_event_source *exit_event_source; sd_event_source *exit_event_source;
sd_event *event; sd_event *event;
Hashmap *genl_family_to_nlmsg_type; Hashmap *genl_family_by_name;
Hashmap *nlmsg_type_to_genl_family; Hashmap *genl_family_by_id;
}; };
struct netlink_attribute { struct netlink_attribute {
@ -118,7 +121,7 @@ struct sd_netlink_message {
int protocol; int protocol;
struct nlmsghdr *hdr; struct nlmsghdr *hdr;
struct netlink_container containers[RTNL_CONTAINER_DEPTH]; struct netlink_container containers[NETLINK_CONTAINER_DEPTH];
unsigned n_containers; /* number of containers */ unsigned n_containers; /* number of containers */
bool sealed:1; bool sealed:1;
bool broadcast:1; bool broadcast:1;
@ -126,10 +129,22 @@ struct sd_netlink_message {
sd_netlink_message *next; /* next in a chain of multi-part messages */ sd_netlink_message *next; /* next in a chain of multi-part messages */
}; };
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type); int message_new_empty(sd_netlink *nl, sd_netlink_message **ret);
int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret); int message_new_full(
sd_netlink *nl,
uint16_t nlmsg_type,
const NLTypeSystem *type_system,
size_t header_size,
sd_netlink_message **ret);
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type);
int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret);
uint32_t message_get_serial(sd_netlink_message *m);
void message_seal(sd_netlink_message *m);
int netlink_open_family(sd_netlink **ret, int family); int netlink_open_family(sd_netlink **ret, int family);
bool netlink_pid_changed(sd_netlink *nl);
int netlink_rqueue_make_room(sd_netlink *nl);
int netlink_rqueue_partial_make_room(sd_netlink *nl);
int socket_open(int family); int socket_open(int family);
int socket_bind(sd_netlink *nl); int socket_bind(sd_netlink *nl);
@ -139,9 +154,18 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount); int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount);
int socket_read_message(sd_netlink *nl); int socket_read_message(sd_netlink *nl);
int rtnl_rqueue_make_room(sd_netlink *rtnl); int netlink_add_match_internal(
int rtnl_rqueue_partial_make_room(sd_netlink *rtnl); sd_netlink *nl,
sd_netlink_slot **ret_slot,
const uint32_t *groups,
size_t n_groups,
uint16_t type,
uint8_t cmd,
sd_netlink_message_handler_t callback,
sd_netlink_destroy_t destroy_callback,
void *userdata,
const char *description);
/* Make sure callbacks don't destroy the rtnl connection */ /* Make sure callbacks don't destroy the netlink connection */
#define NETLINK_DONT_DESTROY(rtnl) \ #define NETLINK_DONT_DESTROY(nl) \
_cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl) _cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##nl = sd_netlink_ref(nl)

View File

@ -13,48 +13,20 @@
#include "format-util.h" #include "format-util.h"
#include "netlink-internal.h" #include "netlink-internal.h"
#include "netlink-types.h" #include "netlink-types.h"
#include "netlink-util.h"
#include "socket-util.h" #include "socket-util.h"
#include "util.h"
static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) { static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t msg_type, uint16_t flags) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type;
size_t size;
int r; int r;
assert_return(nfnl, -EINVAL); assert_return(nfnl, -EINVAL);
assert_return(ret, -EINVAL);
r = type_system_root_get_type(nfnl, &nl_type, NFNL_SUBSYS_NFTABLES); r = message_new(nfnl, &m, NFNL_SUBSYS_NFTABLES << 8 | msg_type);
if (r < 0) if (r < 0)
return r; return r;
if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) m->hdr->nlmsg_flags |= flags;
return -EINVAL;
r = message_new_empty(nfnl, &m);
if (r < 0)
return r;
size = NLMSG_SPACE(type_get_size(nl_type));
assert(size >= sizeof(struct nlmsghdr));
m->hdr = malloc0(size);
if (!m->hdr)
return -ENOMEM;
m->hdr->nlmsg_flags = NLM_F_REQUEST | flags;
type_get_type_system(nl_type, &m->containers[0].type_system);
r = type_system_get_type_system(m->containers[0].type_system,
&m->containers[0].type_system,
type);
if (r < 0)
return r;
m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type;
*(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) {
.nfgen_family = family, .nfgen_family = family,
@ -66,11 +38,11 @@ static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int famil
return 0; return 0;
} }
static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) { static int nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, uint16_t msg_type) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = message_new(nfnl, &m, v); r = message_new(nfnl, &m, NFNL_SUBSYS_NONE << 8 | msg_type);
if (r < 0) if (r < 0)
return r; return r;
@ -81,26 +53,31 @@ static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int
}; };
*ret = TAKE_PTR(m); *ret = TAKE_PTR(m);
return r; return 0;
} }
int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) { int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) {
return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN); return nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN);
} }
int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) { int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) {
return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END); return nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END);
} }
int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_basechain(
int family, sd_netlink *nfnl,
const char *table, const char *chain, sd_netlink_message **ret,
const char *type, int family,
uint8_t hook, int prio) { const char *table,
const char *chain,
const char *type,
uint8_t hook,
int prio) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE | NLM_F_ACK); r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE);
if (r < 0) if (r < 0)
return r; return r;
@ -136,12 +113,16 @@ int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret
return 0; return 0;
} }
int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_del_table(
int family, const char *table) { sd_netlink *nfnl,
sd_netlink_message **ret,
int family,
const char *table) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE | NLM_F_ACK); r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE);
if (r < 0) if (r < 0)
return r; return r;
@ -153,12 +134,16 @@ int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret,
return r; return r;
} }
int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_table(
int family, const char *table, uint16_t flags) { sd_netlink *nfnl,
sd_netlink_message **ret,
int family,
const char *table) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | flags); r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL);
if (r < 0) if (r < 0)
return r; return r;
@ -170,12 +155,17 @@ int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
return r; return r;
} }
int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_rule(
int family, const char *table, const char *chain) { sd_netlink *nfnl,
sd_netlink_message **ret,
int family,
const char *table,
const char *chain) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE | NLM_F_ACK); r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE);
if (r < 0) if (r < 0)
return r; return r;
@ -191,13 +181,19 @@ int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret,
return r; return r;
} }
int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_set(
int family, const char *table, const char *set_name, sd_netlink *nfnl,
uint32_t set_id, uint32_t klen) { sd_netlink_message **ret,
int family,
const char *table,
const char *set_name,
uint32_t set_id,
uint32_t klen) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE | NLM_F_ACK); r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE);
if (r < 0) if (r < 0)
return r; return r;
@ -216,16 +212,22 @@ int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret,
r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen)); r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen));
if (r < 0) if (r < 0)
return r; return r;
*ret = TAKE_PTR(m); *ret = TAKE_PTR(m);
return r; return r;
} }
int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_setelems_begin(
int family, const char *table, const char *set_name) { sd_netlink *nfnl,
sd_netlink_message **ret,
int family,
const char *table,
const char *set_name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE | NLM_F_ACK); r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE);
if (r < 0) if (r < 0)
return r; return r;
@ -245,12 +247,17 @@ int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message
return r; return r;
} }
int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_del_setelems_begin(
int family, const char *table, const char *set_name) { sd_netlink *nfnl,
sd_netlink_message **ret,
int family,
const char *table,
const char *set_name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, NLM_F_ACK); r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, 0);
if (r < 0) if (r < 0)
return r; return r;
@ -271,7 +278,9 @@ int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message
} }
static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) { static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) {
int r = sd_netlink_message_open_container(m, attr); int r;
r = sd_netlink_message_open_container(m, attr);
if (r < 0) if (r < 0)
return r; return r;
@ -282,9 +291,14 @@ static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *da
return sd_netlink_message_close_container(m); /* attr */ return sd_netlink_message_close_container(m); /* attr */
} }
int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, uint32_t num, int sd_nfnl_nft_message_add_setelem(
const void *key, uint32_t klen, sd_netlink_message *m,
const void *data, uint32_t dlen) { uint32_t num,
const void *key,
uint32_t klen,
const void *data,
uint32_t dlen) {
int r; int r;
r = sd_netlink_message_open_array(m, num); r = sd_netlink_message_open_array(m, num);
@ -301,7 +315,8 @@ int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, uint32_t num,
goto cancel; goto cancel;
} }
return r; return 0;
cancel: cancel:
sd_netlink_message_cancel_array(m); sd_netlink_message_cancel_array(m);
return r; return r;

View File

@ -271,13 +271,13 @@ int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
} }
int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
uint16_t nhmsg_type, int nh_family, uint16_t nlmsg_type, int nh_family,
unsigned char nh_protocol) { unsigned char nh_protocol) {
struct nhmsg *nhm; struct nhmsg *nhm;
int r; int r;
assert_return(rtnl_message_type_is_nexthop(nhmsg_type), -EINVAL); assert_return(rtnl_message_type_is_nexthop(nlmsg_type), -EINVAL);
switch(nhmsg_type) { switch(nlmsg_type) {
case RTM_DELNEXTHOP: case RTM_DELNEXTHOP:
assert_return(nh_family == AF_UNSPEC, -EINVAL); assert_return(nh_family == AF_UNSPEC, -EINVAL);
_fallthrough_; _fallthrough_;
@ -292,11 +292,11 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
} }
assert_return(ret, -EINVAL); assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nhmsg_type); r = message_new(rtnl, ret, nlmsg_type);
if (r < 0) if (r < 0)
return r; return r;
if (nhmsg_type == RTM_NEWNEXTHOP) if (nlmsg_type == RTM_NEWNEXTHOP)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND; (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
nhm = NLMSG_DATA((*ret)->hdr); nhm = NLMSG_DATA((*ret)->hdr);

View File

@ -20,15 +20,14 @@
#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK) #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK) #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) { int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) {
sd_netlink_message *m; sd_netlink_message *m;
assert_return(ret, -EINVAL); assert(nl);
assert(ret);
/* Note that 'rtnl' is currently unused, if we start using it internally /* Note that 'nl' is currently unused, if we start using it internally we must take care to
we must take care to avoid problems due to mutual references between * avoid problems due to mutual references between buses and their queued messages. See sd-bus. */
buses and their queued messages. See sd-bus.
*/
m = new(sd_netlink_message, 1); m = new(sd_netlink_message, 1);
if (!m) if (!m)
@ -36,48 +35,80 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
*m = (sd_netlink_message) { *m = (sd_netlink_message) {
.n_ref = 1, .n_ref = 1,
.protocol = rtnl->protocol, .protocol = nl->protocol,
.sealed = false, .sealed = false,
}; };
*ret = m; *ret = m;
return 0; return 0;
} }
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) { int message_new_full(
sd_netlink *nl,
uint16_t nlmsg_type,
const NLTypeSystem *type_system,
size_t header_size,
sd_netlink_message **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type;
size_t size; size_t size;
int r; int r;
assert_return(rtnl, -EINVAL); assert(nl);
assert(type_system);
r = type_system_root_get_type(rtnl, &nl_type, type); assert(ret);
if (r < 0)
return r;
if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
return -EINVAL;
r = message_new_empty(rtnl, &m);
if (r < 0)
return r;
size = NLMSG_SPACE(type_get_size(nl_type));
size = NLMSG_SPACE(header_size);
assert(size >= sizeof(struct nlmsghdr)); assert(size >= sizeof(struct nlmsghdr));
r = message_new_empty(nl, &m);
if (r < 0)
return r;
m->containers[0].type_system = type_system;
m->hdr = malloc0(size); m->hdr = malloc0(size);
if (!m->hdr) if (!m->hdr)
return -ENOMEM; return -ENOMEM;
m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
type_get_type_system(nl_type, &m->containers[0].type_system);
m->hdr->nlmsg_len = size; m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = type; m->hdr->nlmsg_type = nlmsg_type;
*ret = TAKE_PTR(m); *ret = TAKE_PTR(m);
return 0;
}
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type) {
const NLTypeSystem *type_system;
size_t size;
int r;
assert_return(nl, -EINVAL);
assert_return(ret, -EINVAL);
r = type_system_root_get_type_system_and_header_size(nl, type, &type_system, &size);
if (r < 0)
return r;
return message_new_full(nl, type, type_system, size, ret);
}
int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) {
struct nlmsgerr *err;
int r;
assert(error <= 0);
r = message_new(nl, ret, NLMSG_ERROR);
if (r < 0)
return r;
message_seal(*ret);
(*ret)->hdr->nlmsg_seq = serial;
err = NLMSG_DATA((*ret)->hdr);
err->error = error;
return 0; return 0;
} }
@ -184,13 +215,12 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) { static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
const NLType *type; const NLType *type;
int r;
assert(m); assert(m);
r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type); type = type_system_get_type(m->containers[m->n_containers].type_system, attribute_type);
if (r < 0) if (!type)
return r; return -EOPNOTSUPP;
if (type_get_type(type) != data_type) if (type_get_type(type) != data_type)
return -EINVAL; return -EINVAL;
@ -538,7 +568,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM); assert_return(!m->sealed, -EPERM);
/* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */ /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE); assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED); r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
if (r < 0) { if (r < 0) {
@ -553,22 +583,23 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type
if (r < 0) if (r < 0)
return r; return r;
r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type); type_system_union = type_system_get_type_system_union(
if (r < 0) m->containers[m->n_containers].type_system,
return r; type);
if (!type_system_union)
return -EOPNOTSUPP;
r = type_system_union_protocol_get_type_system(type_system_union, m->containers[m->n_containers + 1].type_system =
&m->containers[m->n_containers + 1].type_system, type_system_union_get_type_system_by_protocol(
family); type_system_union,
if (r < 0) family);
return r; } else
} else { m->containers[m->n_containers + 1].type_system =
r = type_system_get_type_system(m->containers[m->n_containers].type_system, type_system_get_type_system(
&m->containers[m->n_containers + 1].type_system, m->containers[m->n_containers].type_system,
type); type);
if (r < 0) if (!m->containers[m->n_containers + 1].type_system)
return r; return -EOPNOTSUPP;
}
r = add_rtattr(m, type | NLA_F_NESTED, NULL, size); r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
if (r < 0) if (r < 0)
@ -585,19 +616,22 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM); assert_return(!m->sealed, -EPERM);
assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE); assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type); type_system_union = type_system_get_type_system_union(
if (r < 0) m->containers[m->n_containers].type_system,
return r; type);
if (!type_system_union)
return -EOPNOTSUPP;
r = type_system_union_get_type_system(type_system_union, m->containers[m->n_containers + 1].type_system =
&m->containers[m->n_containers + 1].type_system, type_system_union_get_type_system_by_string(
key); type_system_union,
if (r < 0) key);
return r; if (!m->containers[m->n_containers + 1].type_system)
return -EOPNOTSUPP;
r = sd_netlink_message_append_string(m, type_system_union->match, key); r = sd_netlink_message_append_string(m, type_system_union_get_match_attribute(type_system_union), key);
if (r < 0) if (r < 0)
return r; return r;
@ -628,7 +662,7 @@ int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM); assert_return(!m->sealed, -EPERM);
assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE); assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0); r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
if (r < 0) if (r < 0)
@ -673,7 +707,7 @@ static int netlink_message_read_internal(
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->sealed, -EPERM); assert_return(m->sealed, -EPERM);
assert(m->n_containers < RTNL_CONTAINER_DEPTH); assert(m->n_containers < NETLINK_CONTAINER_DEPTH);
if (!m->containers[m->n_containers].attributes) if (!m->containers[m->n_containers].attributes)
return -ENODATA; return -ENODATA;
@ -1008,26 +1042,26 @@ int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container
int r; int r;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL); assert_return(m->n_containers < NETLINK_CONTAINER_DEPTH, -EINVAL);
r = type_system_get_type(m->containers[m->n_containers].type_system, nl_type = type_system_get_type(
&nl_type, m->containers[m->n_containers].type_system,
container_type); container_type);
if (r < 0) if (!nl_type)
return r; return -EOPNOTSUPP;
if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
return -EINVAL; return -EINVAL;
r = type_system_get_type_system(m->containers[m->n_containers].type_system, type_system = type_system_get_type_system(
&type_system, m->containers[m->n_containers].type_system,
container_type); container_type);
if (r < 0) if (!type_system)
return r; return -EOPNOTSUPP;
r = type_system_get_type(type_system, &nl_type, type_id); nl_type = type_system_get_type(type_system, type_id);
if (r < 0) if (!nl_type)
return r; return -EOPNOTSUPP;
if (type_get_type(nl_type) != NETLINK_TYPE_STRING) if (type_get_type(nl_type) != NETLINK_TYPE_STRING)
return -EINVAL; return -EINVAL;
@ -1079,7 +1113,7 @@ static int netlink_container_parse(sd_netlink_message *m,
return -ENOMEM; return -ENOMEM;
if (attributes[type].offset != 0) if (attributes[type].offset != 0)
log_debug("rtnl: message parse - overwriting repeated attribute"); log_debug("sd-netlink: message parse - overwriting repeated attribute");
attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr; attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED; attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
@ -1104,61 +1138,62 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
int r; int r;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL); assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL);
r = type_system_get_type(m->containers[m->n_containers].type_system, nl_type = type_system_get_type(
&nl_type, m->containers[m->n_containers].type_system,
type_id); type_id);
if (r < 0) if (!nl_type)
return r; return -EOPNOTSUPP;
type = type_get_type(nl_type); type = type_get_type(nl_type);
if (type == NETLINK_TYPE_NESTED) { if (type == NETLINK_TYPE_NESTED) {
r = type_system_get_type_system(m->containers[m->n_containers].type_system, type_system = type_system_get_type_system(
&type_system, m->containers[m->n_containers].type_system,
type_id); type_id);
if (r < 0) if (!type_system)
return r; return -EOPNOTSUPP;
} else if (type == NETLINK_TYPE_UNION) { } else if (type == NETLINK_TYPE_UNION) {
const NLTypeSystemUnion *type_system_union; const NLTypeSystemUnion *type_system_union;
r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, type_system_union = type_system_get_type_system_union(
&type_system_union, m->containers[m->n_containers].type_system,
type_id); type_id);
if (r < 0) if (!type_system_union)
return r; return -EOPNOTSUPP;
switch (type_system_union->match_type) { switch (type_system_union_get_match_type(type_system_union)) {
case NL_MATCH_SIBLING: case NL_MATCH_SIBLING: {
{
const char *key; const char *key;
r = sd_netlink_message_read_string(m, type_system_union->match, &key); r = sd_netlink_message_read_string(
m,
type_system_union_get_match_attribute(type_system_union),
&key);
if (r < 0) if (r < 0)
return r; return r;
r = type_system_union_get_type_system(type_system_union, type_system = type_system_union_get_type_system_by_string(
&type_system, type_system_union,
key); key);
if (r < 0) if (!type_system)
return r; return -EOPNOTSUPP;
break; break;
} }
case NL_MATCH_PROTOCOL: case NL_MATCH_PROTOCOL: {
{
int family; int family;
r = sd_rtnl_message_get_family(m, &family); r = sd_rtnl_message_get_family(m, &family);
if (r < 0) if (r < 0)
return r; return r;
r = type_system_union_protocol_get_type_system(type_system_union, type_system = type_system_union_get_type_system_by_protocol(
&type_system, type_system_union,
family); family);
if (r < 0) if (!type_system)
return r; return -EOPNOTSUPP;
break; break;
} }
@ -1195,7 +1230,7 @@ int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id
int r; int r;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL); assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL);
r = netlink_message_read_internal(m, type_id, &container, NULL); r = netlink_message_read_internal(m, type_id, &container, NULL);
if (r < 0) if (r < 0)
@ -1231,7 +1266,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) {
return 0; return 0;
} }
uint32_t rtnl_message_get_serial(sd_netlink_message *m) { uint32_t message_get_serial(sd_netlink_message *m) {
assert(m); assert(m);
assert(m->hdr); assert(m->hdr);
@ -1280,18 +1315,15 @@ static int netlink_message_parse_error(sd_netlink_message *m) {
NLMSG_PAYLOAD(m->hdr, hlen)); NLMSG_PAYLOAD(m->hdr, hlen));
} }
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) { int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
const NLType *nl_type;
uint16_t type;
size_t size; size_t size;
int r; int r;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(genl || m->protocol != NETLINK_GENERIC, -EINVAL); assert_return(nl, -EINVAL);
/* don't allow appending to message once parsed */ /* don't allow appending to message once parsed */
if (!m->sealed) message_seal(m);
rtnl_message_seal(m);
for (unsigned i = 1; i <= m->n_containers; i++) for (unsigned i = 1; i <= m->n_containers; i++)
m->containers[i].attributes = mfree(m->containers[i].attributes); m->containers[i].attributes = mfree(m->containers[i].attributes);
@ -1304,37 +1336,22 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
assert(m->hdr); assert(m->hdr);
r = type_system_root_get_type(genl, &nl_type, m->hdr->nlmsg_type); r = type_system_root_get_type_system_and_header_size(nl, m->hdr->nlmsg_type,
&m->containers[0].type_system, &size);
if (r < 0) if (r < 0)
return r; return r;
type = type_get_type(nl_type); if (sd_netlink_message_is_error(m))
size = type_get_size(nl_type); return netlink_message_parse_error(m);
if (type == NETLINK_TYPE_NESTED) { return netlink_container_parse(m,
const NLTypeSystem *type_system; &m->containers[0],
(struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
type_get_type_system(nl_type, &type_system); NLMSG_PAYLOAD(m->hdr, size));
m->containers[0].type_system = type_system;
if (sd_netlink_message_is_error(m))
r = netlink_message_parse_error(m);
else
r = netlink_container_parse(m,
&m->containers[m->n_containers],
(struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
NLMSG_PAYLOAD(m->hdr, size));
if (r < 0)
return r;
}
return 0;
} }
void rtnl_message_seal(sd_netlink_message *m) { void message_seal(sd_netlink_message *m) {
assert(m); assert(m);
assert(!m->sealed);
m->sealed = true; m->sealed = true;
} }

View File

@ -70,25 +70,11 @@ void netlink_slot_disconnect(sd_netlink_slot *slot, bool unref) {
case NETLINK_MATCH_CALLBACK: case NETLINK_MATCH_CALLBACK:
LIST_REMOVE(match_callbacks, nl->match_callbacks, &slot->match_callback); LIST_REMOVE(match_callbacks, nl->match_callbacks, &slot->match_callback);
switch (slot->match_callback.type) { for (size_t i = 0; i < slot->match_callback.n_groups; i++)
case RTM_NEWLINK: (void) socket_broadcast_group_unref(nl, slot->match_callback.groups[i]);
case RTM_DELLINK:
(void) socket_broadcast_group_unref(nl, RTNLGRP_LINK);
break; slot->match_callback.n_groups = 0;
case RTM_NEWADDR: slot->match_callback.groups = mfree(slot->match_callback.groups);
case RTM_DELADDR:
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_IFADDR);
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_IFADDR);
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_ROUTE);
(void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_ROUTE);
break;
}
break; break;
default: default:

View File

@ -238,7 +238,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr
n = recvmsg_safe(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0)); n = recvmsg_safe(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
if (n == -ENOBUFS) if (n == -ENOBUFS)
return log_debug_errno(n, "rtnl: kernel receive buffer overrun"); return log_debug_errno(n, "sd-netlink: kernel receive buffer overrun");
if (IN_SET(n, -EAGAIN, -EINTR)) if (IN_SET(n, -EAGAIN, -EINTR))
return 0; return 0;
if (n < 0) if (n < 0)
@ -246,7 +246,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr
if (sender.nl.nl_pid != 0) { if (sender.nl.nl_pid != 0) {
/* not from the kernel, ignore */ /* not from the kernel, ignore */
log_debug("rtnl: ignoring message from PID %"PRIu32, sender.nl.nl_pid); log_debug("sd-netlink: ignoring message from PID %"PRIu32, sender.nl.nl_pid);
if (peek) { if (peek) {
/* drop the message */ /* drop the message */
@ -276,7 +276,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr
* If nothing useful was received 0 is returned. * If nothing useful was received 0 is returned.
* On failure, a negative error code is returned. * On failure, a negative error code is returned.
*/ */
int socket_read_message(sd_netlink *rtnl) { int socket_read_message(sd_netlink *nl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL;
bool multi_part = false, done = false; bool multi_part = false, done = false;
size_t len, allocated; size_t len, allocated;
@ -285,25 +285,25 @@ int socket_read_message(sd_netlink *rtnl) {
unsigned i = 0; unsigned i = 0;
int r; int r;
assert(rtnl); assert(nl);
assert(rtnl->rbuffer); assert(nl->rbuffer);
/* read nothing, just get the pending message size */ /* read nothing, just get the pending message size */
r = socket_recv_message(rtnl->fd, &iov, NULL, true); r = socket_recv_message(nl->fd, &iov, NULL, true);
if (r <= 0) if (r <= 0)
return r; return r;
else else
len = (size_t) r; len = (size_t) r;
/* make room for the pending message */ /* make room for the pending message */
if (!greedy_realloc((void **)&rtnl->rbuffer, len, sizeof(uint8_t))) if (!greedy_realloc((void**) &nl->rbuffer, len, sizeof(uint8_t)))
return -ENOMEM; return -ENOMEM;
allocated = MALLOC_SIZEOF_SAFE(rtnl->rbuffer); allocated = MALLOC_SIZEOF_SAFE(nl->rbuffer);
iov = IOVEC_MAKE(rtnl->rbuffer, allocated); iov = IOVEC_MAKE(nl->rbuffer, allocated);
/* read the pending message */ /* read the pending message */
r = socket_recv_message(rtnl->fd, &iov, &group, false); r = socket_recv_message(nl->fd, &iov, &group, false);
if (r <= 0) if (r <= 0)
return r; return r;
else else
@ -313,22 +313,22 @@ int socket_read_message(sd_netlink *rtnl) {
/* message did not fit in read buffer */ /* message did not fit in read buffer */
return -EIO; return -EIO;
if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) { if (NLMSG_OK(nl->rbuffer, len) && nl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
multi_part = true; multi_part = true;
for (i = 0; i < rtnl->rqueue_partial_size; i++) for (i = 0; i < nl->rqueue_partial_size; i++)
if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) == if (message_get_serial(nl->rqueue_partial[i]) ==
rtnl->rbuffer->nlmsg_seq) { nl->rbuffer->nlmsg_seq) {
first = rtnl->rqueue_partial[i]; first = nl->rqueue_partial[i];
break; break;
} }
} }
for (struct nlmsghdr *new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { for (struct nlmsghdr *new_msg = nl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type; size_t size;
if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid) if (!group && new_msg->nlmsg_pid != nl->sockaddr.nl.nl_pid)
/* not broadcast and not for us */ /* not broadcast and not for us */
continue; continue;
@ -346,7 +346,7 @@ int socket_read_message(sd_netlink *rtnl) {
} }
/* check that we support this message type */ /* check that we support this message type */
r = type_system_root_get_type(rtnl, &nl_type, new_msg->nlmsg_type); r = type_system_root_get_type_system_and_header_size(nl, new_msg->nlmsg_type, NULL, &size);
if (r < 0) { if (r < 0) {
if (r == -EOPNOTSUPP) if (r == -EOPNOTSUPP)
log_debug("sd-netlink: ignored message with unknown type: %i", log_debug("sd-netlink: ignored message with unknown type: %i",
@ -356,12 +356,12 @@ int socket_read_message(sd_netlink *rtnl) {
} }
/* check that the size matches the message type */ /* check that the size matches the message type */
if (new_msg->nlmsg_len < NLMSG_LENGTH(type_get_size(nl_type))) { if (new_msg->nlmsg_len < NLMSG_LENGTH(size)) {
log_debug("sd-netlink: message is shorter than expected, dropping"); log_debug("sd-netlink: message is shorter than expected, dropping");
continue; continue;
} }
r = message_new_empty(rtnl, &m); r = message_new_empty(nl, &m);
if (r < 0) if (r < 0)
return r; return r;
@ -372,7 +372,7 @@ int socket_read_message(sd_netlink *rtnl) {
return -ENOMEM; return -ENOMEM;
/* seal and parse the top-level message */ /* seal and parse the top-level message */
r = sd_netlink_message_rewind(m, rtnl); r = sd_netlink_message_rewind(m, nl);
if (r < 0) if (r < 0)
return r; return r;
@ -390,31 +390,31 @@ int socket_read_message(sd_netlink *rtnl) {
if (!multi_part || done) { if (!multi_part || done) {
/* we got a complete message, push it on the read queue */ /* we got a complete message, push it on the read queue */
r = rtnl_rqueue_make_room(rtnl); r = netlink_rqueue_make_room(nl);
if (r < 0) if (r < 0)
return r; return r;
rtnl->rqueue[rtnl->rqueue_size++] = TAKE_PTR(first); nl->rqueue[nl->rqueue_size++] = TAKE_PTR(first);
if (multi_part && (i < rtnl->rqueue_partial_size)) { if (multi_part && (i < nl->rqueue_partial_size)) {
/* remove the message form the partial read queue */ /* remove the message form the partial read queue */
memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1, memmove(nl->rqueue_partial + i, nl->rqueue_partial + i + 1,
sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1)); sizeof(sd_netlink_message*) * (nl->rqueue_partial_size - i - 1));
rtnl->rqueue_partial_size--; nl->rqueue_partial_size--;
} }
return 1; return 1;
} else { } else {
/* we only got a partial multi-part message, push it on the /* we only got a partial multi-part message, push it on the
partial read queue */ partial read queue */
if (i < rtnl->rqueue_partial_size) if (i < nl->rqueue_partial_size)
rtnl->rqueue_partial[i] = TAKE_PTR(first); nl->rqueue_partial[i] = TAKE_PTR(first);
else { else {
r = rtnl_rqueue_partial_make_room(rtnl); r = netlink_rqueue_partial_make_room(nl);
if (r < 0) if (r < 0)
return r; return r;
rtnl->rqueue_partial[rtnl->rqueue_partial_size++] = TAKE_PTR(first); nl->rqueue_partial[nl->rqueue_partial_size++] = TAKE_PTR(first);
} }
return 0; return 0;

View File

@ -0,0 +1,234 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/batman_adv.h>
#include <linux/fou.h>
#include <linux/genetlink.h>
#include <linux/if.h>
#include <linux/if_macsec.h>
#include <linux/l2tp.h>
#include <linux/nl80211.h>
#include <linux/wireguard.h>
#include "netlink-genl.h"
#include "netlink-types-internal.h"
/***************** genl ctrl type systems *****************/
static const NLType genl_ctrl_mcast_group_types[] = {
[CTRL_ATTR_MCAST_GRP_NAME] = { .type = NETLINK_TYPE_STRING },
[CTRL_ATTR_MCAST_GRP_ID] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(genl_ctrl_mcast_group);
static const NLType genl_ctrl_ops_types[] = {
[CTRL_ATTR_OP_ID] = { .type = NETLINK_TYPE_U32 },
[CTRL_ATTR_OP_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(genl_ctrl_ops);
static const NLType genl_ctrl_types[] = {
[CTRL_ATTR_FAMILY_ID] = { .type = NETLINK_TYPE_U16 },
[CTRL_ATTR_FAMILY_NAME] = { .type = NETLINK_TYPE_STRING },
[CTRL_ATTR_VERSION] = { .type = NETLINK_TYPE_U32 },
[CTRL_ATTR_HDRSIZE] = { .type = NETLINK_TYPE_U32 },
[CTRL_ATTR_MAXATTR] = { .type = NETLINK_TYPE_U32 },
[CTRL_ATTR_OPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_ops_type_system },
[CTRL_ATTR_MCAST_GROUPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_mcast_group_type_system },
/*
[CTRL_ATTR_POLICY] = { .type = NETLINK_TYPE_NESTED, },
[CTRL_ATTR_OP_POLICY] = { .type = NETLINK_TYPE_NESTED, }
*/
[CTRL_ATTR_OP] = { .type = NETLINK_TYPE_U32 },
};
/***************** genl batadv type systems *****************/
static const NLType genl_batadv_types[] = {
[BATADV_ATTR_VERSION] = { .type = NETLINK_TYPE_STRING },
[BATADV_ATTR_ALGO_NAME] = { .type = NETLINK_TYPE_STRING },
[BATADV_ATTR_MESH_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_MESH_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ },
[BATADV_ATTR_MESH_ADDRESS] = { .size = ETH_ALEN },
[BATADV_ATTR_HARD_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_HARD_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ },
[BATADV_ATTR_HARD_ADDRESS] = { .size = ETH_ALEN },
[BATADV_ATTR_ORIG_ADDRESS] = { .size = ETH_ALEN },
[BATADV_ATTR_TPMETER_RESULT] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_TPMETER_TEST_TIME] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_TPMETER_BYTES] = { .type = NETLINK_TYPE_U64 },
[BATADV_ATTR_TPMETER_COOKIE] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_PAD] = { .type = NETLINK_TYPE_UNSPEC },
[BATADV_ATTR_ACTIVE] = { .type = NETLINK_TYPE_FLAG },
[BATADV_ATTR_TT_ADDRESS] = { .size = ETH_ALEN },
[BATADV_ATTR_TT_TTVN] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_TT_LAST_TTVN] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_TT_CRC32] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_TT_VID] = { .type = NETLINK_TYPE_U16 },
[BATADV_ATTR_TT_FLAGS] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_FLAG_BEST] = { .type = NETLINK_TYPE_FLAG },
[BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_NEIGH_ADDRESS] = { .size = ETH_ALEN },
[BATADV_ATTR_TQ] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_THROUGHPUT] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_ROUTER] = { .size = ETH_ALEN },
[BATADV_ATTR_BLA_OWN] = { .type = NETLINK_TYPE_FLAG },
[BATADV_ATTR_BLA_ADDRESS] = { .size = ETH_ALEN },
[BATADV_ATTR_BLA_VID] = { .type = NETLINK_TYPE_U16 },
[BATADV_ATTR_BLA_BACKBONE] = { .size = ETH_ALEN },
[BATADV_ATTR_BLA_CRC] = { .type = NETLINK_TYPE_U16 },
[BATADV_ATTR_DAT_CACHE_IP4ADDRESS] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_DAT_CACHE_HWADDRESS] = { .size = ETH_ALEN },
[BATADV_ATTR_DAT_CACHE_VID] = { .type = NETLINK_TYPE_U16 },
[BATADV_ATTR_MCAST_FLAGS] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_VLANID] = { .type = NETLINK_TYPE_U16 },
[BATADV_ATTR_AGGREGATED_OGMS_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_AP_ISOLATION_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_ISOLATION_MARK] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_ISOLATION_MASK] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_BONDING_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_FRAGMENTATION_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_GW_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_GW_MODE] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_GW_SEL_CLASS] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_HOP_PENALTY] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_LOG_LEVEL] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_MULTICAST_FANOUT] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_NETWORK_CODING_ENABLED] = { .type = NETLINK_TYPE_U8 },
[BATADV_ATTR_ORIG_INTERVAL] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_ELP_INTERVAL] = { .type = NETLINK_TYPE_U32 },
[BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NETLINK_TYPE_U32 },
};
/***************** genl fou type systems *****************/
static const NLType genl_fou_types[] = {
[FOU_ATTR_PORT] = { .type = NETLINK_TYPE_U16 },
[FOU_ATTR_AF] = { .type = NETLINK_TYPE_U8 },
[FOU_ATTR_IPPROTO] = { .type = NETLINK_TYPE_U8 },
[FOU_ATTR_TYPE] = { .type = NETLINK_TYPE_U8 },
[FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG },
[FOU_ATTR_LOCAL_V4] = { .type = NETLINK_TYPE_IN_ADDR },
[FOU_ATTR_PEER_V4] = { .type = NETLINK_TYPE_IN_ADDR },
[FOU_ATTR_LOCAL_V6] = { .type = NETLINK_TYPE_IN_ADDR },
[FOU_ATTR_PEER_V6] = { .type = NETLINK_TYPE_IN_ADDR},
[FOU_ATTR_PEER_PORT] = { .type = NETLINK_TYPE_U16},
[FOU_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32},
};
/***************** genl l2tp type systems *****************/
static const NLType genl_l2tp_types[] = {
[L2TP_ATTR_PW_TYPE] = { .type = NETLINK_TYPE_U16 },
[L2TP_ATTR_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
[L2TP_ATTR_OFFSET] = { .type = NETLINK_TYPE_U16 },
[L2TP_ATTR_DATA_SEQ] = { .type = NETLINK_TYPE_U16 },
[L2TP_ATTR_L2SPEC_TYPE] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_L2SPEC_LEN] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_PROTO_VERSION] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_IFNAME] = { .type = NETLINK_TYPE_STRING },
[L2TP_ATTR_CONN_ID] = { .type = NETLINK_TYPE_U32 },
[L2TP_ATTR_PEER_CONN_ID] = { .type = NETLINK_TYPE_U32 },
[L2TP_ATTR_SESSION_ID] = { .type = NETLINK_TYPE_U32 },
[L2TP_ATTR_PEER_SESSION_ID] = { .type = NETLINK_TYPE_U32 },
[L2TP_ATTR_UDP_CSUM] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_VLAN_ID] = { .type = NETLINK_TYPE_U16 },
[L2TP_ATTR_RECV_SEQ] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_SEND_SEQ] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_LNS_MODE] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_USING_IPSEC] = { .type = NETLINK_TYPE_U8 },
[L2TP_ATTR_FD] = { .type = NETLINK_TYPE_U32 },
[L2TP_ATTR_IP_SADDR] = { .type = NETLINK_TYPE_IN_ADDR },
[L2TP_ATTR_IP_DADDR] = { .type = NETLINK_TYPE_IN_ADDR },
[L2TP_ATTR_UDP_SPORT] = { .type = NETLINK_TYPE_U16 },
[L2TP_ATTR_UDP_DPORT] = { .type = NETLINK_TYPE_U16 },
[L2TP_ATTR_IP6_SADDR] = { .type = NETLINK_TYPE_IN_ADDR },
[L2TP_ATTR_IP6_DADDR] = { .type = NETLINK_TYPE_IN_ADDR },
[L2TP_ATTR_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_FLAG },
[L2TP_ATTR_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_FLAG },
};
/***************** genl macsec type systems *****************/
static const NLType genl_macsec_rxsc_types[] = {
[MACSEC_RXSC_ATTR_SCI] = { .type = NETLINK_TYPE_U64 },
};
DEFINE_TYPE_SYSTEM(genl_macsec_rxsc);
static const NLType genl_macsec_sa_types[] = {
[MACSEC_SA_ATTR_AN] = { .type = NETLINK_TYPE_U8 },
[MACSEC_SA_ATTR_ACTIVE] = { .type = NETLINK_TYPE_U8 },
[MACSEC_SA_ATTR_PN] = { .type = NETLINK_TYPE_U32 },
[MACSEC_SA_ATTR_KEYID] = { .size = MACSEC_KEYID_LEN },
[MACSEC_SA_ATTR_KEY] = { .size = MACSEC_MAX_KEY_LEN },
};
DEFINE_TYPE_SYSTEM(genl_macsec_sa);
static const NLType genl_macsec_types[] = {
[MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[MACSEC_ATTR_RXSC_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_rxsc_type_system },
[MACSEC_ATTR_SA_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_type_system },
};
/***************** genl nl80211 type systems *****************/
static const NLType genl_nl80211_types[] = {
[NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR },
[NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_STRING },
[NL80211_ATTR_IFTYPE] = { .type = NETLINK_TYPE_U32 },
};
/***************** genl wireguard type systems *****************/
static const NLType genl_wireguard_allowedip_types[] = {
[WGALLOWEDIP_A_FAMILY] = { .type = NETLINK_TYPE_U16 },
[WGALLOWEDIP_A_IPADDR] = { .type = NETLINK_TYPE_IN_ADDR },
[WGALLOWEDIP_A_CIDR_MASK] = { .type = NETLINK_TYPE_U8 },
};
DEFINE_TYPE_SYSTEM(genl_wireguard_allowedip);
static const NLType genl_wireguard_peer_types[] = {
[WGPEER_A_PUBLIC_KEY] = { .size = WG_KEY_LEN },
[WGPEER_A_FLAGS] = { .type = NETLINK_TYPE_U32 },
[WGPEER_A_PRESHARED_KEY] = { .size = WG_KEY_LEN },
[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NETLINK_TYPE_U16 },
[WGPEER_A_ENDPOINT] = { .type = NETLINK_TYPE_SOCKADDR },
[WGPEER_A_ALLOWEDIPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_allowedip_type_system },
};
DEFINE_TYPE_SYSTEM(genl_wireguard_peer);
static const NLType genl_wireguard_types[] = {
[WGDEVICE_A_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[WGDEVICE_A_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ-1 },
[WGDEVICE_A_FLAGS] = { .type = NETLINK_TYPE_U32 },
[WGDEVICE_A_PRIVATE_KEY] = { .size = WG_KEY_LEN },
[WGDEVICE_A_LISTEN_PORT] = { .type = NETLINK_TYPE_U16 },
[WGDEVICE_A_FWMARK] = { .type = NETLINK_TYPE_U32 },
[WGDEVICE_A_PEERS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_peer_type_system },
};
/***************** genl families *****************/
static const NLTypeSystemUnionElement genl_type_systems[] = {
{ .name = CTRL_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_ctrl), },
{ .name = BATADV_NL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_batadv), },
{ .name = FOU_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_fou), },
{ .name = L2TP_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_l2tp), },
{ .name = MACSEC_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_macsec), },
{ .name = NL80211_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_nl80211), },
{ .name = WG_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_wireguard), },
};
/* This is the root type system union, so match_attribute is not necessary. */
DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(genl, 0);
const NLTypeSystem *genl_get_type_system_by_name(const char *name) {
return type_system_union_get_type_system_by_string(&genl_type_system_union, name);
}

View File

@ -0,0 +1,49 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "macro.h"
#include "netlink-types.h"
struct NLType {
uint16_t type;
size_t size;
const NLTypeSystem *type_system;
const NLTypeSystemUnion *type_system_union;
};
struct NLTypeSystem {
uint16_t count;
const NLType *types;
};
typedef struct NLTypeSystemUnionElement {
union {
int protocol;
const char *name;
};
NLTypeSystem type_system;
} NLTypeSystemUnionElement;
struct NLTypeSystemUnion {
size_t count;
const NLTypeSystemUnionElement *elements;
NLMatchType match_type;
uint16_t match_attribute;
};
#define TYPE_SYSTEM_FROM_TYPE(name) \
{ .count = ELEMENTSOF(name##_types), .types = name##_types }
#define DEFINE_TYPE_SYSTEM(name) \
static const NLTypeSystem name##_type_system = TYPE_SYSTEM_FROM_TYPE(name)
#define _DEFINE_TYPE_SYSTEM_UNION(name, type, attr) \
static const NLTypeSystemUnion name##_type_system_union = { \
.count = ELEMENTSOF(name##_type_systems), \
.elements = name##_type_systems, \
.match_type = type, \
.match_attribute = attr, \
}
#define DEFINE_TYPE_SYSTEM_UNION_MATCH_PROTOCOL(name) \
_DEFINE_TYPE_SYSTEM_UNION(name, NL_MATCH_PROTOCOL, 0)
#define DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(name, attr) \
_DEFINE_TYPE_SYSTEM_UNION(name, NL_MATCH_SIBLING, attr)

View File

@ -0,0 +1,197 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include "netlink-types-internal.h"
#include "string-table.h"
static const NLType nfnl_nft_table_types[] = {
[NFTA_TABLE_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_TABLE_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_table);
static const NLType nfnl_nft_chain_hook_types[] = {
[NFTA_HOOK_HOOKNUM] = { .type = NETLINK_TYPE_U32 },
[NFTA_HOOK_PRIORITY] = { .type = NETLINK_TYPE_U32 },
[NFTA_HOOK_DEV] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_chain_hook);
static const NLType nfnl_nft_chain_types[] = {
[NFTA_CHAIN_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_CHAIN_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_CHAIN_HOOK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_hook_type_system },
[NFTA_CHAIN_TYPE] = { .type = NETLINK_TYPE_STRING, .size = 16 },
[NFTA_CHAIN_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_chain);
static const NLType nfnl_nft_expr_meta_types[] = {
[NFTA_META_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_META_KEY] = { .type = NETLINK_TYPE_U32 },
[NFTA_META_SREG] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_payload_types[] = {
[NFTA_PAYLOAD_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_PAYLOAD_BASE] = { .type = NETLINK_TYPE_U32 },
[NFTA_PAYLOAD_OFFSET] = { .type = NETLINK_TYPE_U32 },
[NFTA_PAYLOAD_LEN] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_nat_types[] = {
[NFTA_NAT_TYPE] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_FAMILY] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_ADDR_MIN] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_ADDR_MAX] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_data_types[] = {
[NFTA_DATA_VALUE] = { .type = NETLINK_TYPE_BINARY },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_data);
static const NLType nfnl_nft_expr_bitwise_types[] = {
[NFTA_BITWISE_SREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_BITWISE_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_BITWISE_LEN] = { .type = NETLINK_TYPE_U32 },
[NFTA_BITWISE_MASK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
[NFTA_BITWISE_XOR] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
};
static const NLType nfnl_nft_expr_cmp_types[] = {
[NFTA_CMP_SREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_CMP_OP] = { .type = NETLINK_TYPE_U32 },
[NFTA_CMP_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
};
static const NLType nfnl_nft_expr_fib_types[] = {
[NFTA_FIB_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_FIB_RESULT] = { .type = NETLINK_TYPE_U32 },
[NFTA_FIB_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_lookup_types[] = {
[NFTA_LOOKUP_SET] = { .type = NETLINK_TYPE_STRING },
[NFTA_LOOKUP_SREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_LOOKUP_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_LOOKUP_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_masq_types[] = {
[NFTA_MASQ_FLAGS] = { .type = NETLINK_TYPE_U32 },
[NFTA_MASQ_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
[NFTA_MASQ_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystemUnionElement nfnl_expr_data_type_systems[] = {
{ .name = "bitwise", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_bitwise), },
{ .name = "cmp", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_cmp), },
{ .name = "fib", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_fib), },
{ .name = "lookup", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_lookup), },
{ .name = "masq", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_masq), },
{ .name = "meta", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_meta), },
{ .name = "nat", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_nat), },
{ .name = "payload", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_payload), },
};
DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(nfnl_expr_data, NFTA_EXPR_NAME);
static const NLType nfnl_nft_rule_expr_types[] = {
[NFTA_EXPR_NAME] = { .type = NETLINK_TYPE_STRING, .size = 16 },
[NFTA_EXPR_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &nfnl_expr_data_type_system_union },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_rule_expr);
static const NLType nfnl_nft_rule_types[] = {
[NFTA_RULE_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_RULE_CHAIN] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_RULE_EXPRESSIONS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_expr_type_system }
};
DEFINE_TYPE_SYSTEM(nfnl_nft_rule);
static const NLType nfnl_nft_set_types[] = {
[NFTA_SET_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_FLAGS] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_KEY_TYPE] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_KEY_LEN] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_DATA_TYPE] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_DATA_LEN] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_POLICY] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_ID] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_set);
static const NLType nfnl_nft_setelem_types[] = {
[NFTA_SET_ELEM_KEY] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
[NFTA_SET_ELEM_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
[NFTA_SET_ELEM_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_setelem);
static const NLType nfnl_nft_setelem_list_types[] = {
[NFTA_SET_ELEM_LIST_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_LIST_SET] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_type_system },
};
DEFINE_TYPE_SYSTEM(nfnl_nft_setelem_list);
static const NLType nfnl_subsys_nft_types [] = {
[NFT_MSG_DELTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWCHAIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWSET] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_set_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_DELSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
};
DEFINE_TYPE_SYSTEM(nfnl_subsys_nft);
static const NLType nfnl_msg_batch_types [] = {
[NFNL_BATCH_GENID] = { .type = NETLINK_TYPE_U32 }
};
DEFINE_TYPE_SYSTEM(nfnl_msg_batch);
static const NLType nfnl_subsys_none_types[] = {
[NFNL_MSG_BATCH_BEGIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
[NFNL_MSG_BATCH_END] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
};
DEFINE_TYPE_SYSTEM(nfnl_subsys_none);
static const NLType nfnl_types[] = {
[NFNL_SUBSYS_NONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_subsys_none_type_system },
[NFNL_SUBSYS_NFTABLES] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_subsys_nft_type_system },
};
DEFINE_TYPE_SYSTEM(nfnl);
const NLType *nfnl_get_type(uint16_t nlmsg_type) {
const NLTypeSystem *subsys;
subsys = type_system_get_type_system(&nfnl_type_system, nlmsg_type >> 8);
if (!subsys)
return NULL;
return type_system_get_type(subsys, nlmsg_type & ((1U << 8) - 1));
}

View File

@ -0,0 +1,872 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/batman_adv.h>
#include <linux/can/netlink.h>
#include <linux/can/vxcan.h>
#include <linux/fib_rules.h>
#include <linux/fou.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/if_addrlabel.h>
#include <linux/if_bridge.h>
#include <linux/if_link.h>
#include <linux/if_macsec.h>
#include <linux/if_tunnel.h>
#include <linux/ip.h>
#include <linux/l2tp.h>
#include <linux/netlink.h>
#include <linux/nexthop.h>
#include <linux/nl80211.h>
#include <linux/pkt_sched.h>
#include <linux/rtnetlink.h>
#include <linux/veth.h>
#include <linux/wireguard.h>
#include "sd-netlink.h"
#include "netlink-types-internal.h"
#include "string-table.h"
/* Maximum ARP IP target defined in kernel */
#define BOND_MAX_ARP_TARGETS 16
typedef enum {
BOND_ARP_TARGETS_0,
BOND_ARP_TARGETS_1,
BOND_ARP_TARGETS_2,
BOND_ARP_TARGETS_3,
BOND_ARP_TARGETS_4,
BOND_ARP_TARGETS_5,
BOND_ARP_TARGETS_6,
BOND_ARP_TARGETS_7,
BOND_ARP_TARGETS_8,
BOND_ARP_TARGETS_9,
BOND_ARP_TARGETS_10,
BOND_ARP_TARGETS_11,
BOND_ARP_TARGETS_12,
BOND_ARP_TARGETS_13,
BOND_ARP_TARGETS_14,
BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS,
} BondArpTargets;
static const NLTypeSystem rtnl_link_type_system;
static const NLType rtnl_link_info_data_batadv_types[] = {
[IFLA_BATADV_ALGO_NAME] = { .type = NETLINK_TYPE_STRING, .size = 20 },
};
static const NLType rtnl_link_info_data_veth_types[] = {
[VETH_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
};
static const NLType rtnl_link_info_data_vxcan_types[] = {
[VXCAN_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
};
static const NLType rtnl_link_info_data_ipvlan_types[] = {
[IFLA_IPVLAN_MODE] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_macvlan_macaddr_types[] = {
[IFLA_MACVLAN_MACADDR] = { .type = NETLINK_TYPE_ETHER_ADDR },
};
DEFINE_TYPE_SYSTEM(rtnl_macvlan_macaddr);
static const NLType rtnl_link_info_data_macvlan_types[] = {
[IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_MACVLAN_MACADDR_MODE] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACVLAN_MACADDR_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_macvlan_macaddr_type_system },
[IFLA_MACVLAN_MACADDR_COUNT] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACVLAN_BC_QUEUE_LEN] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACVLAN_BC_QUEUE_LEN_USED] = { .type = NETLINK_TYPE_REJECT },
};
static const NLType rtnl_link_info_data_bridge_types[] = {
[IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_VLAN_FILTERING] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_ROOT_PORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_ROOT_PATH_COST] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_TOPOLOGY_CHANGE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_TOPOLOGY_CHANGE_DETECTED] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_HELLO_TIMER] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_TCN_TIMER] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_TOPOLOGY_CHANGE_TIMER] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_GC_TIMER] = { .type = NETLINK_TYPE_U64 },
[IFLA_BR_GROUP_ADDR] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_FDB_FLUSH] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_MCAST_ROUTER] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_MCAST_SNOOPING] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_MCAST_QUERIER] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_MCAST_HASH_MAX] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NETLINK_TYPE_U32 },
[IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NETLINK_TYPE_U64 },
[IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NETLINK_TYPE_U64 },
[IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NETLINK_TYPE_U64 },
[IFLA_BR_MCAST_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 },
[IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
[IFLA_BR_NF_CALL_IPTABLES] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_NF_CALL_IP6TABLES] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_NF_CALL_ARPTABLES] = { .type = NETLINK_TYPE_U8 },
[IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NETLINK_TYPE_U16 },
[IFLA_BR_MCAST_IGMP_VERSION] = { .type = NETLINK_TYPE_U8 },
};
static const NLType rtnl_vlan_qos_map_types[] = {
[IFLA_VLAN_QOS_MAPPING] = { .size = sizeof(struct ifla_vlan_qos_mapping) },
};
DEFINE_TYPE_SYSTEM(rtnl_vlan_qos_map);
static const NLType rtnl_link_info_data_vlan_types[] = {
[IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 },
[IFLA_VLAN_FLAGS] = { .size = sizeof(struct ifla_vlan_flags) },
[IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system },
[IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system },
[IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_link_info_data_vxlan_types[] = {
[IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 },
[IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 },
[IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 },
[IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32},
[IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_PORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_VXLAN_GROUP6] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_VXLAN_LOCAL6] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_VXLAN_UDP_CSUM] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_REMCSUM_TX] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_REMCSUM_RX] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_GBP] = { .type = NETLINK_TYPE_FLAG },
[IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG },
[IFLA_VXLAN_COLLECT_METADATA] = { .type = NETLINK_TYPE_U8 },
[IFLA_VXLAN_LABEL] = { .type = NETLINK_TYPE_U32 },
[IFLA_VXLAN_GPE] = { .type = NETLINK_TYPE_FLAG },
[IFLA_VXLAN_TTL_INHERIT] = { .type = NETLINK_TYPE_FLAG },
[IFLA_VXLAN_DF] = { .type = NETLINK_TYPE_U8 },
};
static const NLType rtnl_bond_arp_target_types[] = {
[BOND_ARP_TARGETS_0] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_1] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_2] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_3] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_4] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_5] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_6] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_7] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_8] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_9] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_10] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_11] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_12] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_13] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_14] = { .type = NETLINK_TYPE_U32 },
[BOND_ARP_TARGETS_MAX] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(rtnl_bond_arp_target);
static const NLType rtnl_link_info_data_bond_types[] = {
[IFLA_BOND_MODE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_ACTIVE_SLAVE] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_MIIMON] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_UPDELAY] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_DOWNDELAY] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_USE_CARRIER] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_ARP_INTERVAL] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_ARP_IP_TARGET] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_bond_arp_target_type_system },
[IFLA_BOND_ARP_VALIDATE] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_ARP_ALL_TARGETS] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_PRIMARY] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_PRIMARY_RESELECT] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_FAIL_OVER_MAC] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_XMIT_HASH_POLICY] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_RESEND_IGMP] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_NUM_PEER_NOTIF] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_ALL_SLAVES_ACTIVE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_MIN_LINKS] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_LP_INTERVAL] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NETLINK_TYPE_U32 },
[IFLA_BOND_AD_LACP_RATE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_AD_SELECT] = { .type = NETLINK_TYPE_U8 },
[IFLA_BOND_AD_INFO] = { .type = NETLINK_TYPE_NESTED },
[IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NETLINK_TYPE_U16 },
[IFLA_BOND_AD_USER_PORT_KEY] = { .type = NETLINK_TYPE_U16 },
[IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NETLINK_TYPE_ETHER_ADDR },
[IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NETLINK_TYPE_U8 },
};
static const NLType rtnl_link_info_data_iptun_types[] = {
[IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_TOS] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_6RD_PREFIX] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_link_info_data_ipgre_types[] = {
[IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 },
[IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 },
[IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 },
[IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 },
[IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
[IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
[IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 },
[IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
[IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_GRE_ERSPAN_INDEX] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_link_info_data_ipvti_types[] = {
[IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 },
[IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 },
[IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
};
static const NLType rtnl_link_info_data_ip6tnl_types[] = {
[IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_ENCAP_LIMIT] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_link_info_data_vrf_types[] = {
[IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_link_info_data_geneve_types[] = {
[IFLA_GENEVE_ID] = { .type = NETLINK_TYPE_U32 },
[IFLA_GENEVE_TTL] = { .type = NETLINK_TYPE_U8 },
[IFLA_GENEVE_TOS] = { .type = NETLINK_TYPE_U8 },
[IFLA_GENEVE_PORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_GENEVE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_GENEVE_REMOTE6] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_GENEVE_UDP_CSUM] = { .type = NETLINK_TYPE_U8 },
[IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 },
[IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 },
[IFLA_GENEVE_LABEL] = { .type = NETLINK_TYPE_U32 },
[IFLA_GENEVE_TTL_INHERIT] = { .type = NETLINK_TYPE_U8 },
[IFLA_GENEVE_DF] = { .type = NETLINK_TYPE_U8 },
};
static const NLType rtnl_link_info_data_can_types[] = {
[IFLA_CAN_BITTIMING] = { .size = sizeof(struct can_bittiming) },
[IFLA_CAN_RESTART_MS] = { .type = NETLINK_TYPE_U32 },
[IFLA_CAN_CTRLMODE] = { .size = sizeof(struct can_ctrlmode) },
[IFLA_CAN_TERMINATION] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_link_info_data_macsec_types[] = {
[IFLA_MACSEC_SCI] = { .type = NETLINK_TYPE_U64 },
[IFLA_MACSEC_PORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_MACSEC_ICV_LEN] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_CIPHER_SUITE] = { .type = NETLINK_TYPE_U64 },
[IFLA_MACSEC_WINDOW] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACSEC_ENCODING_SA] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_ENCRYPT] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_PROTECT] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_INC_SCI] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_ES] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_SCB] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_REPLAY_PROTECT] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_VALIDATION] = { .type = NETLINK_TYPE_U8 },
};
static const NLType rtnl_link_info_data_xfrm_types[] = {
[IFLA_XFRM_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_XFRM_IF_ID] = { .type = NETLINK_TYPE_U32 }
};
static const NLType rtnl_link_info_data_bareudp_types[] = {
[IFLA_BAREUDP_PORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_BAREUDP_ETHERTYPE] = { .type = NETLINK_TYPE_U16 },
[IFLA_BAREUDP_SRCPORT_MIN] = { .type = NETLINK_TYPE_U16 },
[IFLA_BAREUDP_MULTIPROTO_MODE] = { .type = NETLINK_TYPE_FLAG },
};
static const NLTypeSystemUnionElement rtnl_link_info_data_type_systems[] = {
{ .name = "bareudp", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_bareudp), },
{ .name = "batadv", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_batadv), },
{ .name = "bond", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_bond), },
{ .name = "bridge", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_bridge), },
{ .name = "can", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_can), },
{ .name = "dummy", },
{ .name = "erspan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), },
{ .name = "geneve", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_geneve), },
{ .name = "gre", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), },
{ .name = "gretap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), },
{ .name = "ifb", },
{ .name = "ip6gre", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), },
{ .name = "ip6gretap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), },
{ .name = "ip6tnl", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ip6tnl), },
{ .name = "ipip", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_iptun), },
{ .name = "ipvlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvlan), },
{ .name = "ipvtap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvlan), },
{ .name = "macsec", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_macsec), },
{ .name = "macvlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_macvlan), },
{ .name = "macvtap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_macvlan), },
{ .name = "netdevsim", },
{ .name = "nlmon", },
{ .name = "sit", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_iptun), },
{ .name = "vcan", },
{ .name = "veth", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_veth), },
{ .name = "vlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vlan), },
{ .name = "vrf", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vrf), },
{ .name = "vti", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvti), },
{ .name = "vti6", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvti), },
{ .name = "vxcan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vxcan), },
{ .name = "vxlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vxlan), },
{ .name = "wireguard", },
{ .name = "xfrm", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_xfrm), },
};
DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(rtnl_link_info_data, IFLA_INFO_KIND);
static const NLType rtnl_link_info_types[] = {
[IFLA_INFO_KIND] = { .type = NETLINK_TYPE_STRING },
[IFLA_INFO_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union },
/*
[IFLA_INFO_XSTATS],
[IFLA_INFO_SLAVE_KIND] = { .type = NETLINK_TYPE_STRING },
[IFLA_INFO_SLAVE_DATA] = { .type = NETLINK_TYPE_NESTED },
*/
};
DEFINE_TYPE_SYSTEM(rtnl_link_info);
static const struct NLType rtnl_prot_info_bridge_port_types[] = {
[IFLA_BRPORT_STATE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_COST] = { .type = NETLINK_TYPE_U32 },
[IFLA_BRPORT_PRIORITY] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_PROXYARP_WIFI] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_ROOT_ID] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_BRIDGE_ID] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_DESIGNATED_PORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRPORT_DESIGNATED_COST] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRPORT_ID] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRPORT_NO] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_CONFIG_PENDING] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_MESSAGE_AGE_TIMER] = { .type = NETLINK_TYPE_U64 },
[IFLA_BRPORT_FORWARD_DELAY_TIMER] = { .type = NETLINK_TYPE_U64 },
[IFLA_BRPORT_HOLD_TIMER] = { .type = NETLINK_TYPE_U64 },
[IFLA_BRPORT_FLUSH] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_PAD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_MCAST_FLOOD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_VLAN_TUNNEL] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_BCAST_FLOOD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRPORT_NEIGH_SUPPRESS] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_ISOLATED] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_BACKUP_PORT] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystemUnionElement rtnl_prot_info_type_systems[] = {
{ .protocol = AF_BRIDGE, .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_prot_info_bridge_port), },
};
DEFINE_TYPE_SYSTEM_UNION_MATCH_PROTOCOL(rtnl_prot_info);
static const struct NLType rtnl_af_spec_inet6_types[] = {
[IFLA_INET6_FLAGS] = { .type = NETLINK_TYPE_U32 },
/*
IFLA_INET6_CONF,
IFLA_INET6_STATS,
IFLA_INET6_MCAST,
IFLA_INET6_CACHEINFO,
IFLA_INET6_ICMP6STATS,
*/
[IFLA_INET6_TOKEN] = { .type = NETLINK_TYPE_IN_ADDR },
[IFLA_INET6_ADDR_GEN_MODE] = { .type = NETLINK_TYPE_U8 },
};
DEFINE_TYPE_SYSTEM(rtnl_af_spec_inet6);
static const NLType rtnl_af_spec_unspec_types[] = {
[AF_INET6] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
};
static const NLType rtnl_af_spec_bridge_types[] = {
[IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRIDGE_VLAN_INFO] = { .size = sizeof(struct bridge_vlan_info) },
};
static const NLTypeSystemUnionElement rtnl_af_spec_type_systems[] = {
{ .protocol = AF_UNSPEC, .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_af_spec_unspec), },
{ .protocol = AF_BRIDGE, .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_af_spec_bridge), },
};
DEFINE_TYPE_SYSTEM_UNION_MATCH_PROTOCOL(rtnl_af_spec);
static const NLType rtnl_prop_list_types[] = {
[IFLA_ALT_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = ALTIFNAMSIZ - 1 },
};
DEFINE_TYPE_SYSTEM(rtnl_prop_list);
static const NLType rtnl_vf_vlan_list_types[] = {
[IFLA_VF_VLAN_INFO] = { .size = sizeof(struct ifla_vf_vlan_info) },
};
DEFINE_TYPE_SYSTEM(rtnl_vf_vlan_list);
static const NLType rtnl_vf_info_types[] = {
[IFLA_VF_MAC] = { .size = sizeof(struct ifla_vf_mac) },
[IFLA_VF_VLAN] = { .size = sizeof(struct ifla_vf_vlan) },
[IFLA_VF_VLAN_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_vlan_list_type_system},
[IFLA_VF_TX_RATE] = { .size = sizeof(struct ifla_vf_tx_rate) },
[IFLA_VF_SPOOFCHK] = { .size = sizeof(struct ifla_vf_spoofchk) },
[IFLA_VF_RATE] = { .size = sizeof(struct ifla_vf_rate) },
[IFLA_VF_LINK_STATE] = { .size = sizeof(struct ifla_vf_link_state) },
[IFLA_VF_RSS_QUERY_EN] = { .size = sizeof(struct ifla_vf_rss_query_en) },
[IFLA_VF_TRUST] = { .size = sizeof(struct ifla_vf_trust) },
[IFLA_VF_IB_NODE_GUID] = { .size = sizeof(struct ifla_vf_guid) },
[IFLA_VF_IB_PORT_GUID] = { .size = sizeof(struct ifla_vf_guid) },
};
DEFINE_TYPE_SYSTEM(rtnl_vf_info);
static const NLType rtnl_vfinfo_list_types[] = {
[IFLA_VF_INFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_info_type_system },
};
DEFINE_TYPE_SYSTEM(rtnl_vfinfo_list);
static const NLType rtnl_link_types[] = {
[IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR },
[IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR },
[IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
[IFLA_MTU] = { .type = NETLINK_TYPE_U32 },
[IFLA_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_QDISC] = { .type = NETLINK_TYPE_STRING },
[IFLA_STATS] = { .size = sizeof(struct rtnl_link_stats) },
/*
[IFLA_COST],
[IFLA_PRIORITY],
*/
[IFLA_MASTER] = { .type = NETLINK_TYPE_U32 },
/*
[IFLA_WIRELESS],
*/
[IFLA_PROTINFO] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
[IFLA_TXQLEN] = { .type = NETLINK_TYPE_U32 },
/*
[IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
*/
[IFLA_WEIGHT] = { .type = NETLINK_TYPE_U32 },
[IFLA_OPERSTATE] = { .type = NETLINK_TYPE_U8 },
[IFLA_LINKMODE] = { .type = NETLINK_TYPE_U8 },
[IFLA_LINKINFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system },
[IFLA_NET_NS_PID] = { .type = NETLINK_TYPE_U32 },
[IFLA_IFALIAS] = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 },
[IFLA_NUM_VF] = { .type = NETLINK_TYPE_U32 },
[IFLA_VFINFO_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vfinfo_list_type_system },
[IFLA_STATS64] = { .size = sizeof(struct rtnl_link_stats64) },
/*
[IFLA_VF_PORTS] = { .type = NETLINK_TYPE_NESTED },
[IFLA_PORT_SELF] = { .type = NETLINK_TYPE_NESTED },
*/
[IFLA_AF_SPEC] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_af_spec_type_system_union },
/*
[IFLA_VF_PORTS],
[IFLA_PORT_SELF],
*/
[IFLA_GROUP] = { .type = NETLINK_TYPE_U32 },
[IFLA_NET_NS_FD] = { .type = NETLINK_TYPE_U32 },
[IFLA_EXT_MASK] = { .type = NETLINK_TYPE_U32 },
[IFLA_PROMISCUITY] = { .type = NETLINK_TYPE_U32 },
[IFLA_NUM_TX_QUEUES] = { .type = NETLINK_TYPE_U32 },
[IFLA_NUM_RX_QUEUES] = { .type = NETLINK_TYPE_U32 },
[IFLA_GSO_MAX_SEGS] = { .type = NETLINK_TYPE_U32 },
[IFLA_GSO_MAX_SIZE] = { .type = NETLINK_TYPE_U32 },
[IFLA_CARRIER] = { .type = NETLINK_TYPE_U8 },
/*
[IFLA_PHYS_PORT_ID] = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
*/
[IFLA_MIN_MTU] = { .type = NETLINK_TYPE_U32 },
[IFLA_MAX_MTU] = { .type = NETLINK_TYPE_U32 },
[IFLA_PROP_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_prop_list_type_system },
[IFLA_ALT_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = ALTIFNAMSIZ - 1 },
};
DEFINE_TYPE_SYSTEM(rtnl_link);
/* IFA_FLAGS was defined in kernel 3.14, but we still support older
* kernels where IFA_MAX is lower. */
static const NLType rtnl_address_types[] = {
[IFA_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_LABEL] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
[IFA_BROADCAST] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_ANYCAST] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
[IFA_MULTICAST] = { .type = NETLINK_TYPE_IN_ADDR },
[IFA_FLAGS] = { .type = NETLINK_TYPE_U32 },
[IFA_RT_PRIORITY] = { .type = NETLINK_TYPE_U32 },
[IFA_TARGET_NETNSID] = { .type = NETLINK_TYPE_S32 },
};
DEFINE_TYPE_SYSTEM(rtnl_address);
/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
static const NLType rtnl_route_metrics_types[] = {
[RTAX_MTU] = { .type = NETLINK_TYPE_U32 },
[RTAX_WINDOW] = { .type = NETLINK_TYPE_U32 },
[RTAX_RTT] = { .type = NETLINK_TYPE_U32 },
[RTAX_RTTVAR] = { .type = NETLINK_TYPE_U32 },
[RTAX_SSTHRESH] = { .type = NETLINK_TYPE_U32 },
[RTAX_CWND] = { .type = NETLINK_TYPE_U32 },
[RTAX_ADVMSS] = { .type = NETLINK_TYPE_U32 },
[RTAX_REORDERING] = { .type = NETLINK_TYPE_U32 },
[RTAX_HOPLIMIT] = { .type = NETLINK_TYPE_U32 },
[RTAX_INITCWND] = { .type = NETLINK_TYPE_U32 },
[RTAX_FEATURES] = { .type = NETLINK_TYPE_U32 },
[RTAX_RTO_MIN] = { .type = NETLINK_TYPE_U32 },
[RTAX_INITRWND] = { .type = NETLINK_TYPE_U32 },
[RTAX_QUICKACK] = { .type = NETLINK_TYPE_U32 },
[RTAX_CC_ALGO] = { .type = NETLINK_TYPE_U32 },
[RTAX_FASTOPEN_NO_COOKIE] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(rtnl_route_metrics);
static const NLType rtnl_route_types[] = {
[RTA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
[RTA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
[RTA_IIF] = { .type = NETLINK_TYPE_U32 },
[RTA_OIF] = { .type = NETLINK_TYPE_U32 },
[RTA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR },
[RTA_PRIORITY] = { .type = NETLINK_TYPE_U32 },
[RTA_PREFSRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
[RTA_METRICS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_metrics_type_system},
[RTA_MULTIPATH] = { .size = sizeof(struct rtnexthop) },
[RTA_FLOW] = { .type = NETLINK_TYPE_U32 }, /* 6? */
[RTA_CACHEINFO] = { .size = sizeof(struct rta_cacheinfo) },
[RTA_TABLE] = { .type = NETLINK_TYPE_U32 },
[RTA_MARK] = { .type = NETLINK_TYPE_U32 },
[RTA_MFC_STATS] = { .type = NETLINK_TYPE_U64 },
[RTA_VIA] = { /* See struct rtvia */ },
[RTA_NEWDST] = { .type = NETLINK_TYPE_U32 },
[RTA_PREF] = { .type = NETLINK_TYPE_U8 },
[RTA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
[RTA_ENCAP] = { .type = NETLINK_TYPE_NESTED }, /* Multiple type systems i.e. LWTUNNEL_ENCAP_MPLS/LWTUNNEL_ENCAP_IP/LWTUNNEL_ENCAP_ILA etc... */
[RTA_EXPIRES] = { .type = NETLINK_TYPE_U32 },
[RTA_UID] = { .type = NETLINK_TYPE_U32 },
[RTA_TTL_PROPAGATE] = { .type = NETLINK_TYPE_U8 },
[RTA_IP_PROTO] = { .type = NETLINK_TYPE_U8 },
[RTA_SPORT] = { .type = NETLINK_TYPE_U16 },
[RTA_DPORT] = { .type = NETLINK_TYPE_U16 },
[RTA_NH_ID] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(rtnl_route);
static const NLType rtnl_neigh_types[] = {
[NDA_DST] = { .type = NETLINK_TYPE_IN_ADDR },
[NDA_LLADDR] = { /* struct ether_addr, struct in_addr, or struct in6_addr */ },
[NDA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
[NDA_PROBES] = { .type = NETLINK_TYPE_U32 },
[NDA_VLAN] = { .type = NETLINK_TYPE_U16 },
[NDA_PORT] = { .type = NETLINK_TYPE_U16 },
[NDA_VNI] = { .type = NETLINK_TYPE_U32 },
[NDA_IFINDEX] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(rtnl_neigh);
static const NLType rtnl_addrlabel_types[] = {
[IFAL_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR, .size = sizeof(struct in6_addr) },
[IFAL_LABEL] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(rtnl_addrlabel);
static const NLType rtnl_routing_policy_rule_types[] = {
[FRA_DST] = { .type = NETLINK_TYPE_IN_ADDR },
[FRA_SRC] = { .type = NETLINK_TYPE_IN_ADDR },
[FRA_IIFNAME] = { .type = NETLINK_TYPE_STRING },
[FRA_GOTO] = { .type = NETLINK_TYPE_U32 },
[FRA_PRIORITY] = { .type = NETLINK_TYPE_U32 },
[FRA_FWMARK] = { .type = NETLINK_TYPE_U32 },
[FRA_FLOW] = { .type = NETLINK_TYPE_U32 },
[FRA_TUN_ID] = { .type = NETLINK_TYPE_U64 },
[FRA_SUPPRESS_IFGROUP] = { .type = NETLINK_TYPE_U32 },
[FRA_SUPPRESS_PREFIXLEN] = { .type = NETLINK_TYPE_U32 },
[FRA_TABLE] = { .type = NETLINK_TYPE_U32 },
[FRA_FWMASK] = { .type = NETLINK_TYPE_U32 },
[FRA_OIFNAME] = { .type = NETLINK_TYPE_STRING },
[FRA_PAD] = { .type = NETLINK_TYPE_U32 },
[FRA_L3MDEV] = { .type = NETLINK_TYPE_U8 },
[FRA_UID_RANGE] = { .size = sizeof(struct fib_rule_uid_range) },
[FRA_PROTOCOL] = { .type = NETLINK_TYPE_U8 },
[FRA_IP_PROTO] = { .type = NETLINK_TYPE_U8 },
[FRA_SPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) },
[FRA_DPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) },
};
DEFINE_TYPE_SYSTEM(rtnl_routing_policy_rule);
static const NLType rtnl_nexthop_types[] = {
[NHA_ID] = { .type = NETLINK_TYPE_U32 },
[NHA_GROUP] = { /* array of struct nexthop_grp */ },
[NHA_GROUP_TYPE] = { .type = NETLINK_TYPE_U16 },
[NHA_BLACKHOLE] = { .type = NETLINK_TYPE_FLAG },
[NHA_OIF] = { .type = NETLINK_TYPE_U32 },
[NHA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR },
[NHA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
[NHA_ENCAP] = { .type = NETLINK_TYPE_NESTED },
[NHA_GROUPS] = { .type = NETLINK_TYPE_FLAG },
[NHA_MASTER] = { .type = NETLINK_TYPE_U32 },
[NHA_FDB] = { .type = NETLINK_TYPE_FLAG },
};
DEFINE_TYPE_SYSTEM(rtnl_nexthop);
static const NLType rtnl_tca_option_data_cake_types[] = {
[TCA_CAKE_BASE_RATE64] = { .type = NETLINK_TYPE_U64 },
[TCA_CAKE_OVERHEAD] = { .type = NETLINK_TYPE_S32 },
[TCA_CAKE_MPU] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_codel_types[] = {
[TCA_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 },
[TCA_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 },
[TCA_CODEL_INTERVAL] = { .type = NETLINK_TYPE_U32 },
[TCA_CODEL_ECN] = { .type = NETLINK_TYPE_U32 },
[TCA_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_drr_types[] = {
[TCA_DRR_QUANTUM] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_ets_quanta_types[] = {
[TCA_ETS_QUANTA_BAND] = { .type = NETLINK_TYPE_U32, },
};
DEFINE_TYPE_SYSTEM(rtnl_tca_option_data_ets_quanta);
static const NLType rtnl_tca_option_data_ets_prio_types[] = {
[TCA_ETS_PRIOMAP_BAND] = { .type = NETLINK_TYPE_U8, },
};
DEFINE_TYPE_SYSTEM(rtnl_tca_option_data_ets_prio);
static const NLType rtnl_tca_option_data_ets_types[] = {
[TCA_ETS_NBANDS] = { .type = NETLINK_TYPE_U8 },
[TCA_ETS_NSTRICT] = { .type = NETLINK_TYPE_U8 },
[TCA_ETS_QUANTA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_option_data_ets_quanta_type_system },
[TCA_ETS_PRIOMAP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_option_data_ets_prio_type_system },
[TCA_ETS_QUANTA_BAND] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_fq_types[] = {
[TCA_FQ_PLIMIT] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_FLOW_PLIMIT] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_QUANTUM] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_INITIAL_QUANTUM] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_RATE_ENABLE] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_FLOW_DEFAULT_RATE] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_FLOW_MAX_RATE] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_BUCKETS_LOG] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_FLOW_REFILL_DELAY] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_LOW_RATE_THRESHOLD] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_ORPHAN_MASK] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_fq_codel_types[] = {
[TCA_FQ_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_INTERVAL] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_ECN] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_FLOWS] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_QUANTUM] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_CODEL_MEMORY_LIMIT] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_fq_pie_types[] = {
[TCA_FQ_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_gred_types[] = {
[TCA_GRED_DPS] = { .size = sizeof(struct tc_gred_sopt) },
};
static const NLType rtnl_tca_option_data_hhf_types[] = {
[TCA_HHF_BACKLOG_LIMIT] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_htb_types[] = {
[TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) },
[TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) },
[TCA_HTB_CTAB] = { .size = TC_RTAB_SIZE },
[TCA_HTB_RTAB] = { .size = TC_RTAB_SIZE },
[TCA_HTB_RATE64] = { .type = NETLINK_TYPE_U64 },
[TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 },
};
static const NLType rtnl_tca_option_data_pie_types[] = {
[TCA_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_qfq_types[] = {
[TCA_QFQ_WEIGHT] = { .type = NETLINK_TYPE_U32 },
[TCA_QFQ_LMAX] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_sfb_types[] = {
[TCA_SFB_PARMS] = { .size = sizeof(struct tc_sfb_qopt) },
};
static const NLType rtnl_tca_option_data_tbf_types[] = {
[TCA_TBF_PARMS] = { .size = sizeof(struct tc_tbf_qopt) },
[TCA_TBF_RTAB] = { .size = TC_RTAB_SIZE },
[TCA_TBF_PTAB] = { .size = TC_RTAB_SIZE },
[TCA_TBF_RATE64] = { .type = NETLINK_TYPE_U64 },
[TCA_TBF_PRATE64] = { .type = NETLINK_TYPE_U64 },
[TCA_TBF_BURST] = { .type = NETLINK_TYPE_U32 },
[TCA_TBF_PBURST] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystemUnionElement rtnl_tca_option_data_type_systems[] = {
{ .name = "cake", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_cake), },
{ .name = "codel", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_codel), },
{ .name = "drr", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_drr), },
{ .name = "ets", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_ets), },
{ .name = "fq", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_fq), },
{ .name = "fq_codel", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_fq_codel), },
{ .name = "fq_pie", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_fq_pie), },
{ .name = "gred", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_gred), },
{ .name = "hhf", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_hhf), },
{ .name = "htb", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_htb), },
{ .name = "pie", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_pie), },
{ .name = "qfq", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_qfq), },
{ .name = "sfb", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_sfb), },
{ .name = "tbf", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_tbf), },
};
DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(rtnl_tca_option_data, TCA_KIND);
static const NLType rtnl_tca_types[] = {
[TCA_KIND] = { .type = NETLINK_TYPE_STRING },
[TCA_OPTIONS] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_tca_option_data_type_system_union },
[TCA_INGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 },
[TCA_EGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 },
};
DEFINE_TYPE_SYSTEM(rtnl_tca);
static const NLType rtnl_mdb_types[] = {
[MDBA_SET_ENTRY] = { .size = sizeof(struct br_port_msg) },
};
DEFINE_TYPE_SYSTEM(rtnl_mdb);
static const NLType rtnl_types[] = {
[RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_DELLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_GETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_SETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_NEWLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_DELLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_GETLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_NEWADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_DELADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_GETADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
[RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
[RTM_NEWADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
[RTM_DELADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
[RTM_GETADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
[RTM_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) },
[RTM_DELRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) },
[RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) },
[RTM_NEWNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) },
[RTM_DELNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) },
[RTM_GETNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) },
[RTM_NEWQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
[RTM_DELQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
[RTM_GETQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
[RTM_NEWTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
[RTM_DELTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
[RTM_GETTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) },
[RTM_NEWMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) },
[RTM_DELMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) },
[RTM_GETMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) },
};
DEFINE_TYPE_SYSTEM(rtnl);
const NLType *rtnl_get_type(uint16_t nlmsg_type) {
return type_system_get_type(&rtnl_type_system, nlmsg_type);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include "macro.h" #include "sd-netlink.h"
enum { enum {
NETLINK_TYPE_UNSPEC, NETLINK_TYPE_UNSPEC,
@ -35,105 +35,30 @@ typedef struct NLTypeSystemUnion NLTypeSystemUnion;
typedef struct NLTypeSystem NLTypeSystem; typedef struct NLTypeSystem NLTypeSystem;
typedef struct NLType NLType; typedef struct NLType NLType;
struct NLTypeSystemUnion { const NLType *rtnl_get_type(uint16_t nlmsg_type);
int num; const NLType *nfnl_get_type(uint16_t nlmsg_type);
NLMatchType match_type; const NLTypeSystem *genl_get_type_system_by_name(const char *name);
uint16_t match; int genl_get_type_system_and_header_size(
int (*lookup)(const char *); sd_netlink *nl,
const NLTypeSystem *type_systems; uint16_t id,
}; const NLTypeSystem **ret_type_system,
size_t *ret_header_size);
extern const NLTypeSystem genl_family_type_system_root;
uint16_t type_get_type(const NLType *type); uint16_t type_get_type(const NLType *type);
size_t type_get_size(const NLType *type); size_t type_get_size(const NLType *type);
void type_get_type_system(const NLType *type, const NLTypeSystem **ret); const NLTypeSystem *type_get_type_system(const NLType *type);
void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **ret); const NLTypeSystemUnion *type_get_type_system_union(const NLType *type);
const NLTypeSystem* type_system_get_root(int protocol); int type_system_root_get_type_system_and_header_size(
uint16_t type_system_get_count(const NLTypeSystem *type_system); sd_netlink *nl,
int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type); uint16_t type,
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type); const NLTypeSystem **ret_type_system,
int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type); size_t *ret_header_size);
int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key);
int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol);
typedef enum NLUnionLinkInfoData { const NLType *type_system_get_type(const NLTypeSystem *type_system, uint16_t type);
NL_UNION_LINK_INFO_DATA_BOND, const NLTypeSystem *type_system_get_type_system(const NLTypeSystem *type_system, uint16_t type);
NL_UNION_LINK_INFO_DATA_BRIDGE, const NLTypeSystemUnion *type_system_get_type_system_union(const NLTypeSystem *type_system, uint16_t type);
NL_UNION_LINK_INFO_DATA_VLAN, NLMatchType type_system_union_get_match_type(const NLTypeSystemUnion *type_system_union);
NL_UNION_LINK_INFO_DATA_VETH, uint16_t type_system_union_get_match_attribute(const NLTypeSystemUnion *type_system_union);
NL_UNION_LINK_INFO_DATA_DUMMY, const NLTypeSystem *type_system_union_get_type_system_by_string(const NLTypeSystemUnion *type_system_union, const char *key);
NL_UNION_LINK_INFO_DATA_MACVLAN, const NLTypeSystem *type_system_union_get_type_system_by_protocol(const NLTypeSystemUnion *type_system_union, uint16_t protocol);
NL_UNION_LINK_INFO_DATA_MACVTAP,
NL_UNION_LINK_INFO_DATA_IPVLAN,
NL_UNION_LINK_INFO_DATA_IPVTAP,
NL_UNION_LINK_INFO_DATA_VXLAN,
NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL,
NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL,
NL_UNION_LINK_INFO_DATA_ERSPAN,
NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL,
NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL,
NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL,
NL_UNION_LINK_INFO_DATA_SIT_TUNNEL,
NL_UNION_LINK_INFO_DATA_VTI_TUNNEL,
NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL,
NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
NL_UNION_LINK_INFO_DATA_VRF,
NL_UNION_LINK_INFO_DATA_VCAN,
NL_UNION_LINK_INFO_DATA_GENEVE,
NL_UNION_LINK_INFO_DATA_VXCAN,
NL_UNION_LINK_INFO_DATA_WIREGUARD,
NL_UNION_LINK_INFO_DATA_NETDEVSIM,
NL_UNION_LINK_INFO_DATA_CAN,
NL_UNION_LINK_INFO_DATA_MACSEC,
NL_UNION_LINK_INFO_DATA_NLMON,
NL_UNION_LINK_INFO_DATA_XFRM,
NL_UNION_LINK_INFO_DATA_IFB,
NL_UNION_LINK_INFO_DATA_BAREUDP,
NL_UNION_LINK_INFO_DATA_BATADV,
_NL_UNION_LINK_INFO_DATA_MAX,
_NL_UNION_LINK_INFO_DATA_INVALID = -EINVAL,
} NLUnionLinkInfoData;
const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_;
NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
typedef enum NLUnionTCAOptionData {
NL_UNION_TCA_OPTION_DATA_CAKE,
NL_UNION_TCA_OPTION_DATA_CODEL,
NL_UNION_TCA_OPTION_DATA_DRR,
NL_UNION_TCA_OPTION_DATA_ETS,
NL_UNION_TCA_OPTION_DATA_FQ,
NL_UNION_TCA_OPTION_DATA_FQ_CODEL,
NL_UNION_TCA_OPTION_DATA_FQ_PIE,
NL_UNION_TCA_OPTION_DATA_GRED,
NL_UNION_TCA_OPTION_DATA_HHF,
NL_UNION_TCA_OPTION_DATA_HTB,
NL_UNION_TCA_OPTION_DATA_PIE,
NL_UNION_TCA_OPTION_DATA_QFQ,
NL_UNION_TCA_OPTION_DATA_SFB,
NL_UNION_TCA_OPTION_DATA_TBF,
_NL_UNION_TCA_OPTION_DATA_MAX,
_NL_UNION_TCA_OPTION_DATA_INVALID = -EINVAL,
} NLUnionTCAOptionData;
const char *nl_union_tca_option_data_to_string(NLUnionTCAOptionData p) _const_;
NLUnionTCAOptionData nl_union_tca_option_data_from_string(const char *p) _pure_;
typedef enum NLUnionNFTExprData {
NL_UNION_NFT_EXPR_DATA_BITWISE,
NL_UNION_NFT_EXPR_DATA_CMP,
NL_UNION_NFT_EXPR_DATA_FIB,
NL_UNION_NFT_EXPR_DATA_LOOKUP,
NL_UNION_NFT_EXPR_DATA_PAYLOAD,
NL_UNION_NFT_EXPR_DATA_MASQ,
NL_UNION_NFT_EXPR_DATA_META,
NL_UNION_NFT_EXPR_DATA_NAT,
_NL_UNION_NFT_EXPR_DATA_MAX,
_NL_UNION_NFT_EXPR_DATA_INVALID = -EINVAL,
} NLUnionNFTExprData;
const char *nl_union_nft_expr_data_to_string(NLUnionNFTExprData p) _const_;
NLUnionNFTExprData nl_union_nft_expr_data_from_string(const char *p) _pure_;

View File

@ -400,25 +400,6 @@ int rtnl_get_link_info(sd_netlink **rtnl, int ifindex, unsigned short *ret_iftyp
return 0; return 0;
} }
int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret) {
struct nlmsgerr *err;
int r;
assert(error <= 0);
r = message_new(rtnl, ret, NLMSG_ERROR);
if (r < 0)
return r;
rtnl_message_seal(*ret);
(*ret)->hdr->nlmsg_seq = serial;
err = NLMSG_DATA((*ret)->hdr);
err->error = error;
return 0;
}
int rtnl_log_parse_error(int r) { int rtnl_log_parse_error(int r) {
return log_error_errno(r, "Failed to parse netlink message: %m"); return log_error_errno(r, "Failed to parse netlink message: %m");
} }

View File

@ -29,10 +29,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret); 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);
static inline bool rtnl_message_type_is_neigh(uint16_t type) { static inline bool rtnl_message_type_is_neigh(uint16_t type) {
return IN_SET(type, RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH); return IN_SET(type, RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH);
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,31 +2,40 @@
#include <net/if.h> #include <net/if.h>
#include <netinet/ether.h> #include <netinet/ether.h>
#include <netinet/in.h>
#include <linux/fou.h>
#include <linux/genetlink.h> #include <linux/genetlink.h>
#include <linux/if_macsec.h>
#include <linux/l2tp.h>
#include <linux/nl80211.h>
#include "sd-netlink.h" #include "sd-netlink.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "ether-addr-util.h" #include "ether-addr-util.h"
#include "macro.h" #include "macro.h"
#include "netlink-genl.h"
#include "netlink-internal.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "socket-util.h" #include "socket-util.h"
#include "stdio-util.h" #include "stdio-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "util.h" #include "tests.h"
static void test_message_link_bridge(sd_netlink *rtnl) { static void test_message_link_bridge(sd_netlink *rtnl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
uint32_t cost; uint32_t cost;
log_debug("/* %s */", __func__);
assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0);
assert_se(sd_rtnl_message_link_set_family(message, AF_BRIDGE) >= 0); assert_se(sd_rtnl_message_link_set_family(message, AF_BRIDGE) >= 0);
assert_se(sd_netlink_message_open_container(message, IFLA_PROTINFO) >= 0); assert_se(sd_netlink_message_open_container(message, IFLA_PROTINFO) >= 0);
assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0); assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
assert_se(sd_netlink_message_close_container(message) >= 0); assert_se(sd_netlink_message_close_container(message) >= 0);
assert_se(sd_netlink_message_rewind(message, NULL) >= 0); assert_se(sd_netlink_message_rewind(message, rtnl) >= 0);
assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0); assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0);
assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0); assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
@ -40,6 +49,8 @@ static void test_link_configure(sd_netlink *rtnl, int ifindex) {
const char *name_out; const char *name_out;
struct ether_addr mac_out; struct ether_addr mac_out;
log_debug("/* %s */", __func__);
/* we'd really like to test NEWLINK, but let's not mess with the running kernel */ /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
@ -57,6 +68,8 @@ static void test_link_get(sd_netlink *rtnl, int ifindex) {
uint32_t u32_data; uint32_t u32_data;
struct ether_addr eth_data; struct ether_addr eth_data;
log_debug("/* %s */", __func__);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
assert_se(m); assert_se(m);
@ -83,6 +96,8 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
struct ifa_cacheinfo cache; struct ifa_cacheinfo cache;
const char *label; const char *label;
log_debug("/* %s */", __func__);
assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0); assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
assert_se(m); assert_se(m);
assert_se(sd_netlink_message_request_dump(m, true) >= 0); assert_se(sd_netlink_message_request_dump(m, true) >= 0);
@ -100,6 +115,8 @@ static void test_route(sd_netlink *rtnl) {
uint32_t index = 2, u32_data; uint32_t index = 2, u32_data;
int r; int r;
log_debug("/* %s */", __func__);
r = sd_rtnl_message_new_route(rtnl, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC); r = sd_rtnl_message_new_route(rtnl, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Could not create RTM_NEWROUTE message: %m"); log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
@ -120,7 +137,7 @@ static void test_route(sd_netlink *rtnl) {
return; return;
} }
assert_se(sd_netlink_message_rewind(req, NULL) >= 0); assert_se(sd_netlink_message_rewind(req, rtnl) >= 0);
assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0); assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
assert_se(addr_data.s_addr == addr.s_addr); assert_se(addr_data.s_addr == addr.s_addr);
@ -134,6 +151,8 @@ static void test_route(sd_netlink *rtnl) {
static void test_multiple(void) { static void test_multiple(void) {
sd_netlink *rtnl1, *rtnl2; sd_netlink *rtnl1, *rtnl2;
log_debug("/* %s */", __func__);
assert_se(sd_netlink_open(&rtnl1) >= 0); assert_se(sd_netlink_open(&rtnl1) >= 0);
assert_se(sd_netlink_open(&rtnl2) >= 0); assert_se(sd_netlink_open(&rtnl2) >= 0);
@ -164,6 +183,8 @@ static void test_event_loop(int ifindex) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
char *ifname; char *ifname;
log_debug("/* %s */", __func__);
ifname = strdup("lo2"); ifname = strdup("lo2");
assert_se(ifname); assert_se(ifname);
@ -194,6 +215,8 @@ static void test_async(int ifindex) {
const char *description; const char *description;
char *ifname; char *ifname;
log_debug("/* %s */", __func__);
ifname = strdup("lo"); ifname = strdup("lo");
assert_se(ifname); assert_se(ifname);
@ -225,6 +248,8 @@ static void test_slot_set(int ifindex) {
const char *description; const char *description;
char *ifname; char *ifname;
log_debug("/* %s */", __func__);
ifname = strdup("lo"); ifname = strdup("lo");
assert_se(ifname); assert_se(ifname);
@ -303,6 +328,8 @@ static void test_async_destroy_callback(int ifindex) {
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL; _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
char *ifname; char *ifname;
log_debug("/* %s */", __func__);
assert_se(t = new(struct test_async_object, 1)); assert_se(t = new(struct test_async_object, 1));
assert_se(ifname = strdup("lo")); assert_se(ifname = strdup("lo"));
*t = (struct test_async_object) { *t = (struct test_async_object) {
@ -371,6 +398,8 @@ static void test_pipe(int ifindex) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL;
int counter = 0; int counter = 0;
log_debug("/* %s */", __func__);
assert_se(sd_netlink_open(&rtnl) >= 0); assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
@ -396,6 +425,8 @@ static void test_container(sd_netlink *rtnl) {
uint32_t u32_data; uint32_t u32_data;
const char *string_data; const char *string_data;
log_debug("/* %s */", __func__);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0); assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
@ -406,7 +437,7 @@ static void test_container(sd_netlink *rtnl) {
assert_se(sd_netlink_message_close_container(m) >= 0); assert_se(sd_netlink_message_close_container(m) >= 0);
assert_se(sd_netlink_message_close_container(m) == -EINVAL); assert_se(sd_netlink_message_close_container(m) == -EINVAL);
assert_se(sd_netlink_message_rewind(m, NULL) >= 0); assert_se(sd_netlink_message_rewind(m, rtnl) >= 0);
assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0); assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0);
assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0); assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
@ -429,6 +460,8 @@ static void test_match(void) {
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *s1 = NULL, *s2 = NULL; _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *s1 = NULL, *s2 = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
log_debug("/* %s */", __func__);
assert_se(sd_netlink_open(&rtnl) >= 0); assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_netlink_add_match(rtnl, &s1, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0); assert_se(sd_netlink_add_match(rtnl, &s1, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0);
@ -445,6 +478,8 @@ static void test_get_addresses(sd_netlink *rtnl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
sd_netlink_message *m; sd_netlink_message *m;
log_debug("/* %s */", __func__);
assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0); assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
assert_se(sd_netlink_message_request_dump(req, true) >= 0); assert_se(sd_netlink_message_request_dump(req, true) >= 0);
assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0); assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0);
@ -472,7 +507,9 @@ static void test_get_addresses(sd_netlink *rtnl) {
static void test_message(sd_netlink *rtnl) { static void test_message(sd_netlink *rtnl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
assert_se(rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0); log_debug("/* %s */", __func__);
assert_se(message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0);
assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT); assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
} }
@ -480,8 +517,10 @@ static void test_array(void) {
_cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
log_debug("/* %s */", __func__);
assert_se(sd_genl_socket_open(&genl) >= 0); assert_se(sd_genl_socket_open(&genl) >= 0);
assert_se(sd_genl_message_new(genl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &m) >= 0); assert_se(sd_genl_message_new(genl, CTRL_GENL_NAME, CTRL_CMD_GETFAMILY, &m) >= 0);
assert_se(sd_netlink_message_open_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0); assert_se(sd_netlink_message_open_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
for (unsigned i = 0; i < 10; i++) { for (unsigned i = 0; i < 10; i++) {
@ -496,7 +535,7 @@ static void test_array(void) {
} }
assert_se(sd_netlink_message_close_container(m) >= 0); assert_se(sd_netlink_message_close_container(m) >= 0);
rtnl_message_seal(m); message_seal(m);
assert_se(sd_netlink_message_rewind(m, genl) >= 0); assert_se(sd_netlink_message_rewind(m, genl) >= 0);
assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0); assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
@ -522,6 +561,8 @@ static void test_strv(sd_netlink *rtnl) {
_cleanup_strv_free_ char **names_in = NULL, **names_out; _cleanup_strv_free_ char **names_in = NULL, **names_out;
const char *p; const char *p;
log_debug("/* %s */", __func__);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINKPROP, 1) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINKPROP, 1) >= 0);
for (unsigned i = 0; i < 10; i++) { for (unsigned i = 0; i < 10; i++) {
@ -535,8 +576,8 @@ static void test_strv(sd_netlink *rtnl) {
assert_se(sd_netlink_message_append_strv(m, IFLA_ALT_IFNAME, names_in) >= 0); assert_se(sd_netlink_message_append_strv(m, IFLA_ALT_IFNAME, names_in) >= 0);
assert_se(sd_netlink_message_close_container(m) >= 0); assert_se(sd_netlink_message_close_container(m) >= 0);
rtnl_message_seal(m); message_seal(m);
assert_se(sd_netlink_message_rewind(m, NULL) >= 0); assert_se(sd_netlink_message_rewind(m, rtnl) >= 0);
assert_se(sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names_out) >= 0); assert_se(sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names_out) >= 0);
assert_se(strv_equal(names_in, names_out)); assert_se(strv_equal(names_in, names_out));
@ -547,6 +588,84 @@ static void test_strv(sd_netlink *rtnl) {
assert_se(sd_netlink_message_exit_container(m) >= 0); assert_se(sd_netlink_message_exit_container(m) >= 0);
} }
static int genl_ctrl_match_callback(sd_netlink *genl, sd_netlink_message *m, void *userdata) {
const char *name;
uint16_t id;
uint8_t cmd;
assert(genl);
assert(m);
assert_se(sd_genl_message_get_family_name(genl, m, &name) >= 0);
assert_se(streq(name, CTRL_GENL_NAME));
assert_se(sd_genl_message_get_command(genl, m, &cmd) >= 0);
switch (cmd) {
case CTRL_CMD_NEWFAMILY:
case CTRL_CMD_DELFAMILY:
assert_se(sd_netlink_message_read_string(m, CTRL_ATTR_FAMILY_NAME, &name) >= 0);
assert_se(sd_netlink_message_read_u16(m, CTRL_ATTR_FAMILY_ID, &id) >= 0);
log_debug("%s: %s (id=%"PRIu16") family is %s.",
__func__, name, id, cmd == CTRL_CMD_NEWFAMILY ? "added" : "removed");
break;
case CTRL_CMD_NEWMCAST_GRP:
case CTRL_CMD_DELMCAST_GRP:
assert_se(sd_netlink_message_read_string(m, CTRL_ATTR_FAMILY_NAME, &name) >= 0);
assert_se(sd_netlink_message_read_u16(m, CTRL_ATTR_FAMILY_ID, &id) >= 0);
log_debug("%s: multicast group for %s (id=%"PRIu16") family is %s.",
__func__, name, id, cmd == CTRL_CMD_NEWMCAST_GRP ? "added" : "removed");
break;
default:
log_debug("%s: received nlctrl message with unknown command '%"PRIu8"'.", __func__, cmd);
}
return 0;
}
static void test_genl(void) {
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const char *name;
uint8_t cmd;
int r;
log_debug("/* %s */", __func__);
assert_se(sd_genl_socket_open(&genl) >= 0);
assert_se(sd_event_default(&event) >= 0);
assert_se(sd_netlink_attach_event(genl, event, 0) >= 0);
assert_se(sd_genl_message_new(genl, CTRL_GENL_NAME, CTRL_CMD_GETFAMILY, &m) >= 0);
assert_se(sd_genl_message_get_family_name(genl, m, &name) >= 0);
assert_se(streq(name, CTRL_GENL_NAME));
assert_se(sd_genl_message_get_command(genl, m, &cmd) >= 0);
assert_se(cmd == CTRL_CMD_GETFAMILY);
assert_se(sd_genl_add_match(genl, NULL, CTRL_GENL_NAME, "notify", 0, genl_ctrl_match_callback, NULL, NULL, "genl-ctrl-notify") >= 0);
m = sd_netlink_message_unref(m);
assert_se(sd_genl_message_new(genl, "should-not-exist", CTRL_CMD_GETFAMILY, &m) < 0);
assert_se(sd_genl_message_new(genl, "should-not-exist", CTRL_CMD_GETFAMILY, &m) == -EOPNOTSUPP);
/* These families may not be supported by kernel. Hence, ignore results. */
(void) sd_genl_message_new(genl, FOU_GENL_NAME, 0, &m);
m = sd_netlink_message_unref(m);
(void) sd_genl_message_new(genl, L2TP_GENL_NAME, 0, &m);
m = sd_netlink_message_unref(m);
(void) sd_genl_message_new(genl, MACSEC_GENL_NAME, 0, &m);
m = sd_netlink_message_unref(m);
(void) sd_genl_message_new(genl, NL80211_GENL_NAME, 0, &m);
for (;;) {
r = sd_event_run(event, 500 * USEC_PER_MSEC);
assert_se(r >= 0);
if (r == 0)
return;
}
}
int main(void) { int main(void) {
sd_netlink *rtnl; sd_netlink *rtnl;
sd_netlink_message *m; sd_netlink_message *m;
@ -555,6 +674,8 @@ int main(void) {
int if_loopback; int if_loopback;
uint16_t type; uint16_t type;
test_setup_logging(LOG_DEBUG);
test_match(); test_match();
test_multiple(); test_multiple();
@ -605,5 +726,7 @@ int main(void) {
assert_se((r = sd_netlink_message_unref(r)) == NULL); assert_se((r = sd_netlink_message_unref(r)) == NULL);
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
test_genl();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -80,7 +80,7 @@ ENV{ID_SOFTWARE_RADIO}=="?*", TAG+="uaccess"
# 3D printers, CNC machines, laser cutters, 3D scanners, etc. # 3D printers, CNC machines, laser cutters, 3D scanners, etc.
ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess" ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess"
# Protocol analysers # Protocol analyzers
ENV{ID_PROTOCOL_ANALYSER}=="?*", TAG+="uaccess" ENV{ID_PROTOCOL_ANALYZER}=="?*", TAG+="uaccess"
LABEL="uaccess_end" LABEL="uaccess_end"

View File

@ -122,7 +122,7 @@ static int netdev_batadv_post_create(NetDev *netdev, Link *link, sd_netlink_mess
b = BATADV(netdev); b = BATADV(netdev);
assert(b); assert(b);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_BATADV, BATADV_CMD_SET_MESH, &message); r = sd_genl_message_new(netdev->manager->genl, BATADV_NL_NAME, BATADV_CMD_SET_MESH, &message);
if (r < 0) if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m"); return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");

View File

@ -36,7 +36,7 @@ static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **r
assert(t); assert(t);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m); r = sd_genl_message_new(netdev->manager->genl, FOU_GENL_NAME, FOU_CMD_ADD, &m);
if (r < 0) if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m"); return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");

View File

@ -104,7 +104,7 @@ static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, union in_addr_union *
assert(t); assert(t);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_TUNNEL_CREATE, &m); r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_TUNNEL_CREATE, &m);
if (r < 0) if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m"); return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
@ -195,7 +195,7 @@ static int netdev_l2tp_fill_message_session(NetDev *netdev, L2tpSession *session
assert(session); assert(session);
assert(session->tunnel); assert(session->tunnel);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_SESSION_CREATE, &m); r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_SESSION_CREATE, &m);
if (r < 0) if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m"); return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");

View File

@ -224,7 +224,7 @@ static int netdev_macsec_fill_message(NetDev *netdev, int command, sd_netlink_me
assert(netdev); assert(netdev);
assert(netdev->ifindex > 0); assert(netdev->ifindex > 0);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_MACSEC, command, &m); r = sd_genl_message_new(netdev->manager->genl, MACSEC_GENL_NAME, command, &m);
if (r < 0) if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m"); return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");

View File

@ -229,7 +229,7 @@ static int wireguard_set_interface(NetDev *netdev) {
message = sd_netlink_message_unref(message); message = sd_netlink_message_unref(message);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message); r = sd_genl_message_new(netdev->manager->genl, WG_GENL_NAME, WG_CMD_SET_DEVICE, &message);
if (r < 0) if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m"); return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");

View File

@ -13,6 +13,7 @@
#include "hostname-util.h" #include "hostname-util.h"
#include "in-addr-util.h" #include "in-addr-util.h"
#include "net-condition.h" #include "net-condition.h"
#include "netdev/macvlan.h"
#include "networkd-address-label.h" #include "networkd-address-label.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-bridge-fdb.h" #include "networkd-bridge-fdb.h"
@ -170,8 +171,33 @@ int network_verify(Network *network) {
network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free); network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
} }
if (network->link_local < 0) if (network->link_local < 0) {
network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6; network->link_local = ADDRESS_FAMILY_IPV6;
if (network->bridge)
network->link_local = ADDRESS_FAMILY_NO;
else {
NetDev *netdev;
HASHMAP_FOREACH(netdev, network->stacked_netdevs) {
MacVlan *m;
if (netdev->kind == NETDEV_KIND_MACVLAN)
m = MACVLAN(netdev);
else if (netdev->kind == NETDEV_KIND_MACVTAP)
m = MACVTAP(netdev);
else
continue;
if (m->mode == NETDEV_MACVLAN_MODE_PASSTHRU)
network->link_local = ADDRESS_FAMILY_NO;
/* There won't be a passthru MACVLAN/MACVTAP if there's already one in another mode */
break;
}
}
}
if (network->ipv6ll_address_gen_mode == IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE) if (network->ipv6ll_address_gen_mode == IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE)
SET_FLAG(network->link_local, ADDRESS_FAMILY_IPV6, false); SET_FLAG(network->link_local, ADDRESS_FAMILY_IPV6, false);

View File

@ -8,7 +8,6 @@
#include "lldp-internal.h" #include "lldp-internal.h"
#include "macvlan.h" #include "macvlan.h"
#include "ndisc-internal.h" #include "ndisc-internal.h"
#include "netlink-internal.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-util.h" #include "networkd-util.h"
@ -35,7 +34,6 @@ int main(int argc, char **argv) {
/* test_table(link_state, LINK_STATE); — not a reversible mapping */ /* test_table(link_state, LINK_STATE); — not a reversible mapping */
test_table(lldp_mode, LLDP_MODE); test_table(lldp_mode, LLDP_MODE);
test_table(netdev_kind, NETDEV_KIND); test_table(netdev_kind, NETDEV_KIND);
test_table(nl_union_link_info_data, NL_UNION_LINK_INFO_DATA);
test_table(radv_prefix_delegation, RADV_PREFIX_DELEGATION); test_table(radv_prefix_delegation, RADV_PREFIX_DELEGATION);
test_table(lldp_event, SD_LLDP_EVENT); test_table(lldp_event, SD_LLDP_EVENT);
test_table(ndisc_event, SD_NDISC_EVENT); test_table(ndisc_event, SD_NDISC_EVENT);
@ -48,7 +46,6 @@ int main(int argc, char **argv) {
assert_cc(sizeof(sd_lldp_event_t) == sizeof(int64_t)); assert_cc(sizeof(sd_lldp_event_t) == sizeof(int64_t));
assert_cc(sizeof(sd_ndisc_event_t) == sizeof(int64_t)); assert_cc(sizeof(sd_ndisc_event_t) == sizeof(int64_t));
assert_cc(sizeof(sd_dhcp_lease_server_type_t) == sizeof(int64_t)); assert_cc(sizeof(sd_dhcp_lease_server_type_t) == sizeof(int64_t));
assert_cc(sizeof(sd_genl_family_t) == sizeof(int64_t));
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -932,6 +932,131 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au
return 0; return 0;
} }
int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const netdev_coalesce_param *coalesce) {
struct ethtool_coalesce ecmd = {
.cmd = ETHTOOL_GCOALESCE,
};
struct ifreq ifr = {
.ifr_data = (void*) &ecmd,
};
bool need_update = false;
int r;
assert(ethtool_fd);
assert(ifname);
assert(coalesce);
if (coalesce->use_adaptive_rx_coalesce < 0 &&
coalesce->use_adaptive_tx_coalesce < 0 &&
!coalesce->rx_coalesce_usecs.set &&
!coalesce->rx_max_coalesced_frames.set &&
!coalesce->rx_coalesce_usecs_irq.set &&
!coalesce->rx_max_coalesced_frames_irq.set &&
!coalesce->tx_coalesce_usecs.set &&
!coalesce->tx_max_coalesced_frames.set &&
!coalesce->tx_coalesce_usecs_irq.set &&
!coalesce->tx_max_coalesced_frames_irq.set &&
!coalesce->stats_block_coalesce_usecs.set &&
!coalesce->pkt_rate_low.set &&
!coalesce->rx_coalesce_usecs_low.set &&
!coalesce->rx_max_coalesced_frames_low.set &&
!coalesce->tx_coalesce_usecs_low.set &&
!coalesce->tx_max_coalesced_frames_low.set &&
!coalesce->pkt_rate_high.set &&
!coalesce->rx_coalesce_usecs_high.set &&
!coalesce->rx_max_coalesced_frames_high.set &&
!coalesce->tx_coalesce_usecs_high.set &&
!coalesce->tx_max_coalesced_frames_high.set &&
!coalesce->rate_sample_interval.set)
return 0;
r = ethtool_connect(ethtool_fd);
if (r < 0)
return r;
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
if (coalesce->use_adaptive_rx_coalesce >= 0)
UPDATE(ecmd.use_adaptive_rx_coalesce, (uint32_t) coalesce->use_adaptive_rx_coalesce, need_update);
if (coalesce->use_adaptive_tx_coalesce >= 0)
UPDATE(ecmd.use_adaptive_tx_coalesce, (uint32_t) coalesce->use_adaptive_tx_coalesce, need_update);
if (coalesce->rx_coalesce_usecs.set)
UPDATE(ecmd.rx_coalesce_usecs, coalesce->rx_coalesce_usecs.value, need_update);
if (coalesce->rx_max_coalesced_frames.set)
UPDATE(ecmd.rx_max_coalesced_frames, coalesce->rx_max_coalesced_frames.value, need_update);
if (coalesce->rx_coalesce_usecs_irq.set)
UPDATE(ecmd.rx_coalesce_usecs_irq, coalesce->rx_coalesce_usecs_irq.value, need_update);
if (coalesce->rx_max_coalesced_frames_irq.set)
UPDATE(ecmd.rx_max_coalesced_frames_irq, coalesce->rx_max_coalesced_frames_irq.value, need_update);
if (coalesce->tx_coalesce_usecs.set)
UPDATE(ecmd.tx_coalesce_usecs, coalesce->tx_coalesce_usecs.value, need_update);
if (coalesce->tx_max_coalesced_frames.set)
UPDATE(ecmd.tx_max_coalesced_frames, coalesce->tx_max_coalesced_frames.value, need_update);
if (coalesce->tx_coalesce_usecs_irq.set)
UPDATE(ecmd.tx_coalesce_usecs_irq, coalesce->tx_coalesce_usecs_irq.value, need_update);
if (coalesce->tx_max_coalesced_frames_irq.set)
UPDATE(ecmd.tx_max_coalesced_frames_irq, coalesce->tx_max_coalesced_frames_irq.value, need_update);
if (coalesce->stats_block_coalesce_usecs.set)
UPDATE(ecmd.stats_block_coalesce_usecs, coalesce->stats_block_coalesce_usecs.value, need_update);
if (coalesce->pkt_rate_low.set)
UPDATE(ecmd.pkt_rate_low, coalesce->pkt_rate_low.value, need_update);
if (coalesce->rx_coalesce_usecs_low.set)
UPDATE(ecmd.rx_coalesce_usecs_low, coalesce->rx_coalesce_usecs_low.value, need_update);
if (coalesce->rx_max_coalesced_frames_low.set)
UPDATE(ecmd.rx_max_coalesced_frames_low, coalesce->rx_max_coalesced_frames_low.value, need_update);
if (coalesce->tx_coalesce_usecs_low.set)
UPDATE(ecmd.tx_coalesce_usecs_low, coalesce->tx_coalesce_usecs_low.value, need_update);
if (coalesce->tx_max_coalesced_frames_low.set)
UPDATE(ecmd.tx_max_coalesced_frames_low, coalesce->tx_max_coalesced_frames_low.value, need_update);
if (coalesce->pkt_rate_high.set)
UPDATE(ecmd.pkt_rate_high, coalesce->pkt_rate_high.value, need_update);
if (coalesce->rx_coalesce_usecs_high.set)
UPDATE(ecmd.rx_coalesce_usecs_high, coalesce->rx_coalesce_usecs_high.value, need_update);
if (coalesce->rx_max_coalesced_frames_high.set)
UPDATE(ecmd.rx_max_coalesced_frames_high, coalesce->rx_max_coalesced_frames_high.value, need_update);
if (coalesce->tx_coalesce_usecs_high.set)
UPDATE(ecmd.tx_coalesce_usecs_high, coalesce->tx_coalesce_usecs_high.value, need_update);
if (coalesce->tx_max_coalesced_frames_high.set)
UPDATE(ecmd.tx_max_coalesced_frames_high, coalesce->tx_max_coalesced_frames_high.value, need_update);
if (coalesce->rate_sample_interval.set)
UPDATE(ecmd.rate_sample_interval, DIV_ROUND_UP(coalesce->rate_sample_interval.value, USEC_PER_SEC), need_update);
if (!need_update)
return 0;
ecmd.cmd = ETHTOOL_SCOALESCE;
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
return 0;
}
int config_parse_advertise( int config_parse_advertise(
const char *unit, const char *unit,
const char *filename, const char *filename,
@ -1182,128 +1307,3 @@ int config_parse_coalesce_sec(
return 0; return 0;
} }
int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const netdev_coalesce_param *coalesce) {
struct ethtool_coalesce ecmd = {
.cmd = ETHTOOL_GCOALESCE,
};
struct ifreq ifr = {
.ifr_data = (void*) &ecmd,
};
bool need_update = false;
int r;
assert(ethtool_fd);
assert(ifname);
assert(coalesce);
if (coalesce->use_adaptive_rx_coalesce < 0 &&
coalesce->use_adaptive_tx_coalesce < 0 &&
!coalesce->rx_coalesce_usecs.set &&
!coalesce->rx_max_coalesced_frames.set &&
!coalesce->rx_coalesce_usecs_irq.set &&
!coalesce->rx_max_coalesced_frames_irq.set &&
!coalesce->tx_coalesce_usecs.set &&
!coalesce->tx_max_coalesced_frames.set &&
!coalesce->tx_coalesce_usecs_irq.set &&
!coalesce->tx_max_coalesced_frames_irq.set &&
!coalesce->stats_block_coalesce_usecs.set &&
!coalesce->pkt_rate_low.set &&
!coalesce->rx_coalesce_usecs_low.set &&
!coalesce->rx_max_coalesced_frames_low.set &&
!coalesce->tx_coalesce_usecs_low.set &&
!coalesce->tx_max_coalesced_frames_low.set &&
!coalesce->pkt_rate_high.set &&
!coalesce->rx_coalesce_usecs_high.set &&
!coalesce->rx_max_coalesced_frames_high.set &&
!coalesce->tx_coalesce_usecs_high.set &&
!coalesce->tx_max_coalesced_frames_high.set &&
!coalesce->rate_sample_interval.set)
return 0;
r = ethtool_connect(ethtool_fd);
if (r < 0)
return r;
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
if (coalesce->use_adaptive_rx_coalesce >= 0)
UPDATE(ecmd.use_adaptive_rx_coalesce, (uint32_t) coalesce->use_adaptive_rx_coalesce, need_update);
if (coalesce->use_adaptive_tx_coalesce >= 0)
UPDATE(ecmd.use_adaptive_tx_coalesce, (uint32_t) coalesce->use_adaptive_tx_coalesce, need_update);
if (coalesce->rx_coalesce_usecs.set)
UPDATE(ecmd.rx_coalesce_usecs, coalesce->rx_coalesce_usecs.value, need_update);
if (coalesce->rx_max_coalesced_frames.set)
UPDATE(ecmd.rx_max_coalesced_frames, coalesce->rx_max_coalesced_frames.value, need_update);
if (coalesce->rx_coalesce_usecs_irq.set)
UPDATE(ecmd.rx_coalesce_usecs_irq, coalesce->rx_coalesce_usecs_irq.value, need_update);
if (coalesce->rx_max_coalesced_frames_irq.set)
UPDATE(ecmd.rx_max_coalesced_frames_irq, coalesce->rx_max_coalesced_frames_irq.value, need_update);
if (coalesce->tx_coalesce_usecs.set)
UPDATE(ecmd.tx_coalesce_usecs, coalesce->tx_coalesce_usecs.value, need_update);
if (coalesce->tx_max_coalesced_frames.set)
UPDATE(ecmd.tx_max_coalesced_frames, coalesce->tx_max_coalesced_frames.value, need_update);
if (coalesce->tx_coalesce_usecs_irq.set)
UPDATE(ecmd.tx_coalesce_usecs_irq, coalesce->tx_coalesce_usecs_irq.value, need_update);
if (coalesce->tx_max_coalesced_frames_irq.set)
UPDATE(ecmd.tx_max_coalesced_frames_irq, coalesce->tx_max_coalesced_frames_irq.value, need_update);
if (coalesce->stats_block_coalesce_usecs.set)
UPDATE(ecmd.stats_block_coalesce_usecs, coalesce->stats_block_coalesce_usecs.value, need_update);
if (coalesce->pkt_rate_low.set)
UPDATE(ecmd.pkt_rate_low, coalesce->pkt_rate_low.value, need_update);
if (coalesce->rx_coalesce_usecs_low.set)
UPDATE(ecmd.rx_coalesce_usecs_low, coalesce->rx_coalesce_usecs_low.value, need_update);
if (coalesce->rx_max_coalesced_frames_low.set)
UPDATE(ecmd.rx_max_coalesced_frames_low, coalesce->rx_max_coalesced_frames_low.value, need_update);
if (coalesce->tx_coalesce_usecs_low.set)
UPDATE(ecmd.tx_coalesce_usecs_low, coalesce->tx_coalesce_usecs_low.value, need_update);
if (coalesce->tx_max_coalesced_frames_low.set)
UPDATE(ecmd.tx_max_coalesced_frames_low, coalesce->tx_max_coalesced_frames_low.value, need_update);
if (coalesce->pkt_rate_high.set)
UPDATE(ecmd.pkt_rate_high, coalesce->pkt_rate_high.value, need_update);
if (coalesce->rx_coalesce_usecs_high.set)
UPDATE(ecmd.rx_coalesce_usecs_high, coalesce->rx_coalesce_usecs_high.value, need_update);
if (coalesce->rx_max_coalesced_frames_high.set)
UPDATE(ecmd.rx_max_coalesced_frames_high, coalesce->rx_max_coalesced_frames_high.value, need_update);
if (coalesce->tx_coalesce_usecs_high.set)
UPDATE(ecmd.tx_coalesce_usecs_high, coalesce->tx_coalesce_usecs_high.value, need_update);
if (coalesce->tx_max_coalesced_frames_high.set)
UPDATE(ecmd.tx_max_coalesced_frames_high, coalesce->tx_max_coalesced_frames_high.value, need_update);
if (coalesce->rate_sample_interval.set)
UPDATE(ecmd.rate_sample_interval, DIV_ROUND_UP(coalesce->rate_sample_interval.value, USEC_PER_SEC), need_update);
if (!need_update)
return 0;
ecmd.cmd = ETHTOOL_SCOALESCE;
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
return 0;
}

View File

@ -649,7 +649,7 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) {
msgcnt++; msgcnt++;
assert(msgcnt < NFT_INIT_MSGS); assert(msgcnt < NFT_INIT_MSGS);
/* Set F_EXCL so table add fails if the table already exists. */ /* Set F_EXCL so table add fails if the table already exists. */
r = sd_nfnl_nft_message_new_table(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, NLM_F_EXCL | NLM_F_ACK); r = sd_nfnl_nft_message_new_table(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME);
if (r < 0) if (r < 0)
goto out_unref; goto out_unref;

View File

@ -1,17 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "log.h" #include "log.h"
#include "string-util.h"
#include "wifi-util.h" #include "wifi-util.h"
int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid) { int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
sd_genl_family_t family; const char *family;
int r; int r;
assert(genl); assert(genl);
assert(ifindex > 0); assert(ifindex > 0);
r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m); r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &m);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to create generic netlink message: %m"); return log_debug_errno(r, "Failed to create generic netlink message: %m");
@ -38,11 +39,11 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftyp
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to get information about wifi interface %d: %m", ifindex); return log_debug_errno(r, "Failed to get information about wifi interface %d: %m", ifindex);
r = sd_genl_message_get_family(genl, reply, &family); r = sd_genl_message_get_family_name(genl, reply, &family);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to determine genl family: %m"); return log_debug_errno(r, "Failed to determine genl family: %m");
if (family != SD_GENL_NL80211) { if (!streq(family, NL80211_GENL_NAME)) {
log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family); log_debug("Received message of unexpected genl family '%s', ignoring.", family);
goto nodata; goto nodata;
} }
@ -75,14 +76,14 @@ nodata:
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) { int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
sd_genl_family_t family; const char *family;
int r; int r;
assert(genl); assert(genl);
assert(ifindex > 0); assert(ifindex > 0);
assert(bssid); assert(bssid);
r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m); r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &m);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to create generic netlink message: %m"); return log_debug_errno(r, "Failed to create generic netlink message: %m");
@ -106,11 +107,11 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to get information about wifi station: %m"); return log_debug_errno(r, "Failed to get information about wifi station: %m");
r = sd_genl_message_get_family(genl, reply, &family); r = sd_genl_message_get_family_name(genl, reply, &family);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to determine genl family: %m"); return log_debug_errno(r, "Failed to determine genl family: %m");
if (family != SD_GENL_NL80211) { if (!streq(family, NL80211_GENL_NAME)) {
log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family); log_debug("Received message of unexpected genl family '%s', ignoring.", family);
goto nodata; goto nodata;
} }

View File

@ -31,32 +31,15 @@
_SD_BEGIN_DECLARATIONS; _SD_BEGIN_DECLARATIONS;
typedef struct sd_netlink sd_netlink; typedef struct sd_netlink sd_netlink;
typedef struct sd_genl_socket sd_genl_socket;
typedef struct sd_netlink_message sd_netlink_message; typedef struct sd_netlink_message sd_netlink_message;
typedef struct sd_netlink_slot sd_netlink_slot; typedef struct sd_netlink_slot sd_netlink_slot;
typedef enum sd_genl_family_t {
SD_GENL_ERROR,
SD_GENL_DONE,
SD_GENL_ID_CTRL,
SD_GENL_WIREGUARD,
SD_GENL_FOU,
SD_GENL_L2TP,
SD_GENL_MACSEC,
SD_GENL_NL80211,
SD_GENL_BATADV,
_SD_GENL_FAMILY_MAX,
_SD_GENL_FAMILY_INVALID = -EINVAL,
_SD_ENUM_FORCE_S64(GENL_FAMILY)
} sd_genl_family_t;
/* callback */ /* callback */
typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata); typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata);
typedef _sd_destroy_t sd_netlink_destroy_t; typedef _sd_destroy_t sd_netlink_destroy_t;
/* bus */ /* bus */
int sd_netlink_new_from_netlink(sd_netlink **nl, int fd); int sd_netlink_new_from_fd(sd_netlink **nl, int fd);
int sd_netlink_open(sd_netlink **nl); int sd_netlink_open(sd_netlink **nl);
int sd_netlink_open_fd(sd_netlink **nl, int fd); int sd_netlink_open_fd(sd_netlink **nl, int fd);
int sd_netlink_inc_rcvbuf(sd_netlink *nl, const size_t size); int sd_netlink_inc_rcvbuf(sd_netlink *nl, const size_t size);
@ -86,6 +69,7 @@ int sd_netlink_add_match(sd_netlink *nl, sd_netlink_slot **ret_slot, uint16_t ma
int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority); int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority);
int sd_netlink_detach_event(sd_netlink *nl); int sd_netlink_detach_event(sd_netlink *nl);
/* message */
int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data); int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data);
int sd_netlink_message_append_strv(sd_netlink_message *m, unsigned short type, char * const *data); int sd_netlink_message_append_strv(sd_netlink_message *m, unsigned short type, char * const *data);
int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type); int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type);
@ -129,7 +113,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m);
int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type); int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type);
int sd_netlink_message_cancel_array(sd_netlink_message *m); int sd_netlink_message_cancel_array(sd_netlink_message *m);
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl); int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl);
sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m); sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m);
@ -182,12 +166,12 @@ int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char
int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_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_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_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_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_set_flags(sd_netlink_message *m, uint8_t flags);
int sd_rtnl_message_nexthop_get_family(sd_netlink_message *m, uint8_t *family); 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_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_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_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_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_set_state(sd_netlink_message *m, uint16_t state);
int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family); int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family);
@ -224,13 +208,13 @@ int sd_rtnl_message_set_tclass_handle(sd_netlink_message *m, uint32_t handle);
int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex); int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex);
/* nfnl */ /* nfnl */
int sd_nfnl_socket_open(sd_netlink **nl); int sd_nfnl_socket_open(sd_netlink **ret);
int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret); int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret);
int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret); int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret);
int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table); int family, const char *table);
int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, uint16_t nl_flags); int family, const char *table);
int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *chain, int family, const char *table, const char *chain,
const char *type, uint8_t hook, int prio); const char *type, uint8_t hook, int prio);
@ -250,13 +234,19 @@ int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m,
int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m); int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m);
/* genl */ /* genl */
int sd_genl_socket_open(sd_netlink **nl); int sd_genl_socket_open(sd_netlink **ret);
int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret); int sd_genl_message_new(sd_netlink *genl, const char *family_name, uint8_t cmd, sd_netlink_message **ret);
int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *ret); int sd_genl_message_get_family_name(sd_netlink *genl, sd_netlink_message *m, const char **ret);
int sd_genl_message_get_command(sd_netlink *genl, sd_netlink_message *m, uint8_t *ret);
int sd_genl_add_match(sd_netlink *nl, sd_netlink_slot **ret_slot, const char *family_name,
const char *multicast_group_name, uint8_t command,
sd_netlink_message_handler_t callback,
sd_netlink_destroy_t destroy_callback,
void *userdata, const char *description);
/* slot */ /* slot */
sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *nl); sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *slot);
sd_netlink_slot *sd_netlink_slot_unref(sd_netlink_slot *nl); sd_netlink_slot *sd_netlink_slot_unref(sd_netlink_slot *slot);
sd_netlink *sd_netlink_slot_get_netlink(sd_netlink_slot *slot); 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_get_userdata(sd_netlink_slot *slot);

View File

@ -4,9 +4,13 @@
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/types.h> #include <sys/types.h>
#include "sd-event.h"
#include "capability-util.h" #include "capability-util.h"
#include "cpu-set-util.h" #include "cpu-set-util.h"
#include "dropin.h"
#include "errno-list.h" #include "errno-list.h"
#include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fs-util.h" #include "fs-util.h"
#include "macro.h" #include "macro.h"
@ -14,11 +18,14 @@
#include "missing_prctl.h" #include "missing_prctl.h"
#include "mkdir.h" #include "mkdir.h"
#include "path-util.h" #include "path-util.h"
#include "process-util.h"
#include "rm-rf.h" #include "rm-rf.h"
#if HAVE_SECCOMP #if HAVE_SECCOMP
#include "seccomp-util.h" #include "seccomp-util.h"
#endif #endif
#include "service.h" #include "service.h"
#include "signal-util.h"
#include "static-destruct.h"
#include "stat-util.h" #include "stat-util.h"
#include "tests.h" #include "tests.h"
#include "unit.h" #include "unit.h"
@ -26,8 +33,11 @@
#include "util.h" #include "util.h"
#include "virt.h" #include "virt.h"
static char *user_runtime_unit_dir = NULL;
static bool can_unshare; static bool can_unshare;
STATIC_DESTRUCTOR_REGISTER(user_runtime_unit_dir, freep);
typedef void (*test_function_t)(Manager *m); typedef void (*test_function_t)(Manager *m);
static int cld_dumped_to_killed(int code) { static int cld_dumped_to_killed(int code) {
@ -79,16 +89,15 @@ static void check_main_result(const char *file, unsigned line, const char *func,
exec_status_dump(&service->main_exec_status, stdout, "\t"); exec_status_dump(&service->main_exec_status, stdout, "\t");
if (cld_dumped_to_killed(service->main_exec_status.code) != cld_dumped_to_killed(code_expected)) { if (cld_dumped_to_killed(service->main_exec_status.code) != cld_dumped_to_killed(code_expected)) {
log_error("%s:%u:%s %s: exit code %d, expected %d", log_error("%s:%u:%s %s: can_unshare=%s: exit code %d, expected %d",
file, line, func, file, line, func, unit->id, yes_no(can_unshare),
unit->id,
service->main_exec_status.code, code_expected); service->main_exec_status.code, code_expected);
abort(); abort();
} }
if (service->main_exec_status.status != status_expected) { if (service->main_exec_status.status != status_expected) {
log_error("%s:%u:%s: %s: exit status %d, expected %d", log_error("%s:%u:%s: %s: can_unshare=%s: exit status %d, expected %d",
file, line, func, unit->id, file, line, func, unit->id, yes_no(can_unshare),
service->main_exec_status.status, status_expected); service->main_exec_status.status, status_expected);
abort(); abort();
} }
@ -106,9 +115,8 @@ static void check_service_result(const char *file, unsigned line, const char *fu
service = SERVICE(unit); service = SERVICE(unit);
if (service->result != result_expected) { if (service->result != result_expected) {
log_error("%s:%u:%s: %s: service end result %s, expected %s", log_error("%s:%u:%s: %s: can_unshare=%s: service end result %s, expected %s",
file, line, func, file, line, func, unit->id, yes_no(can_unshare),
unit->id,
service_result_to_string(service->result), service_result_to_string(service->result),
service_result_to_string(result_expected)); service_result_to_string(result_expected));
abort(); abort();
@ -408,6 +416,190 @@ static void test_exec_inaccessiblepaths(Manager *m) {
test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
} }
static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
char **result = userdata;
char buf[4096];
ssize_t l;
assert(s);
assert(fd >= 0);
l = read(fd, buf, sizeof(buf) - 1);
if (l < 0) {
if (errno == EAGAIN)
goto reenable;
return 0;
}
if (l == 0)
return 0;
buf[l] = '\0';
if (result)
assert_se(strextend(result, buf));
else
log_error("ldd: %s", buf);
reenable:
/* Re-enable the event source if we did not encounter EOF */
assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
return 0;
}
static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
pid_t *pid = userdata;
assert(pid);
(void) kill(*pid, SIGKILL);
return 1;
}
static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
int ret = -EIO;
assert(si);
if (si->si_code == CLD_EXITED)
ret = si->si_status;
sd_event_exit(sd_event_source_get_event(s), ret);
return 1;
}
static int find_libraries(const char *exec, char ***ret) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *sigchld_source = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *stdout_source = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *stderr_source = NULL;
_cleanup_close_pair_ int outpipe[2] = {-1, -1}, errpipe[2] = {-1, -1};
_cleanup_strv_free_ char **libraries = NULL;
_cleanup_free_ char *result = NULL;
pid_t pid;
int r;
assert(exec);
assert(ret);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
assert_se(pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) == 0);
assert_se(pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) == 0);
r = safe_fork("(spawn-ldd)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
assert_se(r >= 0);
if (r == 0) {
if (rearrange_stdio(-1, outpipe[1], errpipe[1]) < 0)
_exit(EXIT_FAILURE);
(void) close_all_fds(NULL, 0);
execlp("ldd", "ldd", exec, NULL);
_exit(EXIT_FAILURE);
}
outpipe[1] = safe_close(outpipe[1]);
errpipe[1] = safe_close(errpipe[1]);
assert_se(sd_event_new(&e) >= 0);
assert_se(sd_event_add_time_relative(e, NULL, CLOCK_MONOTONIC,
10 * USEC_PER_SEC, USEC_PER_SEC, on_spawn_timeout, &pid) >= 0);
assert_se(sd_event_add_io(e, &stdout_source, outpipe[0], EPOLLIN, on_spawn_io, &result) >= 0);
assert_se(sd_event_source_set_enabled(stdout_source, SD_EVENT_ONESHOT) >= 0);
assert_se(sd_event_add_io(e, &stderr_source, errpipe[0], EPOLLIN, on_spawn_io, NULL) >= 0);
assert_se(sd_event_source_set_enabled(stderr_source, SD_EVENT_ONESHOT) >= 0);
assert_se(sd_event_add_child(e, &sigchld_source, pid, WEXITED, on_spawn_sigchld, NULL) >= 0);
/* SIGCHLD should be processed after IO is complete */
assert_se(sd_event_source_set_priority(sigchld_source, SD_EVENT_PRIORITY_NORMAL + 1) >= 0);
assert_se(sd_event_loop(e) >= 0);
_cleanup_strv_free_ char **v = NULL;
assert_se(strv_split_newlines_full(&v, result, 0) >= 0);
char **q;
STRV_FOREACH(q, v) {
_cleanup_free_ char *word = NULL;
const char *p = *q;
r = extract_first_word(&p, &word, NULL, 0);
assert_se(r >= 0);
if (r == 0)
continue;
if (path_is_absolute(word)) {
assert_se(strv_consume(&libraries, TAKE_PTR(word)) >= 0);
continue;
}
word = mfree(word);
r = extract_first_word(&p, &word, NULL, 0);
assert_se(r >= 0);
if (r == 0)
continue;
if (!streq_ptr(word, "=>"))
continue;
word = mfree(word);
r = extract_first_word(&p, &word, NULL, 0);
assert_se(r >= 0);
if (r == 0)
continue;
if (path_is_absolute(word)) {
assert_se(strv_consume(&libraries, TAKE_PTR(word)) >= 0);
continue;
}
}
*ret = TAKE_PTR(libraries);
return 0;
}
static void test_exec_mount_apivfs(Manager *m) {
_cleanup_free_ char *fullpath_touch = NULL, *fullpath_test = NULL, *data = NULL;
_cleanup_strv_free_ char **libraries = NULL, **libraries_test = NULL;
int r;
assert(user_runtime_unit_dir);
r = find_executable("touch", &fullpath_touch);
if (r < 0) {
log_notice_errno(r, "Skipping %s, could not find 'touch' command: %m", __func__);
return;
}
r = find_executable("test", &fullpath_test);
if (r < 0) {
log_notice_errno(r, "Skipping %s, could not find 'test' command: %m", __func__);
return;
}
assert_se(find_libraries(fullpath_touch, &libraries) >= 0);
assert_se(find_libraries(fullpath_test, &libraries_test) >= 0);
assert_se(strv_extend_strv(&libraries, libraries_test, true) >= 0);
assert_se(strextend(&data, "[Service]\n"));
assert_se(strextend(&data, "ExecStart=", fullpath_touch, " /aaa\n"));
assert_se(strextend(&data, "ExecStart=", fullpath_test, " -f /aaa\n"));
assert_se(strextend(&data, "BindReadOnlyPaths=", fullpath_touch, "\n"));
assert_se(strextend(&data, "BindReadOnlyPaths=", fullpath_test, "\n"));
char **p;
STRV_FOREACH(p, libraries)
assert_se(strextend(&data, "BindReadOnlyPaths=", *p, "\n"));
assert_se(write_drop_in(user_runtime_unit_dir, "exec-mount-apivfs-no.service", 10, "bind-mount", data) >= 0);
assert_se(mkdir_p("/tmp/test-exec-mount-apivfs-no/root", 0755) >= 0);
test(m, "exec-mount-apivfs-no.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
(void) rm_rf("/tmp/test-exec-mount-apivfs-no/root", REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_exec_noexecpaths(Manager *m) { static void test_exec_noexecpaths(Manager *m) {
test(m, "exec-noexecpaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); test(m, "exec-noexecpaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
@ -871,6 +1063,7 @@ int main(int argc, char *argv[]) {
entry(test_exec_ignoresigpipe), entry(test_exec_ignoresigpipe),
entry(test_exec_inaccessiblepaths), entry(test_exec_inaccessiblepaths),
entry(test_exec_ioschedulingclass), entry(test_exec_ioschedulingclass),
entry(test_exec_mount_apivfs),
entry(test_exec_noexecpaths), entry(test_exec_noexecpaths),
entry(test_exec_oomscoreadjust), entry(test_exec_oomscoreadjust),
entry(test_exec_passenvironment), entry(test_exec_passenvironment),
@ -931,10 +1124,12 @@ int main(int argc, char *argv[]) {
if (r == -ENOMEDIUM) if (r == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available"); return log_tests_skipped("cgroupfs not available");
_cleanup_free_ char *unit_dir = NULL; _cleanup_free_ char *unit_dir = NULL, *unit_paths = NULL;
assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0); assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir()); assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(user_runtime_unit_dir = path_join(runtime_dir, "systemd/user"));
assert_se(unit_paths = strjoin(unit_dir, ":", user_runtime_unit_dir));
assert_se(set_unit_path(unit_paths) >= 0);
/* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
* cases, otherwise (and if they are present in the environment), * cases, otherwise (and if they are present in the environment),

View File

@ -142,6 +142,8 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
.tx_flow_control = -1, .tx_flow_control = -1,
.autoneg_flow_control = -1, .autoneg_flow_control = -1,
.txqueuelen = UINT32_MAX, .txqueuelen = UINT32_MAX,
.coalesce.use_adaptive_rx_coalesce = -1,
.coalesce.use_adaptive_tx_coalesce = -1,
}; };
for (i = 0; i < ELEMENTSOF(link->features); i++) for (i = 0; i < ELEMENTSOF(link->features); i++)

View File

@ -0,0 +1 @@
../TEST-01-BASIC/Makefile

View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -e
TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/17433"
# shellcheck source=test/test-functions
. "${TEST_BASE_DIR:?}/test-functions"
do_test "$@"

View File

@ -33,6 +33,8 @@ if install_tests
install_dir : testdata_dir) install_dir : testdata_dir)
install_subdir('testsuite-52.units', install_subdir('testsuite-52.units',
install_dir : testdata_dir) install_dir : testdata_dir)
install_subdir('testsuite-63.units',
install_dir : testdata_dir)
testsuite08_dir = testdata_dir + '/testsuite-08.units' testsuite08_dir = testdata_dir + '/testsuite-08.units'
install_data('testsuite-08.units/-.mount', install_data('testsuite-08.units/-.mount',

View File

@ -0,0 +1,15 @@
[Unit]
Description=Test for find_executable() with MountAPIVFS=no
[Service]
Type=oneshot
MountAPIVFS=false
PrivateDevices=false
PrivateMounts=true
PrivateTmp=false
PrivateUsers=false
ProtectControlGroups=false
ProtectKernelModules=false
ProtectKernelTunables=false
RootDirectory=/tmp/test-exec-mount-apivfs-no/root

View File

@ -148,6 +148,7 @@ BASICTOOLS=(
head head
ionice ionice
ip ip
ldd
ln ln
loadkeys loadkeys
login login

View File

@ -1155,7 +1155,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
f.write('[MACVTAP]\nMode=' + mode) f.write('[MACVTAP]\nMode=' + mode)
start_networkd() start_networkd()
self.wait_online(['macvtap99:degraded', 'test1:degraded']) self.wait_online(['macvtap99:degraded',
'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
output = check_output('ip -d link show macvtap99') output = check_output('ip -d link show macvtap99')
print(output) print(output)
@ -1172,7 +1173,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
f.write('[MACVLAN]\nMode=' + mode) f.write('[MACVLAN]\nMode=' + mode)
start_networkd() start_networkd()
self.wait_online(['macvlan99:degraded', 'test1:degraded']) self.wait_online(['macvlan99:degraded',
'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
output = check_output('ip -d link show test1') output = check_output('ip -d link show test1')
print(output) print(output)
@ -1191,7 +1193,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.assertEqual(rc, 0) self.assertEqual(rc, 0)
time.sleep(1) time.sleep(1)
self.wait_online(['macvlan99:degraded', 'test1:degraded']) self.wait_online(['macvlan99:degraded',
'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
output = check_output('ip -d link show test1') output = check_output('ip -d link show test1')
print(output) print(output)

View File

@ -1,6 +1,9 @@
[Unit] [Unit]
Requires=test10.socket Requires=test10.socket
ConditionPathExistsGlob=/tmp/nonexistent ConditionPathExistsGlob=/tmp/nonexistent
# Make sure we hit the socket trigger limit in the test and not the service start limit.
StartLimitInterval=1000
StartLimitBurst=1000
[Service] [Service]
ExecStart=true ExecStart=true

View File

@ -0,0 +1,2 @@
[Path]
PathExists=/tmp/test63

View File

@ -0,0 +1,5 @@
[Unit]
ConditionPathExists=!/tmp/nonexistent
[Service]
ExecStart=true

View File

@ -0,0 +1,16 @@
[Unit]
Description=TEST-63-ISSUE-17433
[Service]
ExecStartPre=rm -f /failed /testok
Type=oneshot
ExecStart=rm -f /tmp/nonexistent
ExecStart=systemctl start test63.path
ExecStart=touch /tmp/test63
# Make sure systemd has sufficient time to hit the start limit for test63.service.
ExecStart=sleep 2
ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = failed'
ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = start-limit-hit'
ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = failed'
ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = unit-start-limit-hit'
ExecStart=sh -x -c 'echo OK >/testok'