Compare commits
26 Commits
af6a2a1e57
...
6a6078a585
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | 6a6078a585 | |
Lennart Poettering | 0aa9bffe10 | |
Lennart Poettering | 3bfcfcf942 | |
Lennart Poettering | a1edbc5118 | |
Lennart Poettering | 48dfa8b0e1 | |
Frantisek Sumsal | 514793658c | |
Zbigniew Jędrzejewski-Szmek | 06ae8800d0 | |
Zbigniew Jędrzejewski-Szmek | 629548c405 | |
Zbigniew Jędrzejewski-Szmek | 9552209292 | |
Zbigniew Jędrzejewski-Szmek | d2e825b4ab | |
Yu Watanabe | caa8538a22 | |
Yu Watanabe | 4bb7cc8287 | |
Yu Watanabe | 79b4428a7d | |
Zbigniew Jędrzejewski-Szmek | 8f817cb888 | |
Zbigniew Jędrzejewski-Szmek | 8efc2c1608 | |
Lennart Poettering | 3a827125e7 | |
Lennart Poettering | d5016c21d7 | |
Lennart Poettering | 867af7282b | |
Lennart Poettering | 07141aa005 | |
Zbigniew Jędrzejewski-Szmek | e9f0c5d08c | |
Yu Watanabe | 98b0299479 | |
Yu Watanabe | fc79e6ff5e | |
Yu Watanabe | 10c71c3605 | |
Zach Smith | 52133271a7 | |
Lennart Poettering | 75997c3fa5 | |
Dimitri John Ledkov | 390902012c |
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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, ÐER_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, ÐER_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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[Match]
|
||||
MACAddress=
|
||||
PermanentMACAddress=
|
||||
OriginalName=
|
||||
Path=
|
||||
Driver=
|
||||
|
|
|
@ -28,6 +28,7 @@ Virtualization=
|
|||
KernelCommandLine=
|
||||
Host=
|
||||
MACAddress=
|
||||
PermanentMACAddress=
|
||||
[Link]
|
||||
RequiredForOnline=
|
||||
ARP=
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue