Compare commits

...

26 Commits

Author SHA1 Message Date
Lennart Poettering 6a6078a585 test: minor typo fix
As pointed out on: https://github.com/systemd/systemd/pull/14465#discussion_r364152064
2020-01-08 14:50:30 +00:00
Lennart Poettering 0aa9bffe10
Merge pull request #14448 from yuwata/network-permanent-mac-address
network, udev: support permanent mac address
2020-01-08 15:36:27 +01:00
Lennart Poettering 3bfcfcf942
Merge pull request #14518 from keszybz/interface-text
doc: tweak grammar in CONTAINER_INTERFACE description
2020-01-08 14:26:33 +01:00
Lennart Poettering a1edbc5118
Merge pull request #14511 from keszybz/sleep-check-rework
Sleep check rework
2020-01-08 14:26:17 +01:00
Lennart Poettering 48dfa8b0e1
Merge pull request #14512 from poettering/root-image-devices
Make RootImage= work reliable with DeviceAllow= in the mix
2020-01-08 12:18:38 +01:00
Frantisek Sumsal 514793658c test: pin meson to 0.52.1 for fuzzit/fuzzbuzz
Latest meson doesn't work with older python 3.5, which is present on
Ubuntu 16.04. Let's pin in to the latest working version (0.52.1) until
we properly bump all necessary Ubuntu images to 18.04.

See: https://github.com/mesonbuild/meson/issues/6427
2020-01-08 13:56:30 +03:00
Zbigniew Jędrzejewski-Szmek 06ae8800d0
Merge pull request #14465 from poettering/setprio-rework
When Nice= is used, clamp to RLIMIT_NICE
2020-01-08 11:06:46 +01:00
Zbigniew Jędrzejewski-Szmek 629548c405
Merge pull request #14488 from yuwata/networkctl-show-logs
networkctl: status command also shows logs of networkd
2020-01-08 10:49:39 +01:00
Zbigniew Jędrzejewski-Szmek 9552209292 man: fix option name 2020-01-08 10:39:44 +01:00
Zbigniew Jędrzejewski-Szmek d2e825b4ab doc: tweak grammar in CONTAINER_INTERFACE description
The only non-stylistic change is to replace descriptions of how we are
encouraging people to use PrivateTmp= and such, because now they are widely
used.
2020-01-08 10:29:10 +01:00
Yu Watanabe caa8538a22 networkctl: show permanent mac address if it is not used now 2020-01-08 17:54:59 +09:00
Yu Watanabe 4bb7cc8287 network, udev: introduce PermanentMACAddress= setting in [Match] section
Closes #13983.
2020-01-08 17:54:54 +09:00
Yu Watanabe 79b4428a7d ethtool: introduce ethtool_get_permanent_macaddr()
Will be used in later commits.
2020-01-08 17:51:56 +09:00
Zbigniew Jędrzejewski-Szmek 8f817cb888 shared/sleep-config: do not ignore resume_offset when resume not set
This is most likely a user error, let's make it easier to diagnose.
2020-01-08 08:07:14 +01:00
Zbigniew Jędrzejewski-Szmek 8efc2c1608 shared/sleep-config: make swap detection stricter again
To make this easier to understand, let's always log (at debug level)
when we accept or reject each device:
/swapfile: detection of swap file offset on Btrfs is not supported
/swapfile: is a candidate device.
/dev/zram0: ignoring zram swap
/dev/vdb: ignoring device with lower priority
/dev/vdc: ignoring device with lower usable space
...

If we know that hibernation will fail, refuse. This includes cases where
/sys/power/resume is set and doesn't match any device, or
/sys/power/resume_offset is set and we're not on btrfs and it doesn't match.
If /sys/power/resume is not set at all, we still accept the device with the
highest priority (see 6d176522f5 and
88bc86fcf8)

Tested cases:
1. no swap active → refuse
2. just zram swap active → refuse
3. swapfile on btrfs with /sys/power/resume{,_offset} set → OK
4. swapfile on btrfs with /sys/power/resume set, offset not set → refuse
5. swapfile on btrfs with /sys/power/resume set to nonexistent device, offset set → refuse
6. /sys/power/resume not set, offset set, candidate exists → OK (*)
7. /sys/power/resume not set, offset not set, candidate exists → OK

(*) I think this should fail, but I'm leaving that for the next commit.
2020-01-08 08:07:14 +01:00
Lennart Poettering 3a827125e7 man: stop recommending modprobe -abq in ExecStartPre= 2020-01-07 19:00:56 +01:00
Lennart Poettering d5016c21d7 units: tweaks to modprobe@.service
Let's use uppercase wording in the description string, like we usually
do.

Let's allow using this service in early boot.

If it's pulled into the initial transaction it's better to finish
loading this before sysinit.target.

Don't bother with this in containers that lack CAP_SYS_MODULE
2020-01-07 18:54:24 +01:00
Lennart Poettering 867af7282b unit: make sure to pull in modprobe@loop.service when RootImage= is used with DeviceAllow=
Fixes: #14214
2020-01-07 18:53:31 +01:00
Lennart Poettering 07141aa005 bpf-devices: line-break some overly long function signatures 2020-01-07 18:41:36 +01:00
Zbigniew Jędrzejewski-Szmek e9f0c5d08c shared/sleep: use stat() instead of open()+fstat() in one place
No functional change.
2020-01-07 16:20:35 +01:00
Yu Watanabe 98b0299479 network: append INTERFACE= attributes for logs corresponds to a netif 2020-01-07 22:20:43 +09:00
Yu Watanabe fc79e6ff5e test-network: suppress logs in status command 2020-01-07 22:20:43 +09:00
Yu Watanabe 10c71c3605 networkctl: status command also shows logs of networkd
Closes #14050.
2020-01-07 22:20:37 +09:00
Zach Smith 52133271a7 systemd-sleep: always attempt hibernation if configured
When calculation of swap file offset is unsupported, rely on the
/sys/power/resume & /sys/power/resume_offset values if configured
rather than requiring a matching swap entry to be identified.

Refactor to use dev_t for comparison of resume= device instead of string.
2020-01-05 20:15:38 -08:00
Lennart Poettering 75997c3fa5 test: add test case for setpriority_closest() 2020-01-02 21:00:30 +01:00
Dimitri John Ledkov 390902012c core: in execute, Never fail setting Nice priority
Instead, push to the closest possible Nice priority setting.

Replaces: #11397
2020-01-02 20:50:14 +01:00
50 changed files with 822 additions and 318 deletions

View File

@ -16,23 +16,22 @@ manager, please consider supporting the following interfaces.
## Execution Environment
1. If the container manager wants to control the hostname for a container
running systemd it should just set it before invoking systemd, and systemd
will leave it unmodified (that is unless there's an explicit hostname
configured in `/etc/hostname` which overrides whatever is pre-initialized by
the container manager).
running systemd it may just set it before invoking systemd, and systemd will
leave it unmodified when there is no hostname configured in `/etc/hostname`
(that file overrides whatever is pre-initialized by the container manager).
2. Make sure to pre-mount `/proc/`, `/sys/` and `/sys/fs/selinux/` before
invoking systemd, and mount `/proc/sys/`, `/sys/` and `/sys/fs/selinux/`
read-only in order to avoid that the container can alter the host kernel's
configuration settings. (As special exception, if your container has network
namespaces enabled, feel free to make `/proc/sys/net/` writable). systemd
and various other subsystems (such as the SELinux userspace) have been
modified to detect whether these file systems are read-only, and will behave
accordingly. (It's OK to mount `/sys/` as `tmpfs` btw, and only mount a
subset of its sub-trees from the real `sysfs` to hide `/sys/firmware/`,
`/sys/kernel/` and so on. If you do that, still make sure to mark `/sys/`
read-only, as that condition is what systemd looks for, and is what is
considered to be the API in this context.)
2. Make sure to pre-mount `/proc/`, `/sys/`, and `/sys/fs/selinux/` before
invoking systemd, and mount `/proc/sys/`, `/sys/`, and `/sys/fs/selinux/`
read-only in order to prevent the container from altering the host kernel's
configuration settings. (As a special exception, if your container has
network namespaces enabled, feel free to make `/proc/sys/net/` writable).
systemd and various other subsystems (such as the SELinux userspace) have
been modified to behave accordingly when these file systems are read-only.
(It's OK to mount `/sys/` as `tmpfs` btw, and only mount a subset of its
sub-trees from the real `sysfs` to hide `/sys/firmware/`, `/sys/kernel/` and
so on. If you do that, make sure to mark `/sys/` read-only, as that
condition is what systemd looks for, and is what is considered to be the API
in this context.)
3. Pre-mount `/dev/` as (container private) `tmpfs` for the container and bind
mount some suitable TTY to `/dev/console`. Also, make sure to create device
@ -42,17 +41,17 @@ manager, please consider supporting the following interfaces.
sure to set up a `BPF_PROG_TYPE_CGROUP_DEVICE` BPF program — on cgroupv2 —
or the `devices` cgroup controller — on cgroupv1 — so that no other devices
but these may be created in the container. Note that many systemd services
these days use `PrivateDevices=`, which means that systemd will set up a
private `/dev/` for them for which it needs to be able to create these
device nodes. Dropping `CAP_MKNOD` for containers is hence generally not
advisable, but see below.
use `PrivateDevices=`, which means that systemd will set up a private
`/dev/` for them for which it needs to be able to create these device nodes.
Dropping `CAP_MKNOD` for containers is hence generally not advisable, but
see below.
4. `systemd-udevd` is not available in containers (and refuses to start), and hence device
dependencies are unavailable. The `systemd-udevd` unit files will check for `/sys/`
being read-only, as an indication whether device management can work. Hence
make sure to mount `/sys/` read-only in the container (see above). Various
clients to `systemd-udevd` also check the read-only state of `/sys/` in some cases,
including PID 1 itself and `systemd-networkd`.
4. `systemd-udevd` is not available in containers (and refuses to start), and
hence device dependencies are unavailable. The `systemd-udevd` unit files
will check for `/sys/` being read-only, as an indication whether device
management can work. Therefore make sure to mount `/sys/` read-only in the
container (see above). Various clients of `systemd-udevd` also check the
read-only state of `/sys/`, including PID 1 itself and `systemd-networkd`.
5. If systemd detects it is run in a container it will spawn a single shell on
`/dev/console`, and not care about VTs or multiple gettys on VTs. (But see
@ -70,7 +69,7 @@ manager, please consider supporting the following interfaces.
(this only applies to cgroupv1, of course), to protect the controllers from
alteration from inside the containers. Or to turn this around: only the
cgroup sub-tree of the container itself (on cgroupv2 in the unified
hierarchy, and on cgroupv1 in the `name=systemd` hierarchy) must be writable
hierarchy, and on cgroupv1 in the `name=systemd` hierarchy) may be writable
to the container.
7. Create the control group root of your container by either running your
@ -81,15 +80,15 @@ manager, please consider supporting the following interfaces.
it. This ensures that that the unit you created will be part of all cgroup
controllers (or at least the ones systemd understands). The latter may also
be done via `systemd-machined`'s `CreateMachine()` API. Make sure to use the
cgroup path systemd put your process in for all operations of the
container. Do not add new cgroup directories to the top of the tree. This
will not only confuse systemd and the admin, but also ensure your
implementation is not "stackable".
cgroup path systemd put your process in for all operations of the container.
Do not add new cgroup directories to the top of the tree. This will not only
confuse systemd and the admin, but also prevent your implementation from
being "stackable".
## Environment Variables
1. To allow systemd (and other code) to identify that it is executed within a
container, please set the `$container=` environment variable for PID 1 in
1. To allow systemd (and other programs) to identify that it is executed within
a container, please set the `$container` environment variable for PID 1 in
the container to a short lowercase string identifying your
implementation. With this in place the `ConditionVirtualization=` setting in
unit files will work properly. Example: `container=lxc-libvirt`
@ -97,51 +96,51 @@ manager, please consider supporting the following interfaces.
2. systemd has special support for allowing container managers to initialize
the UUID for `/etc/machine-id` to some manager supplied value. This is only
enabled if `/etc/machine-id` is empty (i.e. not yet set) at boot time of the
container. The container manager should set `$container_uuid=` as
environment variable for the container's PID 1 to the container UUID it
wants to set. (This is similar to the effect of `qemu`'s `-uuid`
switch). Note that you should pass only a UUID here that is actually unique
(i.e. only one running container should have a specific UUID), and gets
changed when a container gets duplicated. Also note that systemd will try to
persistently store the UUID in `/etc/machine-id` (if writable) when this
option is used, hence you should always pass the same UUID here. Keeping the
externally used UUID for a container and the internal one in sync is
hopefully useful to minimize surprise for the administrator.
container. The container manager should set `$container_uuid` as environment
variable for the container's PID 1 to the container UUID. (This is similar
to the effect of `qemu`'s `-uuid` switch). Note that you should pass only a
UUID here that is actually unique (i.e. only one running container should
have a specific UUID), and gets changed when a container gets duplicated.
Also note that systemd will try to persistently store the UUID in
`/etc/machine-id` (if writable) when this option is used, hence you should
always pass the same UUID here. Keeping the externally used UUID for a
container and the internal one in sync is hopefully useful to minimize
surprise for the administrator.
3. systemd can automatically spawn login gettys on additional ptys. A container
manager can set the `$container_ttys=` environment variable for the
manager can set the `$container_ttys` environment variable for the
container's PID 1 to tell it on which ptys to spawn gettys. The variable
should take a space separated list of pty names, without the leading `/dev/`
prefix, but with the `pts/` prefix included. Note that despite the
variable's name you may only specify ptys, and not other types of ttys. Also
you need to specify the pty itself, a symlink will not suffice. This is
implemented in
[systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-getty-generator.html). Note
that this variable should not include the pty that `/dev/console` maps to if
it maps to one (see below). Example: if the container receives
`container_ttys=pts/7 pts/8 pts/14` it will spawn three additionally login
gettys on ptys 7, 8 and 14.
[systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-getty-generator.html).
Note that this variable should not include the pty that `/dev/console` maps
to if it maps to one (see below). Example: if the container receives
`container_ttys=pts/7 pts/8 pts/14` it will spawn three additional login
gettys on ptys 7, 8, and 14.
## Advanced Integration
1. Consider syncing `/etc/localtime` from the host file system into the
container. Make it a relative symlink to the containers's zoneinfo dir, as
usual. Tools rely on being able to determine the timezone setting from the
symlink value, and by making it relative it looks nice even if people list
the containers' `/etc/` from the host.
symlink value, and making it relative looks nice even if people list the
container's `/etc/` from the host.
2. Make the container journal available in the host, by automatically
symlinking the container journal directory into the host journal
directory. More precisely, link `/var/log/journal/<container-machine-id>` of
the container into the same dir of the host. Administrators can then
symlinking the container journal directory into the host journal directory.
More precisely, link `/var/log/journal/<container-machine-id>` of the
container into the same dir of the host. Administrators can then
automatically browse all container journals (correctly interleaved) by
issuing `journalctl -m`. The container machine ID you can determine from
issuing `journalctl -m`. The container machine ID can be determined from
`/etc/machine-id` in the container.
3. If the container manager wants to cleanly shutdown the container, it might
be a good idea to send `SIGRTMIN+3` to its init process. systemd will then do a
clean shutdown. Note however, that only systemd understands `SIGRTMIN+3` like
this, this might confuse other init systems.
be a good idea to send `SIGRTMIN+3` to its init process. systemd will then
do a clean shutdown. Note however, that since only systemd understands
`SIGRTMIN+3` like this, this might confuse other init systems.
4. To support [Socket Activated
Containers](http://0pointer.de/blog/projects/socket-activated-containers.html)
@ -150,33 +149,33 @@ manager, please consider supporting the following interfaces.
passed FDs in `$LISTEN_FDS` and its PID as `$LISTEN_PID`. It should take
these and pass them on to the container's init process, also setting
$LISTEN_FDS and `$LISTEN_PID` (basically, it can just leave the FDs and
`$LISTEN_FDS` untouched, but it needs to set `$LISTEN_PID` to for the
`$LISTEN_FDS` untouched, but it needs to adjust `$LISTEN_PID` to the
container init process). That's all that's necessary to make socket
activation work. The protocol to hand sockets from systemd to services is
hence the same as from a container manager to a container systemd. For
hence the same as from the container manager to the container systemd. For
further details see the explanations of
[sd_listen_fds(1)](http://0pointer.de/public/systemd-man/sd_listen_fds.html)
and the [blog story for service
developers](http://0pointer.de/blog/projects/socket-activation.html).
5. Container managers should stay away from the `name=systemd` cgroup hierarchy
outside of the unit they created for their container. That's private
property of systemd, and no other code should interfere with it.
5. Container managers should stay away from the cgroup hierarchy outside of the
unit they created for their container. That's private property of systemd,
and no other code should modify it.
## Networking
1. Inside of a container, if a `veth` link is named `host0`, `systemd-networkd`
running inside of the container will by default do DHCPv4 client, DHCPv6
client and IPv4LL on it. It is thus recommended that container managers that
add a `veth` link to a container name it `host0`, to get automatically
configured networked, with no manual interference from outside.
running inside of the container will by default run DHCPv4, DHCPv6, and
IPv4LL clients on it. It is thus recommended that container managers that
add a `veth` link to a container name it `host0`, to get an automatically
configured network, with no manual setup.
2. Outside of a container, if a `veth` link is prefixed "ve-" will by default do
DHCPv4 server and DHCPv6 serer on it, as well as IPv4LL. It is thus recommended
that container managers that add a `veth` link to a container name the external
side `ve-` followed by the container name.
2. Outside of a container, if a `veth` link is prefixed "ve-", `systemd-networkd`
will by default run DHCPv4 and DHCPv6 servers on it, as well as IPv4LL. It
is thus recommended that container managers that add a `veth` link to a
container name the external side `ve-` + the container name.
3. It is recommended to configure stable MAC addresses to container `veth`
3. It is recommended to configure stable MAC addresses for container `veth`
devices, for example hashed out of the container names. That way it is more
likely that DHCP and IPv4LL will acquire stable addresses.
@ -186,37 +185,34 @@ manager, please consider supporting the following interfaces.
used service setting that provides a service with its own, private, minimal
version of `/dev/`. To set this up systemd in the container needs this
capability. If you take away the capability than all services that set this
flag will cease to work, and this are increasingly many, as we encourage
people to make use of this functionality. Use `BPF_PROG_TYPE_CGROUP_DEVICE`
BPF programs — on cgroupv2 — or the `devices` controller — on cgroupv1 — to
restrict what device nodes the container can create instead of taking away
the capability wholesale. (Also see section about fully unprivileged
containers below.)
flag will cease to work. Use `BPF_PROG_TYPE_CGROUP_DEVICE` BPF programs — on
cgroupv2 — or the `devices` controller — on cgroupv1 — to restrict what
device nodes the container can create instead of taking away the capability
wholesale. (Also see the section about fully unprivileged containers below.)
2. Do not drop `CAP_SYS_ADMIN` from the container. A number of file system
namespacing related settings, such as `PrivateDevices=`, `ProtectHome=`,
`ProtectSystem=`, `MountFlags=`, `PrivateTmp=`, `ReadWriteDirectories=`,
`ReadOnlyDirectories=`, `InaccessibleDirectories=`, `MountFlags=` need to be
able to open new mount namespaces and the mount certain file system into
it. You break all services that make use of these flags if you drop the
flag. Note that already quite a number of services make use of this as we
actively encourage users to make use of this security functionality. Also
2. Do not drop `CAP_SYS_ADMIN` from the container. A number of the most
commonly used file system namespacing related settings, such as
`PrivateDevices=`, `ProtectHome=`, `ProtectSystem=`, `MountFlags=`,
`PrivateTmp=`, `ReadWriteDirectories=`, `ReadOnlyDirectories=`,
`InaccessibleDirectories=`, and `MountFlags=` need to be able to open new
mount namespaces and the mount certain file systems into them. You break all
services that make use of these options if you drop the capability. Also
note that logind mounts `XDG_RUNTIME_DIR` as `tmpfs` for all logged in users
and won't work either if you take away the capability. (Also see section
about fully unprivileged containers below.)
and that won't work either if you take away the capability. (Also see
section about fully unprivileged containers below.)
3. Do not cross-link `/dev/kmsg` with `/dev/console`. They are different things,
you cannot link them to each other.
4. Do not pretend that the real VTs would be available in the containers. The
VT subsystem consists of all devices `/dev/tty*`, `/dev/vcs*`, `/dev/vcsa*`
4. Do not pretend that the real VTs are available in the container. The VT
subsystem consists of all the devices `/dev/tty*`, `/dev/vcs*`, `/dev/vcsa*`
plus their `sysfs` counterparts. They speak specific `ioctl()`s and
understand specific escape sequences, that other ptys don't
understand. Hence, it is explicitly not OK to mount a pty to `/dev/tty1`,
`/dev/tty2`, `/dev/tty3`. This is explicitly not supported.
understand specific escape sequences, that other ptys don't understand.
Hence, it is explicitly not OK to mount a pty to `/dev/tty1`, `/dev/tty2`,
`/dev/tty3`. This is explicitly not supported.
5. Don't pretend that passing arbitrary devices to containers could really work
well. For example, do not pass device nodes for block devices, … to the
well. For example, do not pass device nodes for block devices to the
container. Device access (with the exception of network devices) is not
virtualized on Linux. Enumeration and probing of meta information from
`/sys/` and elsewhere is not possible to do correctly in a container. Simply
@ -231,7 +227,7 @@ manager, please consider supporting the following interfaces.
7. Do not make `/sys/` writable in the container. If you do,
`systemd-udevd.service` is started to manage your devices — inside the
container, but that will cause conflicts and errors given that the Linux
container, but that will cause conflicts and errors given that the Linux
device model is not virtualized for containers on Linux and thus the
containers and the host would try to manage the same devices, fighting for
ownership. Multiple other subsystems of systemd similarly test for `/sys/`
@ -249,15 +245,15 @@ manager, please consider supporting the following interfaces.
## Fully Unprivileged Container Payload
First things first, to make this clear: Linux containers are not a security
technology right now. There are more holes in the model than in a swiss cheese.
technology right now. There are more holes in the model than in swiss cheese.
For example: If you do not use user namespacing, and share root and other users
For example: if you do not use user namespacing, and share root and other users
between container and host, the `struct user` structures will be shared between
host and container, and hence `RLIMIT_NPROC` and so of the container users affect
the host and other containers, and vice versa. This is a major security hole,
and actually is a real-life problem: since Avahi sets `RLIMIT_NPROC` of its user
to 2 (to effectively disallow `fork()`ing) you cannot run more than one Avahi
instance on the entire system...
host and container, and hence `RLIMIT_NPROC` and so of the container users
affect the host and other containers, and vice versa. This is a major security
hole, and actually is a real-life problem: since Avahi sets `RLIMIT_NPROC` of
its user to 2 (to effectively disallow `fork()`ing) you cannot run more than
one Avahi instance on the entire system...
People have been asking to be able to run systemd without `CAP_SYS_ADMIN` and
`CAP_SYS_MKNOD` in the container. This is now supported to some level in

View File

@ -5,7 +5,11 @@ setup:
- sudo apt-get update -y
- sudo apt-get build-dep -y systemd
- sudo apt-get install -y python3-pip
- pip3 install meson ninja
# FIXME: temporarily pin the meson version as 0.53 doesn't work with older
# python 3.5
# # See: https://github.com/mesonbuild/meson/issues/6427
#
- pip3 install meson==0.52.1 ninja
- export PATH="$HOME/.local/bin/:$PATH"
- CC=$FUZZ_CC CXX=$FUZZ_CXX meson -Dfuzzbuzz=true -Dfuzzbuzz-engine-dir=$(dirname "$FUZZ_ENGINE") -Dfuzzbuzz-engine=$(cut -d. -f1 <(basename "$FUZZ_ENGINE")) -Db_lundef=false ./build
- ninja -v -C ./build fuzzers

View File

@ -311,6 +311,25 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
</listitem>
</varlistentry>
<varlistentry>
<term><option>-l</option></term>
<term><option>--full</option></term>
<listitem>
<para>Do not ellipsize the logs in <command>status</command> command.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-n</option></term>
<term><option>--lines=</option></term>
<listitem>
<para>When used with <command>status</command>, controls the number of journal lines to show,
counting from the most recent ones. Takes a positive integer argument. Defaults to 10.</para>
</listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
<xi:include href="standard-options.xml" xpointer="no-legend" />

View File

@ -80,6 +80,17 @@
<programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PermanentMACAddress=</varname></term>
<listitem>
<para>A whitespace-separated list of hardware's permanent addresses. While
<varname>MACAddress=</varname> matches the device's current MAC address, this matches the
device's permanent MAC address, which may be different from the current one. Use full
colon-, hyphen- or dot-delimited hexadecimal. This option may appear more than once, in
which case the lists are merged. If the empty string is assigned to this option, the list
of hardware addresses defined prior to this is reset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>OriginalName=</varname></term>
<listitem>

View File

@ -97,6 +97,17 @@
<programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PermanentMACAddress=</varname></term>
<listitem>
<para>A whitespace-separated list of hardware's permanent addresses. While
<varname>MACAddress=</varname> matches the device's current MAC address, this matches the
device's permanent MAC address, which may be different from the current one. Use full
colon-, hyphen- or dot-delimited hexadecimal. This option may appear more than once, in
which case the lists are merged. If the empty string is assigned to this option, the list
of hardware addresses defined prior to this is reset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Path=</varname></term>
<listitem>

View File

@ -720,10 +720,15 @@
<para>Note that whitelists defined this way should only reference device groups which are
resolvable at the time the unit is started. Any device groups not resolvable then are not added to
the device whitelist. In order to work around this limitation, consider extending service units
with an <command>ExecStartPre=/sbin/modprobe…</command> line that loads the necessary
kernel module implementing the device group if missing. Example: <programlisting>
with a pair of <command>After=modprobe@xyz.service</command> and
<command>Wants=modprobe@xyz.service</command> lines that load the necessary kernel module
implementing the device group if missing.
Example: <programlisting>
[Unit]
Wants=modprobe@loop.service
After=modprobe@loop.service
[Service]
ExecStartPre=-/sbin/modprobe -abq loop
DeviceAllow=block-loop
DeviceAllow=/dev/loop-control
</programlisting></para>

View File

@ -1545,7 +1545,7 @@
<para>Note: <varname>ConsistsOf=</varname>, <varname>BoundBy=</varname>,
<varname>RequisiteOf=</varname>, <varname>ConflictedBy=</varname> are created
implicitly along with their reverse and cannot be specified directly.</para>
implicitly along with their reverses and cannot be specified directly.</para>
<para>Note: <varname>Triggers=</varname> is created implicitly between a socket,
path unit, or an automount unit, and the unit they activate. By default a unit
@ -1557,7 +1557,7 @@
<citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
and
<citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. <varname>TriggersBy=</varname> is created implicitly on the
for details. <varname>TriggeredBy=</varname> is created implicitly on the
triggered unit.</para>
<para>Note: <varname>Following=</varname> is used to group device aliases and points to the

View File

@ -22,6 +22,7 @@
#include "alloc-util.h"
#include "architecture.h"
#include "env-util.h"
#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
@ -1527,6 +1528,62 @@ int pidfd_get_pid(int fd, pid_t *ret) {
return parse_pid(p, ret);
}
static int rlimit_to_nice(rlim_t limit) {
if (limit <= 1)
return PRIO_MAX-1; /* i.e. 19 */
if (limit >= -PRIO_MIN + PRIO_MAX)
return PRIO_MIN; /* i.e. -20 */
return PRIO_MAX - (int) limit;
}
int setpriority_closest(int priority) {
int current, limit, saved_errno;
struct rlimit highest;
/* Try to set requested nice level */
if (setpriority(PRIO_PROCESS, 0, priority) >= 0)
return 1;
/* Permission failed */
saved_errno = -errno;
if (!ERRNO_IS_PRIVILEGE(saved_errno))
return saved_errno;
errno = 0;
current = getpriority(PRIO_PROCESS, 0);
if (errno != 0)
return -errno;
if (priority == current)
return 1;
/* Hmm, we'd expect that raising the nice level from our status quo would always work. If it doesn't,
* then the whole setpriority() system call is blocked to us, hence let's propagate the error
* right-away */
if (priority > current)
return saved_errno;
if (getrlimit(RLIMIT_NICE, &highest) < 0)
return -errno;
limit = rlimit_to_nice(highest.rlim_cur);
/* We are already less nice than limit allows us */
if (current < limit) {
log_debug("Cannot raise nice level, permissions and the resource limit do not allow it.");
return 0;
}
/* Push to the allowed limit */
if (setpriority(PRIO_PROCESS, 0, limit) < 0)
return -errno;
log_debug("Cannot set requested nice level (%i), used next best (%i).", priority, limit);
return 0;
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",

View File

@ -200,3 +200,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
})
int pidfd_get_pid(int fd, pid_t *ret);
int setpriority_closest(int priority);

View File

@ -38,7 +38,13 @@ static int bpf_access_type(const char *acc) {
return r;
}
static int bpf_prog_whitelist_device(BPFProgram *prog, char type, int major, int minor, const char *acc) {
static int bpf_prog_whitelist_device(
BPFProgram *prog,
char type,
int major,
int minor,
const char *acc) {
int r, access;
assert(prog);
@ -74,7 +80,12 @@ static int bpf_prog_whitelist_device(BPFProgram *prog, char type, int major, int
return r;
}
static int bpf_prog_whitelist_major(BPFProgram *prog, char type, int major, const char *acc) {
static int bpf_prog_whitelist_major(
BPFProgram *prog,
char type,
int major,
const char *acc) {
int r, access;
assert(prog);
@ -109,7 +120,11 @@ static int bpf_prog_whitelist_major(BPFProgram *prog, char type, int major, cons
return r;
}
static int bpf_prog_whitelist_class(BPFProgram *prog, char type, const char *acc) {
static int bpf_prog_whitelist_class(
BPFProgram *prog,
char type,
const char *acc) {
int r, access;
assert(prog);
@ -143,7 +158,11 @@ static int bpf_prog_whitelist_class(BPFProgram *prog, char type, const char *acc
return r;
}
int bpf_devices_cgroup_init(BPFProgram **ret, CGroupDevicePolicy policy, bool whitelist) {
int bpf_devices_cgroup_init(
BPFProgram **ret,
CGroupDevicePolicy policy,
bool whitelist) {
const struct bpf_insn pre_insn[] = {
/* load device type to r2 */
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
@ -306,7 +325,14 @@ int bpf_devices_supported(void) {
return supported = 1;
}
static int whitelist_device_pattern(BPFProgram *prog, const char *path, char type, const unsigned *maj, const unsigned *min, const char *acc) {
static int whitelist_device_pattern(
BPFProgram *prog,
const char *path,
char type,
const unsigned *maj,
const unsigned *min,
const char *acc) {
assert(IN_SET(type, 'b', 'c'));
if (cg_all_unified() > 0) {
@ -343,7 +369,12 @@ static int whitelist_device_pattern(BPFProgram *prog, const char *path, char typ
}
}
int bpf_devices_whitelist_device(BPFProgram *prog, const char *path, const char *node, const char *acc) {
int bpf_devices_whitelist_device(
BPFProgram *prog,
const char *path,
const char *node,
const char *acc) {
mode_t mode;
dev_t rdev;
int r;
@ -377,7 +408,13 @@ int bpf_devices_whitelist_device(BPFProgram *prog, const char *path, const char
return whitelist_device_pattern(prog, path, S_ISCHR(mode) ? 'c' : 'b', &maj, &min, acc);
}
int bpf_devices_whitelist_major(BPFProgram *prog, const char *path, const char *name, char type, const char *acc) {
int bpf_devices_whitelist_major(
BPFProgram *prog,
const char *path,
const char *name,
char type,
const char *acc) {
unsigned maj;
int r;
@ -459,7 +496,10 @@ int bpf_devices_whitelist_major(BPFProgram *prog, const char *path, const char *
return 0;
}
int bpf_devices_whitelist_static(BPFProgram *prog, const char *path) {
int bpf_devices_whitelist_static(
BPFProgram *prog,
const char *path) {
static const char auto_devices[] =
"/dev/null\0" "rwm\0"
"/dev/zero\0" "rwm\0"

View File

@ -3236,11 +3236,11 @@ static int exec_child(
}
}
if (context->nice_set)
if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
*exit_status = EXIT_NICE;
return log_unit_error_errno(unit, errno, "Failed to set up process scheduling priority (nice level): %m");
}
if (context->nice_set) {
r = setpriority_closest(context->nice);
if (r < 0)
return log_unit_error_errno(unit, r, "Failed to set up process scheduling priority (nice level): %m");
}
if (context->cpu_sched_set) {
struct sched_param param = {

View File

@ -4324,6 +4324,11 @@ int unit_patch_contexts(Unit *u) {
r = cgroup_add_device_allow(cc, "block-blkext", "rwm");
if (r < 0)
return r;
/* Make sure "block-loop" can be resolved, i.e. make sure "loop" shows up in /proc/devices */
r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, "modprobe@loop.service", true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
}

View File

@ -167,6 +167,7 @@ static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
bool net_match_config(Set *match_mac,
Set *match_permanent_mac,
char * const *match_paths,
char * const *match_drivers,
char * const *match_types,
@ -177,6 +178,7 @@ bool net_match_config(Set *match_mac,
Set *match_bssid,
sd_device *device,
const struct ether_addr *dev_mac,
const struct ether_addr *dev_permanent_mac,
const char *dev_name,
char * const *alternative_names,
enum nl80211_iftype wifi_iftype,
@ -200,6 +202,12 @@ bool net_match_config(Set *match_mac,
if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
return false;
if (match_permanent_mac &&
(!dev_permanent_mac ||
ether_addr_is_null(dev_permanent_mac) ||
!set_contains(match_permanent_mac, dev_permanent_mac)))
return false;
if (!net_condition_test_strv(match_paths, dev_path))
return false;

View File

@ -16,6 +16,7 @@
#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
bool net_match_config(Set *match_mac,
Set *match_permanent_mac,
char * const *match_path,
char * const *match_driver,
char * const *match_type,
@ -26,6 +27,7 @@ bool net_match_config(Set *match_mac,
Set *match_bssid,
sd_device *device,
const struct ether_addr *dev_mac,
const struct ether_addr *dev_permanent_mac,
const char *dev_name,
char * const *alternative_names,
enum nl80211_iftype wifi_iftype,

View File

@ -25,7 +25,7 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlin
if (v->ifname_peer) {
r = sd_netlink_message_append_string(m, IFLA_IFNAME, v->ifname_peer);
if (r < 0)
return log_error_errno(r, "Failed to add netlink interface name: %m");
return log_netdev_error_errno(netdev, r, "Failed to add netlink interface name: %m");
}
if (v->mac_peer) {
@ -53,16 +53,17 @@ static int netdev_veth_verify(NetDev *netdev, const char *filename) {
assert(v);
if (!v->ifname_peer) {
log_warning("Veth NetDev without peer name configured in %s. Ignoring",
filename);
log_netdev_warning(netdev, "Veth NetDev without peer name configured in %s. Ignoring",
filename);
return -EINVAL;
}
if (!v->mac_peer) {
r = netdev_get_mac(v->ifname_peer, &v->mac_peer);
if (r < 0) {
log_warning("Failed to generate predictable MAC address for %s. Ignoring",
v->ifname_peer);
log_netdev_warning(netdev,
"Failed to generate predictable MAC address for %s. Ignoring",
v->ifname_peer);
return -EINVAL;
}
}

View File

@ -62,7 +62,7 @@ static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
assert(v);
if (v->id == VLANID_INVALID) {
log_warning("VLAN without valid Id (%"PRIu16") configured in %s.", v->id, filename);
log_netdev_warning(netdev, "VLAN without valid Id (%"PRIu16") configured in %s.", v->id, filename);
return -EINVAL;
}

View File

@ -23,7 +23,7 @@ static int netdev_vxcan_fill_message_create(NetDev *netdev, Link *link, sd_netli
if (v->ifname_peer) {
r = sd_netlink_message_append_string(m, IFLA_IFNAME, v->ifname_peer);
if (r < 0)
return log_error_errno(r, "Failed to add vxcan netlink interface peer name: %m");
return log_netdev_error_errno(netdev, r, "Failed to add vxcan netlink interface peer name: %m");
}
r = sd_netlink_message_close_container(m);
@ -44,7 +44,7 @@ static int netdev_vxcan_verify(NetDev *netdev, const char *filename) {
assert(v);
if (!v->ifname_peer) {
log_warning("VxCan NetDev without peer name configured in %s. Ignoring", filename);
log_netdev_warning(netdev, "VxCan NetDev without peer name configured in %s. Ignoring", filename);
return -EINVAL;
}

View File

@ -30,6 +30,7 @@
#include "hwdb-util.h"
#include "local-addresses.h"
#include "locale-util.h"
#include "logs-show.h"
#include "macro.h"
#include "main-func.h"
#include "netlink-util.h"
@ -46,6 +47,7 @@
#include "strv.h"
#include "strxcpyx.h"
#include "terminal-util.h"
#include "unit-def.h"
#include "verbs.h"
#include "wifi-util.h"
@ -59,6 +61,8 @@ static PagerFlags arg_pager_flags = 0;
static bool arg_legend = true;
static bool arg_all = false;
static bool arg_stats = false;
static bool arg_full = false;
static unsigned arg_lines = 10;
static char *link_get_type_string(unsigned short iftype, sd_device *d) {
const char *t, *devtype;
@ -134,6 +138,7 @@ typedef struct LinkInfo {
int ifindex;
unsigned short iftype;
struct ether_addr mac_address;
struct ether_addr permanent_mac_address;
uint32_t mtu;
uint32_t min_mtu;
uint32_t max_mtu;
@ -173,6 +178,7 @@ typedef struct LinkInfo {
struct ether_addr bssid;
bool has_mac_address:1;
bool has_permanent_mac_address:1;
bool has_tx_queues:1;
bool has_rx_queues:1;
bool has_stats64:1;
@ -318,6 +324,12 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
memcmp(&info->mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0;
_cleanup_close_ int fd = -1;
info->has_permanent_mac_address =
ethtool_get_permanent_macaddr(&fd, info->name, &info->permanent_mac_address) >= 0 &&
memcmp(&info->permanent_mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0 &&
memcmp(&info->permanent_mac_address, &info->mac_address, sizeof(struct ether_addr)) != 0;
(void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu);
(void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu);
(void) sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu);
@ -1067,6 +1079,69 @@ static int dump_statistics(Table *table, const LinkInfo *info) {
return 0;
}
static OutputFlags get_output_flags(void) {
return
arg_all * OUTPUT_SHOW_ALL |
(arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
colors_enabled() * OUTPUT_COLOR;
}
static int show_logs(const LinkInfo *info) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
int r;
if (arg_lines == 0)
return 0;
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
if (r < 0)
return log_error_errno(r, "Failed to open journal: %m");
r = add_match_this_boot(j, NULL);
if (r < 0)
return log_error_errno(r, "Failed to add boot matches: %m");
if (info) {
char m1[STRLEN("_KERNEL_DEVICE=n") + DECIMAL_STR_MAX(int)];
const char *m2, *m3;
/* kernel */
xsprintf(m1, "_KERNEL_DEVICE=n%i", info->ifindex);
/* networkd */
m2 = strjoina("INTERFACE=", info->name);
/* udevd */
m3 = strjoina("DEVICE=", info->name);
(void)(
(r = sd_journal_add_match(j, m1, 0)) ||
(r = sd_journal_add_disjunction(j)) ||
(r = sd_journal_add_match(j, m2, 0)) ||
(r = sd_journal_add_disjunction(j)) ||
(r = sd_journal_add_match(j, m3, 0))
);
if (r < 0)
return log_error_errno(r, "Failed to add link matches: %m");
} else {
r = add_matches_for_unit(j, "systemd-networkd.service");
if (r < 0)
return log_error_errno(r, "Failed to add unit matches: %m");
r = add_matches_for_unit(j, "systemd-networkd-wait-online.service");
if (r < 0)
return log_error_errno(r, "Failed to add unit matches: %m");
}
return show_journal(
stdout,
j,
OUTPUT_SHORT,
0,
0,
arg_lines,
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
NULL);
}
static int link_status_one(
sd_netlink *rtnl,
sd_hwdb *hwdb,
@ -1228,6 +1303,26 @@ static int link_status_one(
return r;
}
if (info->has_permanent_mac_address) {
_cleanup_free_ char *description = NULL;
char ea[ETHER_ADDR_TO_STRING_MAX];
(void) ieee_oui(hwdb, &info->permanent_mac_address, &description);
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "HW Permanent Address:");
if (r < 0)
return r;
r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
ether_addr_to_string(&info->permanent_mac_address, ea),
description ? " (" : "",
strempty(description),
description ? ")" : "");
if (r < 0)
return r;
}
if (info->mtu > 0) {
char min_str[DECIMAL_STR_MAX(uint32_t)], max_str[DECIMAL_STR_MAX(uint32_t)];
@ -1457,7 +1552,11 @@ static int link_status_one(
if (r < 0)
return r;
return table_print(table, NULL);
r = table_print(table, NULL);
if (r < 0)
return r;
return show_logs(info);
}
static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
@ -1520,7 +1619,11 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
if (r < 0)
return r;
return table_print(table, NULL);
r = table_print(table, NULL);
if (r < 0)
return r;
return show_logs(NULL);
}
static int link_status(int argc, char *argv[], void *userdata) {
@ -1946,6 +2049,8 @@ static int help(void) {
" --no-legend Do not show the headers and footers\n"
" -a --all Show status for all links\n"
" -s --stats Show detailed link statics\n"
" -l --full Do not ellipsize output\n"
" -n --lines=INTEGER Number of journal entries to show\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
, ansi_highlight()
@ -1971,6 +2076,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "all", no_argument, NULL, 'a' },
{ "stats", no_argument, NULL, 's' },
{ "full", no_argument, NULL, 'l' },
{ "lines", required_argument, NULL, 'n' },
{}
};
@ -1979,7 +2086,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "has", options, NULL)) >= 0) {
while ((c = getopt_long(argc, argv, "hasln:", options, NULL)) >= 0) {
switch (c) {
@ -2005,6 +2112,16 @@ static int parse_argv(int argc, char *argv[]) {
arg_stats = true;
break;
case 'l':
arg_full = true;
break;
case 'n':
if (safe_atou(optarg, &arg_lines) < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse lines '%s'", optarg);
break;
case '?':
return -EINVAL;

View File

@ -125,25 +125,25 @@ int address_label_configure(
r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
link->ifindex, AF_INET6);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m");
r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen);
if (r < 0)
return log_error_errno(r, "Could not set prefixlen: %m");
return log_link_error_errno(link, r, "Could not set prefixlen: %m");
r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label);
if (r < 0)
return log_error_errno(r, "Could not append IFAL_LABEL attribute: %m");
return log_link_error_errno(link, r, "Could not append IFAL_LABEL attribute: %m");
r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr.in6);
if (r < 0)
return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req,
callback ?: address_label_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);

View File

@ -668,7 +668,7 @@ int address_configure(
_cleanup_free_ char *pretty = NULL;
(void) in_addr_to_string(address->family, &address->in_addr, &pretty);
log_debug("Starting IPv4ACD client. Probing address %s", strna(pretty));
log_link_debug(link, "Starting IPv4ACD client. Probing address %s", strna(pretty));
}
r = sd_ipv4acd_start(address->acd, true);

View File

@ -45,7 +45,7 @@ static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
size_t n_addresses = 0, n_allocated = 0;
unsigned i;
log_debug("Copying DNS server information from %s", link->ifname);
log_link_debug(link, "Copying DNS server information from %s", link->ifname);
if (!link->network)
return 0;
@ -99,7 +99,7 @@ static int link_push_uplink_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
if (!link->network)
return 0;
log_debug("Copying NTP server information from %s", link->ifname);
log_link_debug(link, "Copying NTP server information from %s", link->ifname);
STRV_FOREACH(a, link->network->ntp) {
union in_addr_union ia;
@ -148,7 +148,7 @@ static int link_push_uplink_sip_to_dhcp_server(Link *link, sd_dhcp_server *s) {
if (!link->network)
return 0;
log_debug("Copying SIP server information from %s", link->ifname);
log_link_debug(link, "Copying SIP server information from %s", link->ifname);
STRV_FOREACH(a, link->network->sip) {
union in_addr_union ia;
@ -294,7 +294,7 @@ int dhcp4_server_configure(Link *link) {
else {
r = get_timezone(&buffer);
if (r < 0)
return log_error_errno(r, "Failed to determine timezone: %m");
return log_link_error_errno(link, r, "Failed to determine timezone: %m");
tz = buffer;
}

View File

@ -814,7 +814,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
_cleanup_free_ char *pretty = NULL;
(void) in_addr_to_string(AF_INET, &addr, &pretty);
log_debug("Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
}
r = sd_ipv4acd_start(link->network->dhcp_acd, true);

View File

@ -126,26 +126,26 @@ int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
/* create new RTM message */
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, PF_BRIDGE);
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_flags(req, fdb_entry->fdb_ntf_flags);
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not set neighbor flags: %m");
/* only NUD_PERMANENT state supported. */
r = sd_rtnl_message_neigh_set_state(req, NUD_NOARP | NUD_PERMANENT);
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not set neighbor state: %m");
r = sd_netlink_message_append_data(req, NDA_LLADDR, &fdb_entry->mac_addr, sizeof(fdb_entry->mac_addr));
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not append NDA_LLADDR attribute: %m");
/* VLAN Id is optional. We'll add VLAN Id only if it's specified. */
if (fdb_entry->vlan_id > 0) {
r = sd_netlink_message_append_u16(req, NDA_VLAN, fdb_entry->vlan_id);
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not append NDA_VLAN attribute: %m");
}
if (!in_addr_is_null(fdb_entry->family, &fdb_entry->destination_addr)) {

View File

@ -162,15 +162,15 @@ int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy
/* create new netlink message */
r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY);
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not set neighbor flags: %m");
r = sd_netlink_message_append_in6_addr(req, NDA_DST, &ipv6_proxy_ndp_address->in_addr);
if (r < 0)
return rtnl_log_create_error(r);
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
r = netlink_call_async(rtnl, NULL, req, set_ipv6_proxy_ndp_address_handler,
link_netlink_destroy_callback, link);

View File

@ -12,6 +12,7 @@
#include "dhcp-identifier.h"
#include "dhcp-lease-internal.h"
#include "env-file.h"
#include "ethtool-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "ipvlan.h"
@ -617,6 +618,11 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
if (r < 0)
log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
_cleanup_close_ int fd = -1;
r = ethtool_get_permanent_macaddr(&fd, link->ifname, &link->permanent_mac);
if (r < 0)
log_link_debug_errno(link, r, "Permanent MAC address not found for new device, continuing without: %m");
r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &link->alternative_names);
if (r < 0 && r != -ENODATA)
return r;
@ -2963,7 +2969,7 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
}
r = network_get(link->manager, link->sd_device, link->ifname, link->alternative_names,
&link->mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
&link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;
@ -3095,7 +3101,7 @@ static int link_initialized_and_synced(Link *link) {
return r;
r = network_get(link->manager, link->sd_device, link->ifname, link->alternative_names,
&link->mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
&link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;

View File

@ -53,6 +53,7 @@ typedef struct Link {
unsigned short iftype;
char *state_file;
struct ether_addr mac;
struct ether_addr permanent_mac;
struct in6_addr ipv6ll_address;
uint32_t mtu;
sd_device *sd_device;

View File

@ -126,28 +126,28 @@ int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_hand
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH,
link->ifindex, neighbor->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_NEWNEIGH message: %m");
return log_link_error_errno(link, r, "Could not allocate RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_state(req, NUD_PERMANENT);
if (r < 0)
return log_error_errno(r, "Could not set state: %m");
return log_link_error_errno(link, r, "Could not set state: %m");
r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE);
if (r < 0)
return log_error_errno(r, "Could not set flags: %m");
return log_link_error_errno(link, r, "Could not set flags: %m");
r = sd_netlink_message_append_data(req, NDA_LLADDR, &neighbor->lladdr, neighbor->lladdr_size);
if (r < 0)
return log_error_errno(r, "Could not append NDA_LLADDR attribute: %m");
return log_link_error_errno(link, r, "Could not append NDA_LLADDR attribute: %m");
r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
if (r < 0)
return log_error_errno(r, "Could not append NDA_DST attribute: %m");
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_configure_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link->neighbor_messages++;
link_ref(link);
@ -189,16 +189,16 @@ int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_DELNEIGH,
link->ifindex, neighbor->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_DELNEIGH message: %m");
return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
if (r < 0)
return log_error_errno(r, "Could not append NDA_DST attribute: %m");
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_remove_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);

View File

@ -28,6 +28,7 @@ struct ConfigPerfItem;
%includes
%%
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_mac)
Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_permanent_mac)
Match.Path, config_parse_match_strv, 0, offsetof(Network, match_path)
Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver)
Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type)

View File

@ -160,10 +160,10 @@ int network_verify(Network *network) {
assert(network);
assert(network->filename);
if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
strv_isempty(network->match_ssid) && !network->conditions)
if (set_isempty(network->match_mac) && set_isempty(network->match_permanent_mac) &&
strv_isempty(network->match_path) && strv_isempty(network->match_driver) &&
strv_isempty(network->match_type) && strv_isempty(network->match_name) &&
strv_isempty(network->match_property) && strv_isempty(network->match_ssid) && !network->conditions)
log_warning("%s: No valid settings found in the [Match] section. "
"The file will match all interfaces. "
"If that is intended, please add Name=* in the [Match] section.",
@ -601,6 +601,7 @@ static Network *network_free(Network *network) {
free(network->filename);
set_free_free(network->match_mac);
set_free_free(network->match_permanent_mac);
strv_free(network->match_path);
strv_free(network->match_driver);
strv_free(network->match_type);
@ -721,7 +722,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
}
int network_get(Manager *manager, sd_device *device,
const char *ifname, char * const *alternative_names, const struct ether_addr *address,
const char *ifname, char * const *alternative_names,
const struct ether_addr *address, const struct ether_addr *permanent_address,
enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
Network **ret) {
Network *network;
@ -731,10 +733,12 @@ int network_get(Manager *manager, sd_device *device,
assert(ret);
ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
if (net_match_config(network->match_mac, network->match_path, network->match_driver,
if (net_match_config(network->match_mac, network->match_permanent_mac,
network->match_path, network->match_driver,
network->match_type, network->match_name, network->match_property,
network->match_wlan_iftype, network->match_ssid, network->match_bssid,
device, address, ifname, alternative_names, wlan_iftype, ssid, bssid)) {
device, address, permanent_address,
ifname, alternative_names, wlan_iftype, ssid, bssid)) {
if (network->match_name && device) {
const char *attr;
uint8_t name_assign_type = NET_NAME_UNKNOWN;

View File

@ -64,6 +64,7 @@ struct Network {
unsigned n_ref;
Set *match_mac;
Set *match_permanent_mac;
char **match_path;
char **match_driver;
char **match_type;
@ -302,7 +303,8 @@ int network_verify(Network *network);
int network_get_by_name(Manager *manager, const char *name, Network **ret);
int network_get(Manager *manager, sd_device *device, const char *ifname, char * const *alternative_names,
const struct ether_addr *mac, enum nl80211_iftype wlan_iftype, const char *ssid,
const struct ether_addr *mac, const struct ether_addr *permanent_mac,
enum nl80211_iftype wlan_iftype, const char *ssid,
const struct ether_addr *bssid, Network **ret);
int network_apply(Network *network, Link *link);
void network_apply_anonymize_if_set(Network *network);

View File

@ -511,7 +511,7 @@ int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
r = route_remove(route, route->link, NULL);
if (r < 0)
log_warning_errno(r, "Could not remove route: %m");
log_link_warning_errno(route->link, r, "Could not remove route: %m");
else
route_free(route);

View File

@ -335,33 +335,33 @@ int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *lin
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
return log_link_error_errno(link, r, "Could not allocate RTM_DELRULE message: %m");
if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
if (r < 0)
return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
if (r < 0)
return log_error_errno(r, "Could not set source prefix length: %m");
return log_link_error_errno(link, r, "Could not set source prefix length: %m");
}
if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
if (r < 0)
return log_error_errno(r, "Could not append FRA_DST attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
if (r < 0)
return log_error_errno(r, "Could not set destination prefix length: %m");
return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
}
r = netlink_call_async(link->manager->rtnl, NULL, m,
callback ?: routing_policy_rule_remove_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
@ -461,102 +461,103 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
(void) in_addr_to_string(rule->family, &rule->from, &from);
(void) in_addr_to_string(rule->family, &rule->to, &to);
log_debug("Configuring routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
from, rule->from_prefixlen, to, rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
log_link_debug(link,
"Configuring routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
from, rule->from_prefixlen, to, rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
}
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
return log_link_error_errno(link, r, "Could not allocate RTM_NEWRULE message: %m");
if (in_addr_is_null(rule->family, &rule->from) == 0) {
r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
if (r < 0)
return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
if (r < 0)
return log_error_errno(r, "Could not set source prefix length: %m");
return log_link_error_errno(link, r, "Could not set source prefix length: %m");
}
if (in_addr_is_null(rule->family, &rule->to) == 0) {
r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
if (r < 0)
return log_error_errno(r, "Could not append FRA_DST attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
if (r < 0)
return log_error_errno(r, "Could not set destination prefix length: %m");
return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
}
r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
if (r < 0)
return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
if (rule->tos > 0) {
r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
if (r < 0)
return log_error_errno(r, "Could not set ip rule tos: %m");
return log_link_error_errno(link, r, "Could not set ip rule tos: %m");
}
if (rule->table < 256) {
r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
if (r < 0)
return log_error_errno(r, "Could not set ip rule table: %m");
return log_link_error_errno(link, r, "Could not set ip rule table: %m");
} else {
r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
if (r < 0)
return log_error_errno(r, "Could not set ip rule table: %m");
return log_link_error_errno(link, r, "Could not set ip rule table: %m");
r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
if (r < 0)
return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_TABLE attribute: %m");
}
if (rule->fwmark > 0) {
r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
if (r < 0)
return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m");
}
if (rule->fwmask > 0) {
r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
if (r < 0)
return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
}
if (rule->iif) {
r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
if (r < 0)
return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_IFNAME attribute: %m");
}
if (rule->oif) {
r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
if (r < 0)
return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m");
}
r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
if (r < 0)
return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m");
if (rule->sport.start != 0 || rule->sport.end != 0) {
r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
if (r < 0)
return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_SPORT_RANGE attribute: %m");
}
if (rule->dport.start != 0 || rule->dport.end != 0) {
r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
if (r < 0)
return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
return log_link_error_errno(link, r, "Could not append FRA_DPORT_RANGE attribute: %m");
}
if (rule->invert_rule) {
r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
if (r < 0)
return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
return log_link_error_errno(link, r, "Could not append FIB_RULE_INVERT attribute: %m");
}
rule->link = link;
@ -565,13 +566,13 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
callback ?: routing_policy_rule_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
r = routing_policy_rule_add(link->manager, rule, NULL);
if (r < 0)
return log_error_errno(r, "Could not add rule: %m");
return log_link_error_errno(link, r, "Could not add rule: %m");
return 1;
}

View File

@ -125,7 +125,7 @@ static void test_network_get(Manager *manager, sd_device *loopback) {
/* let's assume that the test machine does not have a .network file
that applies to the loopback device... */
assert_se(network_get(manager, loopback, "lo", NULL, &mac, 0, NULL, NULL, &network) == -ENOENT);
assert_se(network_get(manager, loopback, "lo", NULL, &mac, &mac, 0, NULL, NULL, &network) == -ENOENT);
assert_se(!network);
}

View File

@ -3,6 +3,7 @@
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/sockios.h>
#include "conf-parser.h"
@ -217,6 +218,46 @@ int ethtool_get_link_info(int *fd, const char *ifname,
return 0;
}
int ethtool_get_permanent_macaddr(int *fd, const char *ifname, struct ether_addr *ret) {
_cleanup_free_ struct ethtool_perm_addr *epaddr = NULL;
struct ifreq ifr;
int r;
assert(fd);
assert(ifname);
assert(ret);
if (*fd < 0) {
r = ethtool_connect_or_warn(fd, false);
if (r < 0)
return r;
}
epaddr = malloc(offsetof(struct ethtool_perm_addr, data) + MAX_ADDR_LEN);
if (!epaddr)
return -ENOMEM;
epaddr->cmd = ETHTOOL_GPERMADDR;
epaddr->size = MAX_ADDR_LEN;
ifr = (struct ifreq) {
.ifr_data = (caddr_t) epaddr,
};
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
r = ioctl(*fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
if (epaddr->size != 6)
return -EOPNOTSUPP;
for (size_t i = 0; i < epaddr->size; i++)
ret->ether_addr_octet[i] = epaddr->data[i];
return 0;
}
int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex) {
struct ethtool_cmd ecmd = {
.cmd = ETHTOOL_GSET

View File

@ -2,6 +2,7 @@
#pragma once
#include <macro.h>
#include <net/ethernet.h>
#include <linux/ethtool.h>
#include "conf-parser.h"
@ -91,6 +92,7 @@ int ethtool_get_driver(int *fd, const char *ifname, char **ret);
int ethtool_get_link_info(int *fd, const char *ifname,
int *ret_autonegotiation, size_t *ret_speed,
Duplex *ret_duplex, NetDevPort *ret_port);
int ethtool_get_permanent_macaddr(int *fd, const char *ifname, struct ether_addr *ret);
int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex);
int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
int ethtool_set_nic_buffer_size(int *fd, const char *ifname, netdev_ring_param *ring);

View File

@ -15,6 +15,7 @@
#include <unistd.h>
#include "alloc-util.h"
#include "blockdev-util.h"
#include "btrfs-util.h"
#include "conf-parser.h"
#include "def.h"
@ -180,39 +181,36 @@ HibernateLocation* hibernate_location_free(HibernateLocation *hl) {
return NULL;
swap_entry_free(hl->swap);
free(hl->resume);
return mfree(hl);
}
static int swap_device_to_major_minor(const SwapEntry *swap, char **ret) {
_cleanup_free_ char *major_minor = NULL;
_cleanup_close_ int fd = -1;
static int swap_device_to_device_id(const SwapEntry *swap, dev_t *ret_dev) {
struct stat sb;
dev_t swap_dev;
int r;
assert(swap);
assert(swap->device);
assert(swap->type);
fd = open(swap->device, O_RDONLY | O_CLOEXEC | O_NONBLOCK);
if (fd < 0)
return log_debug_errno(errno, "Unable to open '%s': %m", swap->device);
r = fstat(fd, &sb);
r = stat(swap->device, &sb);
if (r < 0)
return log_debug_errno(errno, "Unable to stat %s: %m", swap->device);
return r;
swap_dev = streq(swap->type, "partition") ? sb.st_rdev : sb.st_dev;
if (asprintf(&major_minor, "%u:%u", major(swap_dev), minor(swap_dev)) < 0)
return log_oom();
if (streq(swap->type, "partition")) {
if (!S_ISBLK(sb.st_mode))
return -ENOTBLK;
*ret_dev = sb.st_rdev;
return 0;
*ret = TAKE_PTR(major_minor);
return 0;
} else
return get_block_device(swap->device, ret_dev);
}
/*
* Attempt to calculate the swap file offset on supported filesystems. On unsuported
* filesystems, a debug message is logged and ret_offset is set to UINT64_MAX.
*/
static int calculate_swap_file_offset(const SwapEntry *swap, uint64_t *ret_offset) {
_cleanup_close_ int fd = -1;
_cleanup_free_ struct fiemap *fiemap = NULL;
@ -234,8 +232,8 @@ static int calculate_swap_file_offset(const SwapEntry *swap, uint64_t *ret_offse
if (btrfs < 0)
return log_error_errno(btrfs, "Error checking %s for Btrfs filesystem: %m", swap->device);
else if (btrfs > 0) {
log_debug("Detection of swap file offset on Btrfs is not supported: %s; skipping", swap->device);
*ret_offset = 0;
log_debug("%s: detection of swap file offset on Btrfs is not supported", swap->device);
*ret_offset = UINT64_MAX;
return 0;
}
@ -248,15 +246,20 @@ static int calculate_swap_file_offset(const SwapEntry *swap, uint64_t *ret_offse
return 0;
}
static int read_resume_files(char **ret_resume, uint64_t *ret_resume_offset) {
_cleanup_free_ char *resume = NULL, *resume_offset_str = NULL;
static int read_resume_files(dev_t *ret_resume, uint64_t *ret_resume_offset) {
_cleanup_free_ char *resume_str = NULL, *resume_offset_str = NULL;
dev_t resume;
uint64_t resume_offset = 0;
int r;
r = read_one_line_file("/sys/power/resume", &resume);
r = read_one_line_file("/sys/power/resume", &resume_str);
if (r < 0)
return log_debug_errno(r, "Error reading /sys/power/resume: %m");
r = parse_dev(resume_str, &resume);
if (r < 0)
return log_debug_errno(r, "Error parsing /sys/power/resume device: %s: %m", resume_str);
r = read_one_line_file("/sys/power/resume_offset", &resume_offset_str);
if (r == -ENOENT)
log_debug("Kernel does not support resume_offset; swap file offset detection will be skipped.");
@ -268,24 +271,26 @@ static int read_resume_files(char **ret_resume, uint64_t *ret_resume_offset) {
return log_error_errno(r, "Failed to parse value in /sys/power/resume_offset \"%s\": %m", resume_offset_str);
}
if (resume_offset > 0 && streq(resume, "0:0")) {
log_debug("Found offset in /sys/power/resume_offset: %" PRIu64 "; no device id found in /sys/power/resume; ignoring resume_offset",
if (resume_offset > 0 && resume == 0)
log_debug("Warning: found /sys/power/resume_offset==%" PRIu64 ", but /sys/power/resume unset. Misconfiguration?",
resume_offset);
resume_offset = 0;
}
*ret_resume = TAKE_PTR(resume);
*ret_resume = resume;
*ret_resume_offset = resume_offset;
return 0;
}
static bool location_is_resume_device(const HibernateLocation *location, const char *sys_resume, const uint64_t sys_offset) {
assert(location);
assert(location->resume);
assert(sys_resume);
/*
* Determine if the HibernateLocation matches the resume= (device) and resume_offset= (file).
*/
static bool location_is_resume_device(const HibernateLocation *location, dev_t sys_resume, uint64_t sys_offset) {
if (!location)
return false;
return streq(sys_resume, location->resume) && sys_offset == location->resume_offset;
return sys_resume > 0 &&
sys_resume == location->devno &&
(sys_offset == location->offset || (sys_offset > 0 && location->offset == UINT64_MAX));
}
/*
@ -293,16 +298,20 @@ static bool location_is_resume_device(const HibernateLocation *location, const c
* /sys/power/resume_offset.
*
* Returns:
* 1 - HibernateLocation matches values found in /sys/power/resume & /sys/power/resume_offset
* 0 - HibernateLocation is highest priority swap with most remaining space; no valid values exist in /sys/power/resume & /sys/power/resume_offset
* negative value in the case of error
* 1 - Values are set in /sys/power/resume and /sys/power/resume_offset.
* ret_hibernate_location will represent matching /proc/swap entry if identified or NULL if not.
*
* 0 - No values are set in /sys/power/resume and /sys/power/resume_offset.
ret_hibernate_location will represent the highest priority swap with most remaining space discovered in /proc/swaps.
*
* Negative value in the case of error.
*/
int find_hibernate_location(HibernateLocation **ret_hibernate_location) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(hibernate_location_freep) HibernateLocation *hibernate_location = NULL;
_cleanup_free_ char *sys_resume = NULL;
dev_t sys_resume;
uint64_t sys_offset = 0;
unsigned i;
bool resume_match = false;
int r;
/* read the /sys/power/resume & /sys/power/resume_offset values */
@ -318,7 +327,7 @@ int find_hibernate_location(HibernateLocation **ret_hibernate_location) {
}
(void) fscanf(f, "%*s %*s %*s %*s %*s\n");
for (i = 1;; i++) {
for (unsigned i = 1;; i++) {
_cleanup_(swap_entry_freep) SwapEntry *swap = NULL;
uint64_t swap_offset = 0;
int k;
@ -350,59 +359,88 @@ int find_hibernate_location(HibernateLocation **ret_hibernate_location) {
r = calculate_swap_file_offset(swap, &swap_offset);
if (r < 0)
return r;
} else if (streq(swap->type, "partition")) {
const char *fn;
fn = path_startswith(swap->device, "/dev/");
if (fn && startswith(fn, "zram")) {
log_debug("Ignoring compressed RAM swap device '%s'.", swap->device);
log_debug("%s: ignoring zram swap", swap->device);
continue;
}
} else {
log_debug("Swap type %s is unsupported for hibernation: %s; skipping", swap->type, swap->device);
log_debug("%s: swap type %s is unsupported for hibernation, ignoring", swap->device, swap->type);
continue;
}
/* prefer resume device or highest priority swap with most remaining space */
if (!hibernate_location || swap->priority > hibernate_location->swap->priority
|| ((swap->priority == hibernate_location->swap->priority)
&& (swap->size - swap->used) > (hibernate_location->swap->size - hibernate_location->swap->used))) {
_cleanup_free_ char *swap_device_id = NULL;
r = swap_device_to_major_minor(swap, &swap_device_id);
if (r < 0)
return r;
hibernate_location = hibernate_location_free(hibernate_location);
hibernate_location = new(HibernateLocation, 1);
if (!hibernate_location)
return log_oom();
*hibernate_location = (HibernateLocation) {
.resume = TAKE_PTR(swap_device_id),
.resume_offset = swap_offset,
.swap = TAKE_PTR(swap),
};
/* if the swap is the resume device, stop looping swaps */
if (location_is_resume_device(hibernate_location, sys_resume, sys_offset))
break;
if (hibernate_location && swap->priority < hibernate_location->swap->priority) {
log_debug("%s: ignoring device with lower priority", swap->device);
continue;
}
if (hibernate_location &&
(swap->priority == hibernate_location->swap->priority
&& swap->size - swap->used < hibernate_location->swap->size - hibernate_location->swap->used)) {
log_debug("%s: ignoring device with lower usable space", swap->device);
continue;
}
dev_t swap_device;
r = swap_device_to_device_id(swap, &swap_device);
if (r < 0)
return log_error_errno(r, "%s: failed to query device number: %m", swap->device);
hibernate_location = hibernate_location_free(hibernate_location);
hibernate_location = new(HibernateLocation, 1);
if (!hibernate_location)
return log_oom();
*hibernate_location = (HibernateLocation) {
.devno = swap_device,
.offset = swap_offset,
.swap = TAKE_PTR(swap),
};
/* if the swap is the resume device, stop the loop */
if (location_is_resume_device(hibernate_location, sys_resume, sys_offset)) {
log_debug("%s: device matches configured resume settings.", hibernate_location->swap->device);
resume_match = true;
break;
}
log_debug("%s: is a candidate device.", hibernate_location->swap->device);
}
/* We found nothing at all */
if (!hibernate_location)
return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS), "No swap partitions or files were found");
return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS),
"No possible swap partitions or files suitable for hibernation were found in /proc/swaps.");
if (!streq(sys_resume, "0:0") && !location_is_resume_device(hibernate_location, sys_resume, sys_offset))
return log_warning_errno(SYNTHETIC_ERRNO(ENOSYS), "/sys/power/resume and /sys/power/resume_offset has no matching entry in /proc/swaps; Hibernation will fail: resume=%s, resume_offset=%" PRIu64,
sys_resume, sys_offset);
/* resume= is set but a matching /proc/swaps entry was not found */
if (sys_resume != 0 && !resume_match)
return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS),
"No swap partitions or files matching resume config were found in /proc/swaps.");
log_debug("Hibernation will attempt to use swap entry with path: %s, device: %s, offset: %" PRIu64 ", priority: %i",
hibernate_location->swap->device, hibernate_location->resume, hibernate_location->resume_offset, hibernate_location->swap->priority);
if (hibernate_location->offset == UINT64_MAX) {
if (sys_offset == 0)
return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS), "Offset detection failed and /sys/power/resume_offset is not set.");
hibernate_location->offset = sys_offset;
}
if (resume_match)
log_debug("Hibernation will attempt to use swap entry with path: %s, device: %u:%u, offset: %" PRIu64 ", priority: %i",
hibernate_location->swap->device, major(hibernate_location->devno), minor(hibernate_location->devno),
hibernate_location->offset, hibernate_location->swap->priority);
else
log_debug("/sys/power/resume is not configured; attempting to hibernate with path: %s, device: %u:%u, offset: %" PRIu64 ", priority: %i",
hibernate_location->swap->device, major(hibernate_location->devno), minor(hibernate_location->devno),
hibernate_location->offset, hibernate_location->swap->priority);
*ret_hibernate_location = TAKE_PTR(hibernate_location);
if (location_is_resume_device(*ret_hibernate_location, sys_resume, sys_offset))
if (resume_match)
return 1;
return 0;
@ -421,6 +459,18 @@ static bool enough_swap_for_hibernation(void) {
if (r < 0)
return false;
/* If /sys/power/{resume,resume_offset} is configured but a matching entry
* could not be identified in /proc/swaps, user is likely using Btrfs with a swapfile;
* return true and let the system attempt hibernation.
*/
if (r > 0 && !hibernate_location) {
log_debug("Unable to determine remaining swap space; hibernation may fail");
return true;
}
if (!hibernate_location)
return false;
r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active);
if (r < 0) {
log_debug_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");

View File

@ -40,8 +40,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(SwapEntry*, swap_entry_free);
* and the matching /proc/swap entry.
*/
typedef struct HibernateLocation {
char *resume;
uint64_t resume_offset;
dev_t devno;
uint64_t offset;
SwapEntry *swap;
} HibernateLocation;

View File

@ -39,18 +39,19 @@ STATIC_DESTRUCTOR_REGISTER(arg_verb, freep);
static int write_hibernate_location_info(const HibernateLocation *hibernate_location) {
char offset_str[DECIMAL_STR_MAX(uint64_t)];
char resume_str[DECIMAL_STR_MAX(unsigned) * 2 + STRLEN(":")];
int r;
assert(hibernate_location);
assert(hibernate_location->swap);
assert(hibernate_location->resume);
r = write_string_file("/sys/power/resume", hibernate_location->resume, WRITE_STRING_FILE_DISABLE_BUFFER);
xsprintf(resume_str, "%u:%u", major(hibernate_location->devno), minor(hibernate_location->devno));
r = write_string_file("/sys/power/resume", resume_str, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write partition device to /sys/power/resume for '%s': '%s': %m",
hibernate_location->swap->device, hibernate_location->resume);
hibernate_location->swap->device, resume_str);
log_debug("Wrote resume= value for %s to /sys/power/resume: %s", hibernate_location->swap->device, hibernate_location->resume);
log_debug("Wrote resume= value for %s to /sys/power/resume: %s", hibernate_location->swap->device, resume_str);
/* if it's a swap partition, we're done */
if (streq(hibernate_location->swap->type, "partition"))
@ -61,17 +62,17 @@ static int write_hibernate_location_info(const HibernateLocation *hibernate_loca
"Invalid hibernate type: %s", hibernate_location->swap->type);
/* Only available in 4.17+ */
if (hibernate_location->resume_offset > 0 && access("/sys/power/resume_offset", W_OK) < 0) {
if (hibernate_location->offset > 0 && access("/sys/power/resume_offset", W_OK) < 0) {
if (errno == ENOENT) {
log_debug("Kernel too old, can't configure resume_offset for %s, ignoring: %" PRIu64,
hibernate_location->swap->device, hibernate_location->resume_offset);
hibernate_location->swap->device, hibernate_location->offset);
return 0;
}
return log_debug_errno(errno, "/sys/power/resume_offset not writeable: %m");
}
xsprintf(offset_str, "%" PRIu64, hibernate_location->resume_offset);
xsprintf(offset_str, "%" PRIu64, hibernate_location->offset);
r = write_string_file("/sys/power/resume_offset", offset_str, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write swap file offset to /sys/power/resume_offset for '%s': '%s': %m",

View File

@ -14,6 +14,7 @@
#include "alloc-util.h"
#include "architecture.h"
#include "errno-util.h"
#include "fd-util.h"
#include "log.h"
#include "macro.h"
@ -21,11 +22,13 @@
#include "missing_syscall.h"
#include "parse-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "signal-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "tests.h"
#include "user-util.h"
#include "util.h"
#include "virt.h"
@ -601,6 +604,92 @@ static void test_ioprio_class_from_to_string(void) {
test_ioprio_class_from_to_string_one("-1", -1);
}
static void test_setpriority_closest(void) {
int r;
r = safe_fork("(test-setprio)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT|FORK_LOG, NULL);
assert_se(r >= 0);
if (r == 0) {
bool full_test;
int p, q;
/* child */
/* rlimit of 30 equals nice level of -10 */
if (setrlimit(RLIMIT_NICE, &RLIMIT_MAKE_CONST(30)) < 0) {
/* If this fails we are probably unprivileged or in a userns of some kind, let's skip
* the full test */
assert_se(ERRNO_IS_PRIVILEGE(errno));
full_test = false;
} else {
assert_se(setresgid(GID_NOBODY, GID_NOBODY, GID_NOBODY) >= 0);
assert_se(setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) >= 0);
full_test = true;
}
errno = 0;
p = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0);
/* It should always be possible to set our nice level to the current one */
assert_se(setpriority_closest(p) > 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
/* It should also be possible to to set the nice level to one higher */
if (p < PRIO_MAX-1) {
assert_se(setpriority_closest(++p) > 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
}
/* It should also be possible to to set the nice level to two higher */
if (p < PRIO_MAX-1) {
assert_se(setpriority_closest(++p) > 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
}
if (full_test) {
/* These two should work, given the RLIMIT_NICE we set above */
assert_se(setpriority_closest(-10) > 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
assert_se(setpriority_closest(-9) > 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -9);
/* This should succeed but should be clamped to the limit */
assert_se(setpriority_closest(-11) == 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
assert_se(setpriority_closest(-8) > 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -8);
/* This should succeed but should be clamped to the limit */
assert_se(setpriority_closest(-12) == 0);
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
}
_exit(EXIT_SUCCESS);
}
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -627,6 +716,7 @@ int main(int argc, char *argv[]) {
test_safe_fork();
test_pid_to_ptr();
test_ioprio_class_from_to_string();
test_setpriority_closest();
return 0;
}

View File

@ -20,6 +20,7 @@ struct ConfigPerfItem;
%includes
%%
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac)
Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_permanent_mac)
Match.OriginalName, config_parse_match_ifnames, 0, offsetof(link_config, match_name)
Match.Path, config_parse_match_strv, 0, offsetof(link_config, match_path)
Match.Driver, config_parse_match_strv, 0, offsetof(link_config, match_driver)

View File

@ -47,6 +47,7 @@ static void link_config_free(link_config *link) {
free(link->filename);
set_free_free(link->match_mac);
set_free_free(link->match_permanent_mac);
strv_free(link->match_path);
strv_free(link->match_driver);
strv_free(link->match_type);
@ -162,8 +163,8 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
if (link->speed > UINT_MAX)
return -ERANGE;
if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
if (set_isempty(link->match_mac) && set_isempty(link->match_permanent_mac) &&
strv_isempty(link->match_path) && strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions)
log_warning("%s: No valid settings found in the [Match] section. "
"The file will match all interfaces. "
@ -236,16 +237,27 @@ bool link_config_should_reload(link_config_ctx *ctx) {
}
int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
struct ether_addr permanent_mac = {};
link_config *link;
const char *name;
int r;
assert(ctx);
assert(device);
assert(ret);
r = sd_device_get_sysname(device, &name);
if (r < 0)
return r;
r = ethtool_get_permanent_macaddr(&ctx->ethtool_fd, name, &permanent_mac);
if (r < 0)
log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
LIST_FOREACH(links, link, ctx->links) {
if (net_match_config(link->match_mac, link->match_path, link->match_driver,
if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
device, NULL, NULL, NULL, 0, NULL, NULL)) {
device, NULL, &permanent_mac, NULL, NULL, 0, NULL, NULL)) {
if (link->match_name && !strv_contains(link->match_name, "*")) {
unsigned name_assign_type = NET_NAME_UNKNOWN;

View File

@ -36,6 +36,7 @@ struct link_config {
char *filename;
Set *match_mac;
Set *match_permanent_mac;
char **match_path;
char **match_driver;
char **match_type;

View File

@ -1,5 +1,6 @@
[Match]
MACAddress=
PermanentMACAddress=
OriginalName=
Path=
Driver=

View File

@ -28,6 +28,7 @@ Virtualization=
KernelCommandLine=
Host=
MACAddress=
PermanentMACAddress=
[Link]
RequiredForOnline=
ARP=

View File

@ -400,7 +400,7 @@ DHCP={}
self.assertRegex(out, (r'{}\s+ether\s+[a-z-]+\s+unmanaged'.format(self.if_router)).encode())
self.assertRegex(out, (r'{}\s+ether\s+routable\s+configured'.format(self.iface)).encode())
out = subprocess.check_output(['networkctl', 'status', self.iface])
out = subprocess.check_output(['networkctl', '-n', '0', 'status', self.iface])
self.assertRegex(out, br'Type:\s+ether')
self.assertRegex(out, br'State:\s+routable.*configured')
self.assertRegex(out, br'Address:\s+192.168.5.\d+')
@ -420,7 +420,7 @@ DHCP={}
subprocess.call(['ip', 'a', 'show', 'dev', self.iface])
print('---- networkctl status {} ----'.format(self.iface))
sys.stdout.flush()
rc = subprocess.call(['networkctl', 'status', self.iface])
rc = subprocess.call(['networkctl', '-n', '0', 'status', self.iface])
if rc != 0:
print("'networkctl status' exited with an unexpected code {}".format(rc))
self.show_journal('systemd-networkd.service')

View File

@ -369,7 +369,7 @@ def restart_networkd(sleep_sec=0, show_logs=True, remove_state_files=True):
start_networkd(sleep_sec)
def get_operstate(link, show_status=True, setup_state='configured'):
output = check_output(*networkctl_cmd, 'status', link, env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', link, env=env)
if show_status:
print(output)
for line in output.splitlines():
@ -392,14 +392,14 @@ class Utilities():
check_output(*args, env=env)
except subprocess.CalledProcessError:
for link in links_with_operstate:
output = check_output(*networkctl_cmd, 'status', link.split(':')[0], env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', link.split(':')[0], env=env)
print(output)
raise
if not bool_any and setup_state:
# check at least once now, then once per sec for setup_timeout secs
for secs in range(setup_timeout + 1):
for link in links_with_operstate:
output = check_output(*networkctl_cmd, 'status', link.split(':')[0])
output = check_output(*networkctl_cmd, '-n', '0', 'status', link.split(':')[0])
print(output)
if not re.search(rf'(?m)^\s*State:.*({setup_state}).*$', output):
# this link isn't in the right state; break into the sleep below
@ -458,7 +458,7 @@ class NetworkctlTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['dummy98:degraded'])
output = check_output(*networkctl_cmd, 'status', 'dummy98', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
self.assertRegex(output, 'hogehogehogehogehogehoge')
def test_reconfigure(self):
@ -529,11 +529,11 @@ class NetworkctlTests(unittest.TestCase, Utilities):
self.assertNotRegex(output, '1 lo ')
self.assertRegex(output, 'test1')
output = check_output(*networkctl_cmd, 'status', 'te*', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'te*', env=env)
self.assertNotRegex(output, '1: lo ')
self.assertRegex(output, 'test1')
output = check_output(*networkctl_cmd, 'status', 'tes[a-z][0-9]', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'tes[a-z][0-9]', env=env)
self.assertNotRegex(output, '1: lo ')
self.assertRegex(output, 'test1')
@ -543,7 +543,7 @@ class NetworkctlTests(unittest.TestCase, Utilities):
self.wait_online(['test1:degraded'])
output = check_output(*networkctl_cmd, 'status', 'test1', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
self.assertRegex(output, 'MTU: 1600')
def test_type(self):
@ -551,11 +551,11 @@ class NetworkctlTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['test1:degraded'])
output = check_output(*networkctl_cmd, 'status', 'test1', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
print(output)
self.assertRegex(output, 'Type: ether')
output = check_output(*networkctl_cmd, 'status', 'lo', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
print(output)
self.assertRegex(output, 'Type: loopback')
@ -565,12 +565,12 @@ class NetworkctlTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['test1:degraded'])
output = check_output(*networkctl_cmd, 'status', 'test1', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
print(output)
self.assertRegex(output, r'Link File: (/usr)?/lib/systemd/network/99-default.link')
self.assertRegex(output, r'Network File: /run/systemd/network/11-dummy.network')
output = check_output(*networkctl_cmd, 'status', 'lo', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
print(output)
self.assertRegex(output, r'Link File: (/usr)?/lib/systemd/network/99-default.link')
self.assertRegex(output, r'Network File: n/a')
@ -797,7 +797,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['dummy98:routable'])
output = check_output('networkctl status dummy98')
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
print(output)
self.assertRegex(output, 'Network File: /run/systemd/network/14-match-udev-property')
@ -827,7 +827,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
self.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
output = check_output(*networkctl_cmd, 'status', 'bridge99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bridge99', env=env)
print(output)
self.assertRegex(output, 'Priority: 9')
self.assertRegex(output, 'STP: yes')
@ -1394,7 +1394,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
output = check_output(*networkctl_cmd, 'status', 'vxlan99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'vxlan99', env=env)
print(output)
self.assertRegex(output, 'VNI: 999')
self.assertRegex(output, 'Destination Port: 5555')
@ -1665,7 +1665,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['test1:routable'])
output = check_output(*networkctl_cmd, 'status', 'test1', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
print(output)
self.assertRegex(output, '192.168.0.15')
self.assertRegex(output, '192.168.0.1')
@ -1759,7 +1759,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['dummy98:routable'])
output = check_output(*networkctl_cmd, 'status', 'dummy98', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
print(output)
print('### ip -6 route show dev dummy98')
@ -2122,7 +2122,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['dummy98:routable'])
output = check_output(*networkctl_cmd, 'status', 'dummy98', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
print(output)
self.assertRegex(output, 'Address: 192.168.42.100')
self.assertRegex(output, 'DNS: 192.168.42.1')
@ -2602,7 +2602,7 @@ class NetworkdRATests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['veth99:routable', 'veth-peer:degraded'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '2002:da8:1:0')
@ -2630,7 +2630,7 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '192.168.5.*')
self.assertRegex(output, 'Gateway: 192.168.5.1')
@ -2642,7 +2642,7 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, 'Gateway: 192.168.5.*')
self.assertRegex(output, '192.168.5.*')
@ -2712,7 +2712,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
start_dnsmasq()
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '2600::')
self.assertNotRegex(output, '192.168.5')
@ -2730,7 +2730,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
start_dnsmasq(additional_options='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time='2m')
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertNotRegex(output, '2600::')
self.assertRegex(output, '192.168.5')
@ -2753,7 +2753,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertNotRegex(output, '2600::')
self.assertRegex(output, '192.168.5')
@ -2781,7 +2781,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '2600::')
self.assertRegex(output, '192.168.5')
@ -2990,7 +2990,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, r'192.168.5.*')
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, r'192.168.5.*')
@ -3006,7 +3006,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, r'192.168.5.*')
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, r'192.168.5.*')
@ -3017,7 +3017,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, r'192.168.5.*')
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, r'192.168.5.*')
@ -3029,7 +3029,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, r'192.168.5.*')
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, r'192.168.5.*')
@ -3179,7 +3179,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
start_dnsmasq()
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '192.168.5')
@ -3373,7 +3373,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
start_dnsmasq('--dhcp-option=option:domain-search,example.com')
self.wait_online(['veth99:routable', 'veth-peer:routable'])
output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, 'Search Domains: example.com')

View File

@ -32,6 +32,10 @@ if [ -z "$FUZZING_ENGINE" ]; then
fuzzflag="llvm-fuzz=true"
fi
# FIXME: temporarily pin the meson version as 0.53 doesn't work with older python 3.5
# See: https://github.com/mesonbuild/meson/issues/6427
pip3 install meson==0.52.1
meson $build -D$fuzzflag -Db_lundef=false
ninja -v -C $build fuzzers

View File

@ -10,7 +10,9 @@ sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ xenial main restri
sudo apt-get update -y
sudo apt-get build-dep systemd -y
sudo apt-get install -y ninja-build python3-pip python3-setuptools quota
pip3 install meson
# FIXME: temporarily pin the meson version as 0.53 doesn't work with older python 3.5
# See: https://github.com/mesonbuild/meson/issues/6427
pip3 install meson==0.52.1
cd $REPO_ROOT
export PATH="$HOME/.local/bin/:$PATH"

View File

@ -14,7 +14,9 @@ sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ xenial main restri
sudo apt-get update -y
sudo apt-get build-dep systemd -y
sudo apt-get install -y ninja-build python3-pip python3-setuptools
pip3 install meson
# FIXME: temporarily pin the meson version as 0.53 doesn't work with older python 3.5
# See: https://github.com/mesonbuild/meson/issues/6427
pip3 install meson==0.52.1
cd $REPO_ROOT
export PATH="$HOME/.local/bin/:$PATH"

View File

@ -8,8 +8,11 @@
# (at your option) any later version.
[Unit]
Description=Load kernel module %i
Description=Load Kernel Module %i
DefaultDependencies=no
Before=sysinit.target
Documentation=man:modprobe(8)
ConditionCapability=CAP_SYS_MODULE
[Service]
Type=oneshot