release: bump version to 1.39.4 (development)

This commit is contained in:
Thomas Haller 2022-05-16 09:44:49 +02:00
commit e2476b1063
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
213 changed files with 5520 additions and 9063 deletions

View file

@ -2,6 +2,8 @@
set -ex
export PAGER=cat
IS_FEDORA=0
IS_CENTOS=0
IS_ALPINE=0

View file

@ -1691,7 +1691,6 @@ libnm_lib_h_pub_real = \
src/libnm-client-public/nm-object.h \
src/libnm-client-public/nm-remote-connection.h \
src/libnm-client-public/nm-secret-agent-old.h \
src/libnm-client-public/nm-types.h \
src/libnm-client-public/nm-vpn-connection.h \
src/libnm-client-public/nm-vpn-editor.h \
src/libnm-client-public/nm-vpn-plugin-old.h \
@ -2329,12 +2328,8 @@ src_libnm_systemd_core_libnm_systemd_core_la_libadd = \
src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/nm-default-systemd-core.h \
src/libnm-systemd-core/nm-sd-utils-core.c \
src/libnm-systemd-core/nm-sd-utils-core.h \
src/libnm-systemd-core/nm-sd.c \
src/libnm-systemd-core/nm-sd.h \
src/libnm-systemd-core/nm-sd-utils-dhcp.h \
src/libnm-systemd-core/nm-sd-utils-dhcp.c \
src/libnm-systemd-core/sd-adapt-core/condition.h \
src/libnm-systemd-core/sd-adapt-core/conf-parser.h \
src/libnm-systemd-core/sd-adapt-core/device-util.h \
@ -2345,16 +2340,8 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/sd-adapt-core/sd-daemon.h \
src/libnm-systemd-core/sd-adapt-core/sd-device.h \
src/libnm-systemd-core/sd-adapt-core/udev-util.h \
src/libnm-systemd-core/src/libsystemd-network/arp-util.c \
src/libnm-systemd-core/src/libsystemd-network/arp-util.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c \
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c \
src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c \
src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c \
src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c \
@ -2369,10 +2356,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h \
src/libnm-systemd-core/src/libsystemd-network/network-common.c \
src/libnm-systemd-core/src/libsystemd-network/network-common.h \
src/libnm-systemd-core/src/libsystemd-network/network-internal.c \
src/libnm-systemd-core/src/libsystemd-network/network-internal.h \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \
src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c \
@ -2384,9 +2367,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h \
src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c \
src/libnm-systemd-core/src/systemd/_sd-common.h \
src/libnm-systemd-core/src/systemd/sd-dhcp-client.h \
src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h \
src/libnm-systemd-core/src/systemd/sd-dhcp-option.h \
src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h \
src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h \
src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h \
@ -2547,8 +2527,6 @@ src_core_libNetworkManager_la_SOURCES = \
src/core/dns/nm-dns-dnsmasq.h \
src/core/dns/nm-dns-systemd-resolved.c \
src/core/dns/nm-dns-systemd-resolved.h \
src/core/dns/nm-dns-unbound.c \
src/core/dns/nm-dns-unbound.h \
\
src/core/dnsmasq/nm-dnsmasq-manager.c \
src/core/dnsmasq/nm-dnsmasq-manager.h \
@ -5337,6 +5315,7 @@ EXTRA_DIST += \
src/tests/client/test-client.check-on-disk/test_002.expected \
src/tests/client/test-client.check-on-disk/test_003.expected \
src/tests/client/test-client.check-on-disk/test_004.expected \
src/tests/client/test-client.check-on-disk/test_offline.expected \
\
src/tests/client/meson.build \
$(NULL)

19
NEWS
View file

@ -1,3 +1,22 @@
=============================================
NetworkManager-1.40
Overview of changes since NetworkManager-1.38
=============================================
This is a snapshot of NetworkManager development. The API is
subject to change and not guaranteed to be compatible with
the later release.
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
* Drop unused, internal systemd DHCPv4 client. This is long
replaced by nettools' n-dhcp4 implementation.
* The nmcli command now supports --offline argument with "add" and
"modify" commands, allowing operation on keyfile-formatted connection
profiles without the service running (e.g. during system provisioning).
* The device state file /run/NetworkManager/devices/$ifindex now has
new sections [dhcp4] and [dhcp6] containing the DHCP options for the
current lease.
=============================================
NetworkManager-1.38
Overview of changes since NetworkManager-1.36

View file

@ -13,9 +13,6 @@
/* Define to path of dnsmasq binary */
#mesondefine DNSMASQ_PATH
/* Define to path of unbound dnssec-trigger-script */
#mesondefine DNSSEC_TRIGGER_PATH
/* Gettext package */
#mesondefine GETTEXT_PACKAGE

View file

@ -7,8 +7,8 @@ dnl - add corresponding NM_VERSION_x_y_z macros in
dnl "shared/nm-version-macros.h.in"
dnl - update number in meson.build
m4_define([nm_major_version], [1])
m4_define([nm_minor_version], [38])
m4_define([nm_micro_version], [0])
m4_define([nm_minor_version], [39])
m4_define([nm_micro_version], [4])
m4_define([nm_version],
[nm_major_version.nm_minor_version.nm_micro_version])
@ -306,11 +306,12 @@ AC_ARG_WITH(udev-dir,
[Absolute path of the udev base directory. Set to 'no' not to install the udev rules]),
[], [with_udev_dir="yes"])
if test "$with_udev_dir" != 'no'; then
if test "$with_udev_dir" != 'yes' && printf '%s' "$with_udev_dir" | grep -v -q '^/'; then
AC_MSG_ERROR([--with-udev-dir must be an absolute path or 'yes' or 'no'. Instead it is '$with_udev_dir'])
fi
if test "$with_udev_dir" = 'yes'; then
with_udev_dir="\$(prefix)/lib/udev"
if test "$with_udev_dir" = 'yes' -o "$with_udev_dir" = "" ; then
with_udev_dir="\${prefix}/lib/udev"
else
if printf '%s' "$with_udev_dir" | grep -v -q '^/'; then
AC_MSG_ERROR([--with-udev-dir must be an absolute path or 'yes' or 'no'. Instead it is '$with_udev_dir'])
fi
fi
UDEV_DIR="$with_udev_dir"
AC_SUBST(UDEV_DIR)
@ -745,7 +746,6 @@ AC_SUBST(GLIB_MKENUMS)
AC_ARG_WITH(dbus-sys-dir,
AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is]))
if test -n "$with_dbus_sys_dir" ; then
DBUS_SYS_DIR="$with_dbus_sys_dir"
else
@ -1006,18 +1006,6 @@ fi
AC_DEFINE_UNQUOTED(DNSMASQ_PATH, "$DNSMASQ_PATH", [Define to path of dnsmasq binary])
AC_SUBST(DNSMASQ_PATH)
# dnssec-trigger-script path
AC_ARG_WITH(dnssec_trigger,
AS_HELP_STRING([--with-dnssec-trigger=/path/to/dnssec-trigger-script], [path to unbound dnssec-trigger-script]))
if test "x${with_dnssec_trigger}" = x; then
AC_PATH_PROG(DNSSEC_TRIGGER_PATH, dnssec-trigger-script, /usr/libexec/dnssec-trigger-script,
/usr/local/libexec:/usr/local/lib:/usr/local/lib/dnssec-trigger:/usr/libexec:/usr/lib:/usr/lib/dnssec-trigger)
else
DNSSEC_TRIGGER_PATH="$with_dnssec_trigger"
fi
AC_DEFINE_UNQUOTED(DNSSEC_TRIGGER_PATH, "$DNSSEC_TRIGGER_PATH", [Define to path of unbound dnssec-trigger-script])
AC_SUBST(DNSSEC_TRIGGER_PATH)
# system CA certificates path
AC_ARG_WITH(system-ca-path,
AS_HELP_STRING([--with-system-ca-path=/path/to/ssl/certs], [path to system CA certificates]))
@ -1374,8 +1362,10 @@ echo " exec_prefix: $exec_prefix"
echo " sysconfdir: $sysconfdir"
echo " localstatedir: $localstatedir"
echo " runstatedir: $runstatedir"
echo " datarootdir: $datarootdir"
echo " datadir: $datadir"
echo " systemdunitdir: $with_systemdsystemunitdir"
echo " udev-dir: $with_udev_dir"
echo " nmbinary: $nmbinary"
echo " nmconfdir: $nmconfdir"
echo " nmlibdir: $nmlibdir"
@ -1383,6 +1373,7 @@ echo " nmdatadir: $nmdatadir"
echo " nmstatedir: $nmstatedir"
echo " nmrundir: $nmrundir"
echo " system-ca-path: $with_system_ca_path"
echo " dbus-sys-dir: $DBUS_SYS_DIR"
echo
echo "Platform:"

View file

@ -13,8 +13,8 @@
%global glib2_version %(pkg-config --modversion glib-2.0 2>/dev/null || echo bad)
%global epoch_version 1
%global rpm_version __VERSION__
%global real_version __VERSION__
%global rpm_version %{real_version}
%global release_version __RELEASE_VERSION__
%global snapshot __SNAPSHOT__
%global git_sha __COMMIT__

View file

@ -548,9 +548,13 @@ done
do_command git push "$ORIGIN" "${BRANCHES[@]}" || die "failed to to push branches ${BRANCHES[@]} to $ORIGIN"
FAIL=0
for r in "${RELEASE_FILES[@]}"; do
do_command ssh master.gnome.org ftpadmin install --unattended "$r" || die "ftpadmin install failed"
do_command ssh master.gnome.org ftpadmin install --unattended "$r" || FAIL=1
done
if [ "$FAIL" = 1 ]; then
die "ftpadmin install failed. This was the last step. Invoke the command manually"
fi
CLEANUP_CHECKOUT_BRANCH=
if [ "$DRY_RUN" = 0 ]; then

View file

@ -70,7 +70,7 @@ git_remote_add_gnome() {
}
git_remote_add_github() {
git remote add "${2-origin}" "git://github.com/$1.git"
git remote add "${2-origin}" "https://github.com/$1.git"
git remote 'set-url' --push "${2-origin}" "git@github.com:$1.git"
}
@ -319,16 +319,25 @@ MAKEREPO_GIT_IGNORE_LAST="makerepo.gitignore.last-$CURRENT_BRANCH"
get_local_mirror() {
local URL="$1"
local DIRNAME
local FULLNAME
if [[ -z "$URL" ]]; then
return
fi
local DIRNAME="$(echo $URL.git | sed -e 's#^.*/\([^/]\+\)$#\1#' -e 's/\(.*\)\.git$/\1/')"
local FULLNAME="$srcdir/.git/.makerepo-${DIRNAME}.git"
[[ -n "$NO_REMOTE" ]] && return
DIRNAME="${URL##*/}"
DIRNAME="${DIRNAME%.git}"
FULLNAME="$srcdir/.git/.makerepo-${DIRNAME}.git"
if [ ! -d "$FULLNAME" ] && [ -d "$FULLNAME.git" ]; then
# due to a bug, old versions of the script might have created "*.git.git/" directories.
# rename.
mv "$FULLNAME.git" "$FULLNAME"
fi
if [[ ! -d "$FULLNAME" ]]; then
if [[ -f "$FULLNAME" ]]; then
# create a file with name $FULLNAME, to suppress local mirroring

View file

@ -11,6 +11,9 @@ do_cleanup() {
local IDX="$1"
local NAME_PREFIX="${2:-net}"
local PEER_PREFIX="${3:-d_}"
local NETNS_PREFIX="${4:-tt}"
logger --id "nm-env-prepare-$IDX" "cleanup start # $@"
pkill -F "/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" dnsmasq &>/dev/null || :
rm -rf "/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid"
@ -24,40 +27,60 @@ do_cleanup() {
rm -rf "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf"
ip link del "$PEER_PREFIX$IDX" &>/dev/null || :
ip -netns "$NETNS_PREFIX$IDX" link del "$PEER_PREFIX$IDX" &>/dev/null || :
ip netns del "$NETNS_PREFIX$IDX" &>/dev/null || :
logger --id "nm-env-prepare-$IDX" "cleanup complete # $@"
}
do_setup() {
local IDX="$1"
local NAME_PREFIX="${2:-net}"
local PEER_PREFIX="${3:-d_}"
local NETNS_PREFIX="${4:-tt}"
do_cleanup "$IDX"
logger --id "nm-env-prepare-$IDX" "setup start # $@"
ip link add "$NAME_PREFIX$IDX" type veth peer "$PEER_PREFIX$IDX"
ip link set "$PEER_PREFIX$IDX" up
ip netns add "$NETNS_PREFIX$IDX"
ip -netns "$NETNS_PREFIX$IDX" link set lo up
ip addr add "192.168.$((120 + IDX)).1/23" dev "$PEER_PREFIX$IDX"
ip addr add "192:168:$((120 + IDX))::1/64" dev "$PEER_PREFIX$IDX"
ip -netns "$NETNS_PREFIX$IDX" link add "$NAME_PREFIX$IDX" type veth peer "$PEER_PREFIX$IDX"
ip -netns "$NETNS_PREFIX$IDX" link set "$PEER_PREFIX$IDX" up
ip -netns "$NETNS_PREFIX$IDX" addr add "192.168.$((120 + IDX)).1/23" dev "$PEER_PREFIX$IDX"
ip -netns "$NETNS_PREFIX$IDX" addr add "192:168:$((120 + IDX))::1/64" dev "$PEER_PREFIX$IDX"
# PPPoE inside the rootless container is not actually working, because
# /dev/ppp is not accessible. Still start it, so that we at least can
# test how far it goes...
echo "192.168.$((120 + $IDX)).180-200" > "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX"
pppoe-server -X "/tmp/nm-pppoe-$PEER_PREFIX$IDX.pid" -S isp -C isp -L "192.168.$((120 + IDX)).1" -p "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX" -I "$PEER_PREFIX$IDX" &
ip netns exec "$NETNS_PREFIX$IDX" \
pppoe-server \
-X "/tmp/nm-pppoe-$PEER_PREFIX$IDX.pid" \
-S isp \
-C isp \
-L "192.168.$((120 + IDX)).1" \
-p "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX" \
-I "$PEER_PREFIX$IDX" \
&
dnsmasq \
--conf-file=/dev/null \
--pid-file="/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" \
--no-hosts \
--keep-in-foreground \
--bind-interfaces \
--except-interface=lo \
--clear-on-reload \
--listen-address="192.168.$((120 + $IDX)).1" \
--dhcp-range="192.168.$((120 + $IDX)).100,192.168.$((120 + $IDX)).150" \
--no-ping \
&
ip netns exec "$NETNS_PREFIX$IDX" \
dnsmasq \
--conf-file=/dev/null \
--pid-file="/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" \
--no-hosts \
--keep-in-foreground \
--bind-interfaces \
--log-debug \
--log-queries \
--log-dhcp \
--except-interface=lo \
--clear-on-reload \
--listen-address="192.168.$((120 + $IDX)).1" \
--dhcp-range="192.168.$((120 + $IDX)).100,192.168.$((120 + $IDX)).150" \
--no-ping \
&
cat <<EOF > "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf"
interface $PEER_PREFIX$IDX
@ -70,10 +93,17 @@ interface $PEER_PREFIX$IDX
};
EOF
radvd \
--config "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" \
--pidfile "/tmp/nm-radvd-$PEER_PREFIX$IDX.pid" \
&
ip netns exec "$NETNS_PREFIX$IDX" \
radvd \
--config "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" \
--pidfile "/tmp/nm-radvd-$PEER_PREFIX$IDX.pid" \
--logmethod syslog \
-d 5 \
&
ip -netns ""$NETNS_PREFIX$IDX"" link set "$NAME_PREFIX$IDX" netns $$
logger --id "nm-env-prepare-$IDX" "setup complete: netns=$NETNS_PREFIX$IDX, iface=$NAME_PREFIX$IDX, peer=$PEER_PREFIX$IDX # $@"
}
do_redo() {
@ -81,8 +111,27 @@ do_redo() {
do_setup "$@"
}
do_one_time_setup() {
if [ ! -d /tmp/sys2 ]; then
# `ip -netns t exec ...` will try to mount sysfs. But kernel rejects that in
# the container, unless a writable sysfs is already mounted. Due to --priviledged,
# we have /sys mounted rw, however, ip will first unmount /sys before trying to
# remount it. We thus need it mounted as rw one additional time.
#
# Let's do this setup step once, and never clean it up.
# https://github.com/containers/podman/issues/11887#issuecomment-938706628
mkdir /tmp/sys2
mount -t sysfs --make-private /tmp/sys2
fi
}
###############################################################################
# We do this one-time-setup always when the script runs, and never clean it
# up.
do_one_time_setup
IDX=1
NAME_PREFIX=net
PEER_PREFIX=

View file

@ -109,7 +109,54 @@ find NetworkManager bind mounted at $BASEDIR_NM
run \`nm-env-prepare.sh setup --idx 1\` to setup test interfaces
Configure NetworkManager with
\$ ./configure --enable-maintainer-mode --enable-more-warnings=error --with-more-asserts="\${NM_BUILD_MORE_ASSERTS:-1000}" --with-nm-cloud-setup=yes --prefix=/opt/test --localstatedir=/var --sysconfdir=/etc --enable-gtk-doc --enable-introspection --with-ofono=yes --with-dhclient=yes --with-dhcpcanon=yes --with-dhcpcd=yes --enable-more-logging --enable-compile-warnings=yes --enable-address-sanitizer=no --enable-undefined-sanitizer=no --with-valgrind=yes --enable-concheck --enable-wimax --enable-ifcfg-rh=yes --enable-config-plugin-ibft=yes --enable-ifcfg-suse --enable-ifupdown=yes --enable-ifnet --enable-vala=yes --enable-polkit=yes --with-libnm-glib=yes --with-nmcli=yes --with-nmtui=yes --with-modem-manager-1 --with-suspend-resume=systemd --enable-teamdctl=yes --enable-ovs=yes --enable-tests="\${NM_BUILD_TESTS:-yes}" --with-netconfig=/bin/nowhere/netconfig --with-resolvconf=/bin/nowhere/resolvconf --with-crypto=nss --with-session-tracking=systemd --with-consolekit=yes --with-systemd-logind=yes --with-iwd=yes --enable-json-validation=yes --with-consolekit=yes --with-config-dns-rc-manager-default=auto --with-config-dhcp-default=internal "\${NM_CONFIGURE_OTPS[@]}"
\$ ./configure \
--enable-address-sanitizer=no \
--enable-compile-warnings=yes \
--enable-concheck \
--enable-config-plugin-ibft=yes \
--enable-gtk-doc \
--enable-ifcfg-rh=yes \
--enable-ifcfg-suse \
--enable-ifnet \
--enable-ifupdown=yes \
--enable-introspection \
--enable-json-validation=yes \
--enable-maintainer-mode \
--enable-more-logging \
--enable-more-warnings=error \
--enable-ovs=yes \
--enable-polkit=yes \
--enable-teamdctl=yes \
--enable-undefined-sanitizer=no \
--enable-vala=yes \
--enable-wimax \
--localstatedir=/var \
--prefix=/opt/test \
--sysconfdir=/etc \
--with-config-dhcp-default=internal \
--with-config-dns-rc-manager-default=auto \
--with-consolekit=yes \
--with-consolekit=yes \
--with-crypto=nss \
--with-dhclient=yes \
--with-dhcpcanon=yes \
--with-dhcpcd=yes \
--with-iwd=yes \
--with-libnm-glib=yes \
--with-modem-manager-1 \
--with-netconfig=/bin/nowhere/netconfig \
--with-nm-cloud-setup=yes \
--with-nmcli=yes \
--with-nmtui=yes \
--with-ofono=yes \
--with-resolvconf=/bin/nowhere/resolvconf \
--with-session-tracking=systemd \
--with-suspend-resume=systemd \
--with-systemd-logind=yes \
--with-valgrind=yes \
--enable-tests="\${NM_BUILD_TESTS:-yes}" \
--with-more-asserts="\${NM_BUILD_MORE_ASSERTS:-1000}" \
"\${NM_CONFIGURE_OTPS[@]}"
Test with:
\$ systemctl stop NetworkManager; /opt/test/sbin/NetworkManager --debug 2>&1 | tee -a /tmp/nm-log.txt
EOF
@ -249,6 +296,8 @@ RUN dnf install -y \\
mlocate \\
mobile-broadband-provider-info-devel \\
newt-devel \\
nispor \\
nmstate \\
nss-devel \\
polkit-devel \\
ppp \\

View file

@ -71,11 +71,11 @@ def find_checkpoint(nmc, path):
def find_checkpoint_last(nmc):
l = [c.get_path() for c in nmc.get_checkpoints()]
if not l:
return None
l.sort(key=checkpoint_path_to_num)
return l[-1]
return max(
nmc.get_checkpoints(),
key=lambda c: checkpoint_path_to_num(c.get_path()),
default=None,
)
def validate_path(path, nmc):

View file

@ -345,19 +345,12 @@ no-auto-default=*
<para><literal>systemd-resolved</literal>: NetworkManager will
push the DNS configuration to systemd-resolved</para>
<para><literal>unbound</literal>: NetworkManager will talk
to unbound and dnssec-triggerd, using "Conditional Forwarding"
with DNSSEC support. <filename>/etc/resolv.conf</filename>
will be managed by dnssec-trigger daemon. This option is
deprecated. Note that dnssec-trigger ships a NetworkManager dispatcher
script so this DNS plugin is not necessary.</para>
<para><literal>none</literal>: NetworkManager will not
modify resolv.conf. This implies
<literal>rc-manager</literal>&nbsp;<literal>unmanaged</literal></para>
<para>Note that the plugins <literal>dnsmasq</literal>, <literal>systemd-resolved</literal>
and <literal>unbound</literal> are caching local nameservers.
<para>Note that the plugins <literal>dnsmasq</literal> and <literal>systemd-resolved</literal>
are caching local nameservers.
Hence, when NetworkManager writes <filename>&nmrundir;/resolv.conf</filename>
and <filename>/etc/resolv.conf</filename> (according to <literal>rc-manager</literal>
setting below), the name server there will be localhost only.

View file

@ -614,6 +614,32 @@ Connection 'ethernet-4' (de89cdeb-a3e1-4d53-8fa0-c22546c775f4) successfully
<screen><prompt>$ </prompt><userinput>nmcli connection add type bluetooth con-name "My Bluetooth Hotspot" autoconnect no ifname btnap0 bluetooth.type nap ipv4.method shared ipv6.method shared</userinput></screen>
</example>
<example><title>Offline use</title>
<screen><prompt>$ </prompt><userinput>nmcli --offline con add type ethernet '
conn.id eth0 \
conn.interface-name eth0 \
>/sysroot/etc/NetworkManager/system-connections/eth0.nmconnection</userinput></screen>
<para>
Creates a connection file in keyfile format without using the NetworkManager service.
This allows for use of familiar <command>nmcli</command> syntax in situations
where the service is not running, such as during system installation of image
provisioning and ensures the resulting file is correctly formatted.
</para>
<screen><prompt>$ </prompt><userinput>nmcli --offline con modify type ethernet '
conn.id eth0-ipv6 \
ipv4.method disabled \
&lt;/sysroot/etc/NetworkManager/system-connections/eth0.nmconnection \
>/sysroot/etc/NetworkManager/system-connections/eth0-ipv6.nmconnection</userinput></screen>
<para>
Read and write a connection file without using the NetworkManager service, modifying
some properties along the way.
</para>
<para>
This allows templating of the connection profiles using familiar
<command>nmcli</command> syntax in situations where the service is not running.
</para>
</example>
</refsect1>
<refsect1>

View file

@ -314,6 +314,23 @@
</listitem>
</varlistentry>
<varlistentry>
<term><group choice='plain'>
<arg choice='plain'><option>--offline</option></arg>
</group></term>
<listitem>
<para>Work without a daemon. Makes <command>connection add</command> and
<command>connection modify</command> commands accept and produce connection
data via standard input/output. Ordinarily, nmcli would communicate with
the NetworkManager service.</para>
<para>The connection data format (keyfile) is described in
<citerefentry><refentrytitle>nm-settings-keyfile</refentrytitle><manvolnum>5</manvolnum></citerefentry>
manual.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><group choice='plain'>
<arg choice='plain'><option>-v</option></arg>
@ -928,7 +945,7 @@
<arg choice='plain'><option>uuid</option></arg>
<arg choice='plain'><option>path</option></arg>
</group>
<arg choice='plain'><replaceable>ID</replaceable></arg>
<arg><replaceable>ID</replaceable></arg>
<arg rep='repeat' choice='plain'>
<group choice='req'>
<arg choice='plain'><replaceable>option</replaceable> <replaceable>value</replaceable></arg>
@ -962,7 +979,14 @@
<para>The connection is identified by its name, UUID or D-Bus path. If
<replaceable>ID</replaceable> is ambiguous, a keyword <option>id</option>,
<option>uuid</option> or <option>path</option> can be used.</para>
<option>uuid</option> or <option>path</option> can be used.
The <replaceable>ID</replaceable> is not used with the global
<option>--offline</option> option.</para>
<para>When the global <option>--offline</option> is used, the
command reads the connection from the standard input and prints the
modified connection to standard output instead of making the
the NetworkManager daemon act upon specified connection.</para>
</listitem>
</varlistentry>
@ -1096,6 +1120,10 @@
</listitem>
</varlistentry>
</variablelist>
<para>When the global <option>--offline</option> is used, the
command prints the resulting connection to standard output instead of
actually adding the connection via the NetworkManager daemon.</para>
</listitem>
</varlistentry>

View file

@ -6,7 +6,7 @@ project(
# - add corresponding NM_VERSION_x_y_z macros in
# "src/libnm-core-public/nm-version-macros.h.in"
# - update number in configure.ac
version: '1.38.0',
version: '1.39.4',
license: 'GPL2+',
default_options: [
'buildtype=debugoptimized',
@ -353,10 +353,14 @@ if enable_introspection
endif
udev_udevdir = get_option('udev_dir')
install_udevdir = (udev_udevdir != 'no')
if install_udevdir and udev_udevdir == ''
udev_udevdir = dependency('udev').get_pkgconfig_variable('udevdir')
if udev_udevdir == 'no'
install_udevdir = false
else
install_udevdir = true
if (udev_udevdir == '' or udev_udevdir == 'yes')
udev_udevdir = join_paths(nm_prefix, 'lib/udev')
endif
assert(udev_udevdir.startswith('/'), 'udev_dir must be an absolute path, but is ' + udev_udevdir)
endif
systemd_systemdsystemunitdir = get_option('systemdsystemunitdir')
@ -364,7 +368,7 @@ install_systemdunitdir = (systemd_systemdsystemunitdir != 'no')
if install_systemdunitdir and systemd_systemdsystemunitdir == ''
assert(systemd_dep.found(), 'systemd required but not found, please provide a valid systemd user unit dir or disable it')
systemd_systemdsystemunitdir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
systemd_systemdsystemunitdir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir', define_variable: ['rootprefix', nm_prefix])
endif
enable_systemd_journal = get_option('systemd_journal')
@ -551,7 +555,7 @@ endif
dbus_conf_dir = get_option('dbus_conf_dir')
if dbus_conf_dir == ''
assert(dbus_dep.found(), 'D-Bus required but not found, please provide a valid system bus config dir')
dbus_conf_dir = join_paths(dbus_dep.get_pkgconfig_variable('datadir'), 'dbus-1', 'system.d')
dbus_conf_dir = join_paths(dbus_dep.get_pkgconfig_variable('datarootdir', define_variable: ['prefix', nm_prefix]), 'dbus-1', 'system.d')
endif
dbus_interfaces_dir = dbus_dep.get_pkgconfig_variable('interfaces_dir', define_variable: ['datadir', nm_datadir])
@ -683,18 +687,11 @@ endforeach
# external misc tools paths
default_paths = ['/sbin', '/usr/sbin']
dnssec_ts_paths = ['/usr/local/libexec',
'/usr/local/lib',
'/usr/local/lib/dnssec-trigger',
'/usr/libexec',
'/usr/lib',
'/usr/lib/dnssec-trigger']
# 0: cmdline option, 1: paths, 2: fallback
progs = [['iptables', default_paths, '/usr/sbin/iptables'],
['nft', default_paths, '/usr/sbin/nft'],
['dnsmasq', default_paths, ''],
['dnssec_trigger', dnssec_ts_paths, join_paths(nm_libexecdir, 'dnssec-trigger-script') ],
progs = [['iptables', default_paths, '/usr/sbin/iptables'],
['nft', default_paths, '/usr/sbin/nft'],
['dnsmasq', default_paths, ''],
]
foreach prog : progs
@ -1020,6 +1017,7 @@ output = '\nSystem paths:\n'
output += ' prefix: ' + nm_prefix + '\n'
output += ' exec_prefix: ' + nm_prefix + '\n'
output += ' systemdunitdir: ' + systemd_systemdsystemunitdir + '\n'
output += ' udev_dir: ' + udev_udevdir + '\n'
output += ' nmbinary: ' + nm_pkgsbindir + '\n'
output += ' nmconfdir: ' + nm_pkgconfdir + '\n'
output += ' nmlibdir: ' + nm_pkglibdir + '\n'
@ -1028,7 +1026,8 @@ output += ' nmstatedir: ' + nm_pkgstatedir + '\n'
output += ' nmrundir: ' + nm_pkgrundir + '\n'
output += ' nmvpndir: ' + nm_vpndir + '\n'
output += ' nmplugindir: ' + nm_plugindir + '\n'
output += ' system-ca-path: ' + system_ca_path + '\n'
output += ' system_ca_path: ' + system_ca_path + '\n'
output += ' dbus_conf_dir: ' + dbus_conf_dir + '\n'
output += '\nPlatform:\n'
output += ' session tracking: ' + ','.join(session_trackers) + '\n'
output += ' suspend/resume: ' + suspend_resume + '\n'

View file

@ -7,7 +7,6 @@ option('kernel_firmware_dir', type: 'string', value: '/lib/firmware', descriptio
option('iptables', type: 'string', value: '', description: 'path to iptables')
option('nft', type: 'string', value: '', description: 'path to nft')
option('dnsmasq', type: 'string', value: '', description: 'path to dnsmasq')
option('dnssec_trigger', type: 'string', value: '', description: 'path to unbound dnssec-trigger-script')
# platform
option('dist_version', type: 'string', value: '', description: 'Define the NM\'s distribution version string')

1177
po/uk.po

File diff suppressed because it is too large Load diff

View file

@ -9,23 +9,19 @@ on:
jobs:
ci:
name: CI with Default Configuration
runs-on: ubuntu-latest
steps:
- name: Fetch Sources
uses: actions/checkout@v2
- name: Run through C-Util CI
uses: c-util/automation/src/ci-c-util@v1
with:
m32: 1
valgrind: 1
uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
with:
cabuild_ref: "v1"
m32: true
matrixmode: true
valgrind: true
ci-msvc:
name: CI with MSVC
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2016, windows-latest]
os: [windows-2019, windows-latest]
steps:
- name: Fetch Sources

View file

@ -30,11 +30,12 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
Copyright (C) 2015-2019 Red Hat, Inc.
Copyright (C) 2015-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
Danilo Horta <danilo.horta@pm.me>
David Rheinsberg <david.rheinsberg@gmail.com>
Lucas De Marchi <lucas.de.marchi@gmail.com>
Michele Dionisio
Thomas Haller <thaller@redhat.com>
Tom Gundersen <teg@jklm.no>

View file

@ -1,5 +1,18 @@
# c-list - Circular Intrusive Double Linked List Collection
## CHANGES WITH 4:
* The minimum required meson version is now 0.60.0.
* New function c_list_split() is added. It reverses c_list_splice()
and thus allows to split a list in half.
* TBD
Contributions from: David Rheinsberg
- TBD, YYYY-MM-DD
## CHANGES WITH 3:
* API break: The c_list_loop_*() symbols were removed, since we saw

View file

@ -20,7 +20,7 @@ The requirements for this project are:
At build-time, the following software is required:
* `meson >= 0.41`
* `meson >= 0.60`
* `pkg-config >= 0.29`
### Build

View file

@ -1,15 +1,46 @@
project(
'c-list',
'c',
version: '3',
license: 'Apache',
default_options: [
'c_std=c99',
],
license: 'Apache',
meson_version: '>=0.60.0',
version: '3.0.0',
)
major = meson.project_version().split('.')[0]
project_description = 'Circular Intrusive Double Linked List Collection'
add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
# See c-stdaux for details on these. We do not have c-stdaux as dependency, so
# we keep a duplicated set here, reduced to the minimum.
cflags = meson.get_compiler('c').get_supported_arguments(
'-D_GNU_SOURCE',
'-Wno-gnu-alignof-expression',
'-Wno-maybe-uninitialized',
'-Wno-unknown-warning-option',
'-Wno-unused-parameter',
'-Wno-error=type-limits',
'-Wno-error=missing-field-initializers',
'-Wdate-time',
'-Wdeclaration-after-statement',
'-Wlogical-op',
'-Wmissing-include-dirs',
'-Wmissing-noreturn',
'-Wnested-externs',
'-Wredundant-decls',
'-Wshadow',
'-Wstrict-aliasing=3',
'-Wsuggest-attribute=noreturn',
'-Wundef',
'-Wwrite-strings',
)
add_project_arguments(cflags, language: 'c')
subdir('src')
meson.override_dependency('libclist-'+major, libclist_dep, static: true)

View file

@ -259,6 +259,31 @@ static inline void c_list_splice(CList *target, CList *source) {
}
}
/**
* c_list_split() - split one list in two
* @source: the list to split
* @where: new starting element of newlist
* @target: new list
*
* This splits @source in two. All elements following @where (including @where)
* are moved to @target, replacing any old list. If @where points to @source
* (i.e., the end of the list), @target will be empty.
*/
static inline void c_list_split(CList *source, CList *where, CList *target) {
if (where == source) {
*target = (CList)C_LIST_INIT(*target);
} else {
target->next = where;
target->prev = source->prev;
where->prev->next = source;
source->prev = where->prev;
where->prev = target;
target->prev->next = target;
}
}
/**
* c_list_first() - return pointer to first element, or NULL if empty
* @list: list to operate on, or NULL

View file

@ -13,10 +13,10 @@ if not meson.is_subproject()
install_headers('c-list.h')
mod_pkgconfig.generate(
version: meson.project_version(),
name: 'libclist',
filebase: 'libclist',
description: project_description,
filebase: 'libclist-'+major,
name: 'libclist',
version: meson.project_version(),
)
endif

View file

@ -17,7 +17,8 @@ typedef struct {
} Node;
static void test_api(void) {
CList *list_iter, *list_safe, list = C_LIST_INIT(list);
CList *list_iter, *list_safe;
CList list = C_LIST_INIT(list), list2 = C_LIST_INIT(list2);
Node node = { .id = 0, .link = C_LIST_INIT(node.link) };
assert(c_list_init(&list) == &list);
@ -68,7 +69,7 @@ static void test_api(void) {
c_list_unlink(&node.link);
assert(!c_list_is_linked(&node.link));
/* swap / splice list operators */
/* swap / splice / split list operators */
c_list_swap(&list, &list);
assert(c_list_is_empty(&list));
@ -76,6 +77,10 @@ static void test_api(void) {
c_list_splice(&list, &list);
assert(c_list_is_empty(&list));
c_list_split(&list, &list, &list2);
assert(c_list_is_empty(&list));
assert(c_list_is_empty(&list2));
/* direct/raw iterators */
c_list_for_each(list_iter, &list)

View file

@ -11,6 +11,18 @@
#include <string.h>
#include "c-list.h"
static void assert_list_integrity(CList *list) {
CList *iter;
iter = list;
do {
assert(iter->next->prev == iter);
assert(iter->prev->next == iter);
iter = iter->next;
} while (iter != list);
}
static void test_iterators(void) {
CList *iter, *safe, a, b, list = C_LIST_INIT(list);
unsigned int i;
@ -158,6 +170,85 @@ static void test_splice(void) {
assert(c_list_last(&target) == &e2);
}
static void test_split(void) {
CList e1, e2;
/* split empty list */
{
CList source = C_LIST_INIT(source), target;
c_list_split(&source, &source, &target);
assert(c_list_is_empty(&source));
assert(c_list_is_empty(&target));
assert_list_integrity(&source);
assert_list_integrity(&target);
}
/* split 1-element list excluding the element */
{
CList source = C_LIST_INIT(source), target;
c_list_link_tail(&source, &e1);
c_list_split(&source, &source, &target);
assert(!c_list_is_empty(&source));
assert(c_list_is_empty(&target));
assert_list_integrity(&source);
assert_list_integrity(&target);
}
/* split 1-element list including the element */
{
CList source = C_LIST_INIT(source), target;
c_list_link_tail(&source, &e1);
c_list_split(&source, &e1, &target);
assert(c_list_is_empty(&source));
assert(!c_list_is_empty(&target));
assert_list_integrity(&source);
assert_list_integrity(&target);
}
/* split 2-element list excluding the elements */
{
CList source = C_LIST_INIT(source), target;
c_list_link_tail(&source, &e1);
c_list_link_tail(&source, &e2);
c_list_split(&source, &source, &target);
assert(!c_list_is_empty(&source));
assert(c_list_is_empty(&target));
assert_list_integrity(&source);
assert_list_integrity(&target);
}
/* split 2-element list including one element */
{
CList source = C_LIST_INIT(source), target;
c_list_link_tail(&source, &e1);
c_list_link_tail(&source, &e2);
c_list_split(&source, &e2, &target);
assert(!c_list_is_empty(&source));
assert(!c_list_is_empty(&target));
assert_list_integrity(&source);
assert_list_integrity(&target);
}
/* split 2-element list including both elements */
{
CList source = C_LIST_INIT(source), target;
c_list_link_tail(&source, &e1);
c_list_link_tail(&source, &e2);
c_list_split(&source, &e1, &target);
assert(c_list_is_empty(&source));
assert(!c_list_is_empty(&target));
assert_list_integrity(&source);
assert_list_integrity(&target);
}
}
static void test_flush(void) {
CList e1 = C_LIST_INIT(e1), e2 = C_LIST_INIT(e2);
CList list1 = C_LIST_INIT(list1), list2 = C_LIST_INIT(list2);
@ -220,6 +311,7 @@ int main(void) {
test_iterators();
test_swap();
test_splice();
test_split();
test_flush();
test_macros();
test_gnu();

View file

@ -9,25 +9,15 @@ on:
jobs:
ci:
name: CI with Default Configuration
runs-on: ubuntu-latest
steps:
- name: Fetch Sources
uses: actions/checkout@v2
- name: Run through C-Util CI
uses: c-util/automation/src/ci-c-util@v1
with:
m32: 1
valgrind: 1
uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
with:
cabuild_ref: "v1"
m32: true
matrixmode: true
valgrind: true
ci-ptrace:
name: Reduced CI with PTrace
runs-on: ubuntu-latest
env:
CRBTREE_TEST_PTRACE: '1'
steps:
- name: Fetch Sources
uses: actions/checkout@v2
- name: Run through C-Util CI
uses: c-util/automation/src/ci-c-util@v1
uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
with:
cabuild_ref: "v1"
mesonargs: '-Dptrace=true'

View file

@ -1,3 +0,0 @@
[submodule "subprojects/c-stdaux"]
path = subprojects/c-stdaux
url = https://github.com/c-util/c-stdaux.git

View file

@ -30,7 +30,7 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
Copyright (C) 2015-2019 Red Hat, Inc.
Copyright (C) 2015-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>

View file

@ -1,5 +1,20 @@
# c-rbtree - Intrusive Red-Black Tree Collection
## CHANGES WITH 4:
* Add 'ptrace' build option to enable running tests using 'ptrace'
to verify extended execution properties. This option should not
be used in setups where 'ptrace' cannot be employed (like running
under gdb or valgrind). This option only affects the test-suite.
* meson-0.60.0 is now the minimum required meson version.
* TBD
Contributions from: David Rheinsberg
- TBD, YYYY-MM-DD
## CHANGES WITH 3:
* Add more helpers. Add both a collection of iteratiors and helpers

View file

@ -22,7 +22,7 @@ The requirements for this project are:
At build-time, the following software is required:
* `meson >= 0.41`
* `meson >= 0.60`
* `pkg-config >= 0.29`
### Build

View file

@ -1,19 +1,22 @@
project(
'c-rbtree',
'c',
version: '3',
license: 'Apache',
default_options: [
'c_std=c11'
],
license: 'Apache',
meson_version: '>=0.60.0',
version: '3.0.0',
)
major = meson.project_version().split('.')[0]
project_description = 'Intrusive Red-Black Tree Collection'
add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
use_ptrace = get_option('ptrace')
sub_cstdaux = subproject('c-stdaux')
dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep')
dep_cstdaux = dependency('libcstdaux-1')
add_project_arguments(dep_cstdaux.get_variable('cflags').split(' '), language: 'c')
subdir('src')
meson.override_dependency('libcrbtree-'+major, libcrbtree_dep, static: true)

View file

@ -0,0 +1 @@
option('ptrace', type: 'boolean', value: false, description: 'Allow ptrace in test suite')

View file

@ -144,6 +144,11 @@ static inline void c_rbnode_init(CRBNode *n) {
*
* Return: Pointer to parent container, or NULL.
*/
/*
* Note: This was carefully designed to avoid multiple evaluation of `_what`,
* but avoid context-expression-extensions. That is why it uses the
* possibly odd style of `(x ?: offsetof(...)) - offsetof(...))`.
*/
#define c_rbnode_entry(_what, _t, _m) \
((_t *)(void *)(((unsigned long)(void *)(_what) ?: \
offsetof(_t, _m)) - offsetof(_t, _m)))

View file

@ -8,8 +8,8 @@ libcrbtree_deps = [
dep_cstdaux,
]
libcrbtree_private = static_library(
'crbtree-private',
libcrbtree_both = both_libraries(
'crbtree-'+major,
[
'c-rbtree.c',
],
@ -18,26 +18,19 @@ libcrbtree_private = static_library(
'-fno-common',
],
dependencies: libcrbtree_deps,
pic: true,
)
libcrbtree_shared = shared_library(
'crbtree',
objects: libcrbtree_private.extract_all_objects(),
dependencies: libcrbtree_deps,
install: not meson.is_subproject(),
soversion: 0,
link_depends: libcrbtree_symfile,
link_args: [
'-Wl,--no-undefined',
'-Wl,--version-script=@0@'.format(libcrbtree_symfile),
],
link_depends: libcrbtree_symfile,
soversion: 0,
)
libcrbtree_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: libcrbtree_private,
dependencies: libcrbtree_deps,
include_directories: include_directories('.'),
link_with: libcrbtree_both.get_static_lib(),
version: meson.project_version(),
)
@ -45,11 +38,11 @@ if not meson.is_subproject()
install_headers('c-rbtree.h')
mod_pkgconfig.generate(
libraries: libcrbtree_shared,
version: meson.project_version(),
name: 'libcrbtree',
filebase: 'libcrbtree',
description: project_description,
filebase: 'libcrbtree-'+major,
libraries: libcrbtree_both.get_shared_lib(),
name: 'libcrbtree',
version: meson.project_version(),
)
endif
@ -57,7 +50,7 @@ endif
# target: test-*
#
test_api = executable('test-api', ['test-api.c'], link_with: libcrbtree_shared)
test_api = executable('test-api', ['test-api.c'], link_with: libcrbtree_both.get_shared_lib())
test('API Symbol Visibility', test_api)
test_basic = executable('test-basic', ['test-basic.c'], dependencies: libcrbtree_dep)
@ -70,7 +63,9 @@ test_misc = executable('test-misc', ['test-misc.c'], dependencies: libcrbtree_de
test('Miscellaneous', test_misc)
test_parallel = executable('test-parallel', ['test-parallel.c'], dependencies: libcrbtree_dep)
test('Lockless Parallel Readers', test_parallel)
if use_ptrace
test('Lockless Parallel Readers', test_parallel)
endif
test_posix = executable('test-posix', ['test-posix.c'], dependencies: libcrbtree_dep)
test('Posix tsearch(3p) Comparison', test_posix)

View file

@ -364,9 +364,6 @@ int main(int argc, char **argv) {
unsigned int i;
int r;
if (!getenv("CRBTREE_TEST_PTRACE"))
return 77;
/* we want stable tests, so use fixed seed */
srand(0xdeadbeef);

@ -1 +0,0 @@
Subproject commit c5f166d02ff68af5cdcbad1bdcea2cb134e34ce4

View file

@ -0,0 +1,3 @@
[wrap-git]
url = https://github.com/c-util/c-stdaux.git
revision = v1

View file

@ -9,13 +9,9 @@ on:
jobs:
ci:
name: CI with Default Configuration
runs-on: ubuntu-latest
steps:
- name: Fetch Sources
uses: actions/checkout@v2
- name: Run through C-Util CI
uses: c-util/automation/src/ci-c-util@v1
with:
m32: 1
valgrind: 1
uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
with:
cabuild_ref: "v1"
m32: true
matrixmode: true
valgrind: true

View file

@ -1,3 +0,0 @@
[submodule "subprojects/c-stdaux"]
path = subprojects/c-stdaux
url = https://github.com/c-util/c-stdaux.git

View file

@ -30,7 +30,7 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
Copyright (C) 2015-2019 Red Hat, Inc.
Copyright (C) 2015-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>

View file

@ -21,7 +21,7 @@ The requirements for this project are:
At build-time, the following software is required:
* `meson >= 0.41`
* `meson >= 0.60`
* `pkg-config >= 0.29`
### Build

View file

@ -1,19 +1,21 @@
project(
'c-siphash',
'c',
version: '1',
license: 'Apache',
default_options: [
'c_std=c11'
],
license: 'Apache',
meson_version: '>=0.60.0',
version: '1.0.0',
)
major = meson.project_version().split('.')[0]
project_description = 'Streaming-capable SipHash Implementation'
add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
sub_cstdaux = subproject('c-stdaux')
dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep')
dep_cstdaux = dependency('libcstdaux-1')
add_project_arguments(dep_cstdaux.get_variable('cflags').split(' '), language: 'c')
subdir('src')
meson.override_dependency('libcsiphash-'+major, libcsiphash_dep, static: true)

View file

@ -8,8 +8,8 @@ libcsiphash_deps = [
dep_cstdaux,
]
libcsiphash_private = static_library(
'csiphash-private',
libcsiphash_both = both_libraries(
'csiphash-'+major,
[
'c-siphash.c',
],
@ -18,26 +18,19 @@ libcsiphash_private = static_library(
'-fno-common',
],
dependencies: libcsiphash_deps,
pic: true,
)
libcsiphash_shared = shared_library(
'csiphash',
objects: libcsiphash_private.extract_all_objects(),
dependencies: libcsiphash_deps,
install: not meson.is_subproject(),
soversion: 0,
link_depends: libcsiphash_symfile,
link_args: [
'-Wl,--no-undefined',
'-Wl,--version-script=@0@'.format(libcsiphash_symfile),
],
link_depends: libcsiphash_symfile,
soversion: 0,
)
libcsiphash_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: libcsiphash_private,
dependencies: libcsiphash_deps,
include_directories: include_directories('.'),
link_with: libcsiphash_both.get_static_lib(),
version: meson.project_version(),
)
@ -45,11 +38,11 @@ if not meson.is_subproject()
install_headers('c-siphash.h')
mod_pkgconfig.generate(
libraries: libcsiphash_shared,
version: meson.project_version(),
name: 'libcsiphash',
filebase: 'libcsiphash',
description: project_description,
filebase: 'libcsiphash-'+major,
libraries: libcsiphash_both.get_shared_lib(),
name: 'libcsiphash',
version: meson.project_version(),
)
endif
@ -57,7 +50,7 @@ endif
# target: test-*
#
test_api = executable('test-api', ['test-api.c'], link_with: libcsiphash_shared)
test_api = executable('test-api', ['test-api.c'], link_with: libcsiphash_both.get_shared_lib())
test('API Symbol Visibility', test_api)
test_basic = executable('test-basic', ['test-basic.c'], dependencies: libcsiphash_dep)

@ -1 +0,0 @@
Subproject commit c5f166d02ff68af5cdcbad1bdcea2cb134e34ce4

View file

@ -0,0 +1,3 @@
[wrap-git]
url = https://github.com/c-util/c-stdaux.git
revision = v1

View file

@ -9,13 +9,9 @@ on:
jobs:
ci:
name: CI with Default Configuration
runs-on: ubuntu-latest
steps:
- name: Fetch Sources
uses: actions/checkout@v2
- name: Run through C-Util CI
uses: c-util/automation/src/ci-c-util@v1
with:
m32: 1
valgrind: 1
uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
with:
cabuild_ref: "v1"
m32: true
matrixmode: true
valgrind: true

View file

@ -30,7 +30,7 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
Copyright (C) 2018-2019 Red Hat, Inc.
Copyright (C) 2018-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>

View file

@ -21,7 +21,7 @@ The requirements for this project are:
At build-time, the following software is required:
* `meson >= 0.41`
* `meson >= 0.60`
* `pkg-config >= 0.29`
### Build

View file

@ -1,15 +1,86 @@
project(
'c-stdaux',
'c',
version: '1',
license: 'Apache',
default_options: [
'c_std=c11'
],
license: 'Apache',
meson_version: '>=0.60.0',
version: '1.0.0',
)
major = meson.project_version().split('.')[0]
project_description = 'Auxiliary macros and functions for the C standard library'
add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
#
# CFLAGS
#
# We have a set of compiler flags for GCC and CLANG which adjust their warnings
# and behavior to our coding-style.
#
# This variable is exported to dependent projects via meson for them to use as
# well. Since these exports are limited to strings, we need to be careful that
# the individual entries do not contain spaces (see the assertion below).
#
cflags = meson.get_compiler('c').get_supported_arguments(
# Enable GNU features of our dependencies. See feature_test_macros(7).
'-D_GNU_SOURCE',
# Prevent CLANG from complaining that alignof-expressions are GNU-only.
'-Wno-gnu-alignof-expression',
# Never complain about *MAYBE* uninit variables. This is very flaky and
# produces bogus results with LTO.
'-Wno-maybe-uninitialized',
# Do not complain about unknown GCC/CLANG warnings.
'-Wno-unknown-warning-option',
# There is no standardized way to mark unused arguments, so never
# complain about them.
'-Wno-unused-parameter',
# Preprocessor evaluations often lead to warnings about comparisons
# that are always true/false. Make sure they do not break a build but
# keep them on for diagnostics.
'-Wno-error=type-limits',
# As we use designated field-initializers, this warning should never
# trigger, but still does on GCC in combination with some other
# preprocessor checks. Lets just make sure it does not break builds.
'-Wno-error=missing-field-initializers',
# Warn if we ever use `__DATE__` and similar in our build. We want
# reproducible builds.
'-Wdate-time',
# We strictly follow decl-before-statements, so check it.
'-Wdeclaration-after-statement',
# More strict logical-op sanity checks.
'-Wlogical-op',
# Loudly complain about missing include-directories.
'-Wmissing-include-dirs',
# We want hints about noreturn functions, so warn about them.
'-Wmissing-noreturn',
# Warn if an extern-decl is inside a function. We want imports as
# global attributes, never as local ones.
'-Wnested-externs',
# Warn about redundant declarations. We want declarations in headers
# and want them to be unique.
'-Wredundant-decls',
# Warn about shadowed variables so we do not accidentally override
# variables of parent scopes and thus confuse macros.
'-Wshadow',
# Warn about aliasing violations. Level-3 produces the least false
# positives, but is the slowest. Force it to avoid breaking -Werror
# builds.
'-Wstrict-aliasing=3',
# Suggest 'noreturn' attributes. They are useful, we want them!
'-Wsuggest-attribute=noreturn',
# Warn about undefined identifiers in preprocessor conditionals.
'-Wundef',
# Make sure literal strings are considered 'const'.
'-Wwrite-strings',
)
assert(not ''.join(cflags).contains(' '), 'Malformed compiler flags.')
add_project_arguments(cflags, language: 'c')
subdir('src')
meson.override_dependency('libcstdaux-'+major, libcstdaux_dep, static: true)

View file

@ -6,6 +6,7 @@
libcstdaux_dep = declare_dependency(
include_directories: include_directories('.'),
variables: { 'cflags': ' '.join(cflags) },
version: meson.project_version(),
)
@ -13,10 +14,10 @@ if not meson.is_subproject()
install_headers('c-stdaux.h')
mod_pkgconfig.generate(
version: meson.project_version(),
name: 'libcstdaux',
filebase: 'libcstdaux',
description: project_description,
filebase: 'libcstdaux-'+major,
name: 'libcstdaux',
version: meson.project_version(),
)
endif

View file

@ -359,7 +359,7 @@ static void test_destructors(void) {
/* make sure c_closep() deals fine with negative FDs */
{
_c_cleanup_(c_closep) int t = 0;
_c_cleanup_(c_closep) _c_unused_ int t = 0;
t = -1;
}
@ -370,7 +370,7 @@ static void test_destructors(void) {
* path works as well.
*/
for (i = 0; i < 2; ++i) {
_c_cleanup_(c_closep) int t = -1;
_c_cleanup_(c_closep) _c_unused_ int t = -1;
t = eventfd(0, EFD_CLOEXEC);
c_assert(t >= 0);
@ -401,7 +401,7 @@ static void test_destructors(void) {
/* make sure c_flosep() deals fine with NULL */
{
_c_cleanup_(c_fclosep) FILE *t = (void *)0xdeadbeef;
_c_cleanup_(c_fclosep) _c_unused_ FILE *t = (void *)0xdeadbeef;
t = NULL;
}
@ -412,7 +412,7 @@ static void test_destructors(void) {
* path works as well.
*/
for (i = 0; i < 2; ++i) {
_c_cleanup_(c_fclosep) FILE *t = NULL;
_c_cleanup_(c_fclosep) _c_unused_ FILE *t = NULL;
int tfd;
tfd = eventfd(0, EFD_CLOEXEC);

View file

@ -30,7 +30,6 @@
#include "libnm-platform/nm-linux-platform.h"
#include "libnm-platform/nm-platform-utils.h"
#include "nm-auth-utils.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
/*****************************************************************************/
@ -1155,7 +1154,7 @@ nm_utils_file_is_in_path(const char *abs_filename, const char *abs_path)
g_return_val_if_fail(abs_filename && abs_filename[0] == '/', NULL);
g_return_val_if_fail(abs_path && abs_path[0] == '/', NULL);
path = nm_sd_utils_path_startswith(abs_filename, abs_path);
path = nm_path_startswith(abs_filename, abs_path);
if (!path)
return NULL;

View file

@ -312,7 +312,7 @@ set_bond_attr_or_default(NMDevice *device, NMSettingBond *s_bond, const char *op
NMDeviceBond *self = NM_DEVICE_BOND(device);
const char *value;
value = nm_setting_bond_get_option_or_default(s_bond, opt);
value = nm_setting_bond_get_option_normalized(s_bond, opt);
if (!value) {
if (_LOGT_ENABLED(LOGD_BOND) && nm_setting_bond_get_option_by_name(s_bond, opt))
_LOGT(LOGD_BOND, "bond option '%s' not set as it conflicts with other options", opt);
@ -346,7 +346,7 @@ set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond)
set_arp_targets(
device,
cur_arp_ip_target,
nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
}
static gboolean
@ -361,7 +361,7 @@ apply_bonding_config(NMDeviceBond *self)
s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND);
g_return_val_if_fail(s_bond, FALSE);
mode_str = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE);
mode_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
mode = _nm_setting_bond_mode_from_string(mode_str);
g_return_val_if_fail(mode != NM_BOND_MODE_UNKNOWN, FALSE);
@ -424,8 +424,14 @@ commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_
queue_id_str);
}
static gboolean
enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
static NMTernary
attach_port(NMDevice *device,
NMDevice *port,
NMConnection *connection,
gboolean configure,
GCancellable *cancellable,
NMDeviceAttachPortCallback callback,
gpointer user_data)
{
NMDeviceBond *self = NM_DEVICE_BOND(device);
NMSettingBondPort *s_port;
@ -442,7 +448,7 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole
nm_device_bring_up(port, TRUE, NULL);
if (!success) {
_LOGI(LOGD_BOND, "assigning bond port %s: failed", nm_device_get_ip_iface(port));
_LOGI(LOGD_BOND, "attaching bond port %s: failed", nm_device_get_ip_iface(port));
return FALSE;
}
@ -450,15 +456,15 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole
commit_port_options(device, port, s_port);
_LOGI(LOGD_BOND, "assigned bond port %s", nm_device_get_ip_iface(port));
_LOGI(LOGD_BOND, "attached bond port %s", nm_device_get_ip_iface(port));
} else
_LOGI(LOGD_BOND, "bond port %s was assigned", nm_device_get_ip_iface(port));
_LOGI(LOGD_BOND, "bond port %s was attached", nm_device_get_ip_iface(port));
return TRUE;
}
static void
release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceBond *self = NM_DEVICE_BOND(device);
gboolean success;
@ -472,10 +478,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
configure = FALSE;
}
ifindex_slave = nm_device_get_ip_ifindex(slave);
ifindex_slave = nm_device_get_ip_ifindex(port);
if (ifindex_slave <= 0)
_LOGD(LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface(slave));
_LOGD(LOGD_BOND, "bond port %s is already detached", nm_device_get_ip_iface(port));
if (configure) {
NMConnection *applied;
@ -490,9 +496,9 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
ifindex_slave);
if (success) {
_LOGI(LOGD_BOND, "released bond slave %s", nm_device_get_ip_iface(slave));
_LOGI(LOGD_BOND, "detached bond port %s", nm_device_get_ip_iface(port));
} else {
_LOGW(LOGD_BOND, "failed to release bond slave %s", nm_device_get_ip_iface(slave));
_LOGW(LOGD_BOND, "failed to detach bond port %s", nm_device_get_ip_iface(port));
}
}
@ -512,12 +518,12 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
* other state is noticed by the now-released slave.
*/
if (ifindex_slave > 0) {
if (!nm_device_bring_up(slave, TRUE, NULL))
_LOGW(LOGD_BOND, "released bond slave could not be brought up.");
if (!nm_device_bring_up(port, TRUE, NULL))
_LOGW(LOGD_BOND, "detached bond port could not be brought up.");
}
} else {
if (ifindex_slave > 0) {
_LOGI(LOGD_BOND, "bond slave %s was released", nm_device_get_ip_iface(slave));
_LOGI(LOGD_BOND, "bond port %s was detached", nm_device_get_ip_iface(port));
}
}
}
@ -612,7 +618,7 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne
s_bond = nm_connection_get_setting_bond(con_new);
g_return_if_fail(s_bond);
value = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE);
value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
mode = _nm_setting_bond_mode_from_string(value);
g_return_if_fail(mode != NM_BOND_MODE_UNKNOWN);
@ -663,8 +669,8 @@ nm_device_bond_class_init(NMDeviceBondClass *klass)
device_class->create_and_realize = create_and_realize;
device_class->act_stage1_prepare = act_stage1_prepare;
device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
device_class->enslave_slave = enslave_slave;
device_class->release_slave = release_slave;
device_class->attach_port = attach_port;
device_class->detach_port = detach_port;
device_class->can_reapply_change = can_reapply_change;
device_class->reapply_connection = reapply_connection;
}

View file

@ -974,8 +974,14 @@ deactivate(NMDevice *device)
}
}
static gboolean
enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
static NMTernary
attach_port(NMDevice *device,
NMDevice *port,
NMConnection *connection,
gboolean configure,
GCancellable *cancellable,
NMDeviceAttachPortCallback callback,
gpointer user_data)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE(device);
NMConnection *master_connection;
@ -985,7 +991,7 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
if (configure) {
if (!nm_platform_link_enslave(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
nm_device_get_ip_ifindex(slave)))
nm_device_get_ip_ifindex(port)))
return FALSE;
master_connection = nm_device_get_applied_connection(device);
@ -1009,25 +1015,25 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
* (except for the default one) and so there's no need to flush. */
if (plat_vlans
&& !nm_platform_link_set_bridge_vlans(nm_device_get_platform(slave),
nm_device_get_ifindex(slave),
&& !nm_platform_link_set_bridge_vlans(nm_device_get_platform(port),
nm_device_get_ifindex(port),
TRUE,
plat_vlans))
return FALSE;
}
commit_slave_options(slave, s_port);
commit_slave_options(port, s_port);
_LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(slave));
_LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(port));
} else {
_LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(slave));
_LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(port));
}
return TRUE;
}
static void
release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE(device);
gboolean success;
@ -1040,10 +1046,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
configure = FALSE;
}
ifindex_slave = nm_device_get_ip_ifindex(slave);
ifindex_slave = nm_device_get_ip_ifindex(port);
if (ifindex_slave <= 0) {
_LOGD(LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface(slave));
_LOGD(LOGD_TEAM, "bridge port %s is already detached", nm_device_get_ip_iface(port));
return;
}
@ -1053,12 +1059,12 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
ifindex_slave);
if (success) {
_LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(slave));
_LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(port));
} else {
_LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(slave));
_LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(port));
}
} else {
_LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(slave));
_LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(port));
}
}
@ -1084,10 +1090,6 @@ create_and_realize(NMDevice *device,
s_bridge = nm_connection_get_setting_bridge(connection);
nm_assert(s_bridge);
s_wired = nm_connection_get_setting_wired(connection);
if (s_wired)
mtu = nm_setting_wired_get_mtu(s_wired);
hwaddr = nm_setting_bridge_get_mac_address(s_bridge);
if (!hwaddr
&& nm_device_hw_addr_get_cloned(device, connection, FALSE, &hwaddr_cloned, NULL, NULL)) {
@ -1112,6 +1114,11 @@ create_and_realize(NMDevice *device,
_platform_lnk_bridge_init_from_setting(s_bridge, &props);
s_wired = nm_connection_get_setting_wired(connection);
nm_assert(s_wired);
mtu = nm_setting_wired_get_mtu(s_wired);
/* If mtu != 0, we set the MTU of the new bridge at creation time. However, kernel will still
* automatically adjust the MTU of the bridge based on the minimum of the slave's MTU.
* We don't want this automatism as the user asked for a fixed MTU.
@ -1182,8 +1189,8 @@ nm_device_bridge_class_init(NMDeviceBridgeClass *klass)
device_class->act_stage1_prepare = act_stage1_prepare;
device_class->act_stage2_config = act_stage2_config;
device_class->deactivate = deactivate;
device_class->enslave_slave = enslave_slave;
device_class->release_slave = release_slave;
device_class->attach_port = attach_port;
device_class->detach_port = detach_port;
device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
}

View file

@ -206,38 +206,44 @@ update_connection(NMDevice *device, NMConnection *connection)
g_object_set(G_OBJECT(s_vrf), NM_SETTING_VRF_TABLE, priv->props.table, NULL);
}
static gboolean
enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
static NMTernary
attach_port(NMDevice *device,
NMDevice *port,
NMConnection *connection,
gboolean configure,
GCancellable *cancellable,
NMDeviceAttachPortCallback callback,
gpointer user_data)
{
NMDeviceVrf *self = NM_DEVICE_VRF(device);
gboolean success = TRUE;
const char *slave_iface = nm_device_get_ip_iface(slave);
NMDeviceVrf *self = NM_DEVICE_VRF(device);
gboolean success = TRUE;
const char *port_iface = nm_device_get_ip_iface(port);
nm_device_master_check_slave_physical_port(device, slave, LOGD_DEVICE);
nm_device_master_check_slave_physical_port(device, port, LOGD_DEVICE);
if (configure) {
nm_device_take_down(slave, TRUE);
nm_device_take_down(port, TRUE);
success = nm_platform_link_enslave(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
nm_device_get_ip_ifindex(slave));
nm_device_bring_up(slave, TRUE, NULL);
nm_device_get_ip_ifindex(port));
nm_device_bring_up(port, TRUE, NULL);
if (!success)
return FALSE;
_LOGI(LOGD_DEVICE, "enslaved VRF slave %s", slave_iface);
_LOGI(LOGD_DEVICE, "attached VRF port %s", port_iface);
} else
_LOGI(LOGD_BOND, "VRF slave %s was enslaved", slave_iface);
_LOGI(LOGD_BOND, "VRF port %s was attached", port_iface);
return TRUE;
}
static void
release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceVrf *self = NM_DEVICE_VRF(device);
gboolean success;
int ifindex_slave;
int ifindex_port;
int ifindex;
if (configure) {
@ -246,26 +252,26 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
configure = FALSE;
}
ifindex_slave = nm_device_get_ip_ifindex(slave);
ifindex_port = nm_device_get_ip_ifindex(port);
if (ifindex_slave <= 0)
_LOGD(LOGD_DEVICE, "VRF slave %s is already released", nm_device_get_ip_iface(slave));
if (ifindex_port <= 0)
_LOGD(LOGD_DEVICE, "VRF port %s is already detached", nm_device_get_ip_iface(port));
if (configure) {
if (ifindex_slave > 0) {
if (ifindex_port > 0) {
success = nm_platform_link_release(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
ifindex_slave);
ifindex_port);
if (success) {
_LOGI(LOGD_DEVICE, "released VRF slave %s", nm_device_get_ip_iface(slave));
_LOGI(LOGD_DEVICE, "detached VRF port %s", nm_device_get_ip_iface(port));
} else {
_LOGW(LOGD_DEVICE, "failed to release VRF slave %s", nm_device_get_ip_iface(slave));
_LOGW(LOGD_DEVICE, "failed to detach VRF port %s", nm_device_get_ip_iface(port));
}
}
} else {
if (ifindex_slave > 0) {
_LOGI(LOGD_DEVICE, "VRF slave %s was released", nm_device_get_ip_iface(slave));
if (ifindex_port > 0) {
_LOGI(LOGD_DEVICE, "VRF port %s was detached", nm_device_get_ip_iface(port));
}
}
}
@ -316,8 +322,8 @@ nm_device_vrf_class_init(NMDeviceVrfClass *klass)
device_class->is_master = TRUE;
device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_VRF);
device_class->enslave_slave = enslave_slave;
device_class->release_slave = release_slave;
device_class->attach_port = attach_port;
device_class->detach_port = detach_port;
device_class->link_changed = link_changed;
device_class->unrealize_notify = unrealize_notify;
device_class->create_and_realize = create_and_realize;

View file

@ -120,11 +120,12 @@ typedef enum _nm_packed {
} AddrMethodState;
typedef struct {
CList lst_slave;
NMDevice *slave;
gulong watch_id;
bool slave_is_enslaved;
bool configure;
CList lst_slave;
NMDevice *slave;
GCancellable *cancellable;
gulong watch_id;
bool slave_is_enslaved;
bool configure;
} SlaveInfo;
typedef struct {
@ -604,6 +605,7 @@ typedef struct _NMDevicePrivate {
const NMDeviceIPState state;
NMDeviceIPState state_;
};
gulong dnsmgr_update_pending_signal_id;
} ip_data;
union {
@ -2929,6 +2931,13 @@ _add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities)
/*****************************************************************************/
static void
_dev_ip_state_dnsmgr_update_pending_changed(NMDnsManager *dnsmgr, GParamSpec *pspec, NMDevice *self)
{
_dev_ip_state_check(self, AF_INET);
_dev_ip_state_check(self, AF_INET6);
}
static void
_dev_ip_state_req_timeout_cancel(NMDevice *self, int addr_family)
{
@ -3321,6 +3330,27 @@ got_ip_state:
combinedip_state = priv->ip_data.state;
}
if (combinedip_state == NM_DEVICE_IP_STATE_READY
&& priv->ip_data.state <= NM_DEVICE_IP_STATE_PENDING
&& nm_dns_manager_get_update_pending(nm_manager_get_dns_manager(priv->manager))) {
/* We would be ready, but a DNS update is pending. That prevents us from getting fully ready. */
if (priv->ip_data.dnsmgr_update_pending_signal_id == 0) {
priv->ip_data.dnsmgr_update_pending_signal_id =
g_signal_connect(nm_manager_get_dns_manager(priv->manager),
"notify::" NM_DNS_MANAGER_UPDATE_PENDING,
G_CALLBACK(_dev_ip_state_dnsmgr_update_pending_changed),
self);
_LOGT_ip(AF_UNSPEC,
"check-state: (combined) state: wait for DNS before becoming ready");
}
combinedip_state = NM_DEVICE_IP_STATE_PENDING;
}
if (combinedip_state != NM_DEVICE_IP_STATE_PENDING
&& priv->ip_data.dnsmgr_update_pending_signal_id != 0) {
nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager),
&priv->ip_data.dnsmgr_update_pending_signal_id);
}
_LOGT_ip(AF_UNSPEC,
"check-state: (combined) state %s => %s",
nm_device_ip_state_to_string(priv->ip_data.state),
@ -5898,43 +5928,16 @@ find_slave_info(NMDevice *self, NMDevice *slave)
return NULL;
}
/**
* nm_device_master_enslave_slave:
* @self: the master device
* @slave: the slave device to enslave
* @connection: (allow-none): the slave device's connection
*
* If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function enslaves @slave.
*
* Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave
* other devices.
*/
static gboolean
nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection)
static void
attach_port_done(NMDevice *self, NMDevice *slave, gboolean success)
{
SlaveInfo *info;
gboolean success = FALSE;
gboolean configure;
g_return_val_if_fail(self != NULL, FALSE);
g_return_val_if_fail(slave != NULL, FALSE);
g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE);
info = find_slave_info(self, slave);
if (!info)
return FALSE;
return;
if (info->slave_is_enslaved)
success = TRUE;
else {
configure = (info->configure && connection != NULL);
if (configure)
g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE);
success = NM_DEVICE_GET_CLASS(self)->enslave_slave(self, slave, connection, configure);
info->slave_is_enslaved = success;
}
info->slave_is_enslaved = success;
nm_device_slave_notify_enslave(info->slave, success);
@ -5954,8 +5957,71 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co
*/
if (success)
nm_device_activate_schedule_stage3_ip_config(self, FALSE);
}
return success;
static void
attach_port_cb(NMDevice *self, GError *error, gpointer user_data)
{
NMDevice *slave = user_data;
SlaveInfo *info;
if (nm_utils_error_is_cancelled(error))
return;
info = find_slave_info(self, slave);
if (!info)
return;
nm_clear_g_cancellable(&info->cancellable);
attach_port_done(self, slave, !error);
}
/**
* nm_device_master_enslave_slave:
* @self: the master device
* @slave: the slave device to enslave
* @connection: (allow-none): the slave device's connection
*
* If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function enslaves @slave.
*/
static void
nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection)
{
SlaveInfo *info;
NMTernary success;
gboolean configure;
g_return_if_fail(self);
g_return_if_fail(slave);
g_return_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port);
info = find_slave_info(self, slave);
if (!info)
return;
if (info->slave_is_enslaved)
success = TRUE;
else {
configure = (info->configure && connection != NULL);
if (configure)
g_return_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED);
nm_clear_g_cancellable(&info->cancellable);
info->cancellable = g_cancellable_new();
success = NM_DEVICE_GET_CLASS(self)->attach_port(self,
slave,
connection,
configure,
info->cancellable,
attach_port_cb,
slave);
if (success == NM_TERNARY_DEFAULT)
return;
}
attach_port_done(self, slave, success);
}
/**
@ -5988,7 +6054,7 @@ nm_device_master_release_slave(NMDevice *self,
RELEASE_SLAVE_TYPE_NO_CONFIG,
RELEASE_SLAVE_TYPE_CONFIG,
RELEASE_SLAVE_TYPE_CONFIG_FORCE));
g_return_if_fail(NM_DEVICE_GET_CLASS(self)->release_slave != NULL);
g_return_if_fail(NM_DEVICE_GET_CLASS(self)->detach_port != NULL);
info = find_slave_info(self, slave);
@ -6009,13 +6075,14 @@ nm_device_master_release_slave(NMDevice *self,
g_return_if_fail(self == slave_priv->master);
nm_assert(slave == info->slave);
nm_clear_g_cancellable(&info->cancellable);
/* first, let subclasses handle the release ... */
if (info->slave_is_enslaved || nm_device_sys_iface_state_is_external(slave)
|| release_type >= RELEASE_SLAVE_TYPE_CONFIG_FORCE)
NM_DEVICE_GET_CLASS(self)->release_slave(self,
slave,
release_type >= RELEASE_SLAVE_TYPE_CONFIG);
NM_DEVICE_GET_CLASS(self)->detach_port(self,
slave,
release_type >= RELEASE_SLAVE_TYPE_CONFIG);
/* raise notifications about the release, including clearing is_enslaved. */
nm_device_slave_notify_release(slave, reason);
@ -6356,7 +6423,7 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink)
NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
}
if (master && NM_DEVICE_GET_CLASS(master)->enslave_slave) {
if (master && NM_DEVICE_GET_CLASS(master)->attach_port) {
nm_device_master_add_slave(master, self, FALSE);
goto out;
}
@ -7581,7 +7648,7 @@ nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure)
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
g_return_val_if_fail(NM_IS_DEVICE(slave), FALSE);
g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE);
g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port, FALSE);
priv = NM_DEVICE_GET_PRIVATE(self);
slave_priv = NM_DEVICE_GET_PRIVATE(slave);
@ -10036,6 +10103,7 @@ _dev_ipdhcpx_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_d
FALSE);
if (notify_data->lease_update.accepted) {
nm_manager_write_device_state(priv->manager, self, NULL);
if (priv->ipdhcp_data_x[IS_IPv4].state != NM_DEVICE_IP_STATE_READY) {
_dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_READY);
nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP_CHANGE_X(IS_IPv4),
@ -12342,7 +12410,8 @@ delete_on_deactivate_check_and_schedule(NMDevice *self)
static void
_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply)
{
const int IS_IPv4 = NM_IS_IPv4(addr_family);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
_dev_ipsharedx_cleanup(self, addr_family);
@ -12358,6 +12427,9 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool
_dev_ipmanual_cleanup(self);
nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager),
&priv->ip_data.dnsmgr_update_pending_signal_id);
_dev_ip_state_cleanup(self, AF_UNSPEC, from_reapply);
_dev_ip_state_cleanup(self, addr_family, from_reapply);
}

View file

@ -163,6 +163,7 @@ typedef enum {
} NMDeviceCheckDevAvailableFlags;
typedef void (*NMDeviceDeactivateCallback)(NMDevice *self, GError *error, gpointer user_data);
typedef void (*NMDeviceAttachPortCallback)(NMDevice *self, GError *error, gpointer user_data);
typedef struct _NMDeviceClass {
NMDBusObjectClass parent;
@ -373,12 +374,18 @@ typedef struct _NMDeviceClass {
NMConnection *connection,
GError **error);
gboolean (*enslave_slave)(NMDevice *self,
NMDevice *slave,
NMConnection *connection,
gboolean configure);
void (*release_slave)(NMDevice *self, NMDevice *slave, gboolean configure);
/* Attachs a port asynchronously. Returns TRUE/FALSE on immediate
* success/error; in such cases, the callback is not invoked. If the
* action couldn't be completed immediately, DEFAULT is returned and
* the callback will always be invoked asynchronously. */
NMTernary (*attach_port)(NMDevice *self,
NMDevice *port,
NMConnection *connection,
gboolean configure,
GCancellable *cancellable,
NMDeviceAttachPortCallback callback,
gpointer user_data);
void (*detach_port)(NMDevice *self, NMDevice *port, gboolean configure);
void (*parent_changed_notify)(NMDevice *self,
int old_ifindex,

View file

@ -78,20 +78,26 @@ act_stage3_ip_config(NMDevice *device, int addr_family)
nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL);
}
static gboolean
enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
static NMTernary
attach_port(NMDevice *device,
NMDevice *port,
NMConnection *connection,
gboolean configure,
GCancellable *cancellable,
NMDeviceAttachPortCallback callback,
gpointer user_data)
{
if (!configure)
return TRUE;
if (!NM_IS_DEVICE_OVS_PORT(slave))
if (!NM_IS_DEVICE_OVS_PORT(port))
return FALSE;
return TRUE;
}
static void
release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{}
void
@ -159,8 +165,8 @@ nm_device_ovs_bridge_class_init(NMDeviceOvsBridgeClass *klass)
device_class->get_generic_capabilities = get_generic_capabilities;
device_class->act_stage3_ip_config = act_stage3_ip_config;
device_class->ready_for_ip_config = ready_for_ip_config;
device_class->enslave_slave = enslave_slave;
device_class->release_slave = release_slave;
device_class->attach_port = attach_port;
device_class->detach_port = detach_port;
device_class->can_reapply_change_ovs_external_ids = TRUE;
device_class->reapply_connection = nm_device_ovs_reapply_connection;
}

View file

@ -72,20 +72,42 @@ act_stage3_ip_config(NMDevice *device, int addr_family)
nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL);
}
typedef struct {
NMDevice *device;
NMDevice *port;
GCancellable *cancellable;
NMDeviceAttachPortCallback callback;
gpointer callback_user_data;
} AttachPortData;
static void
add_iface_cb(GError *error, gpointer user_data)
{
NMDevice *slave = user_data;
AttachPortData *data = user_data;
NMDeviceOvsPort *self;
gs_free_error GError *local = NULL;
if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) {
nm_log_warn(LOGD_DEVICE,
"device %s could not be added to a ovs port: %s",
nm_device_get_iface(slave),
error->message);
nm_device_state_changed(slave, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED);
if (g_cancellable_is_cancelled(data->cancellable)) {
local = nm_utils_error_new_cancelled(FALSE, NULL);
error = local;
} else if (error && !nm_utils_error_is_cancelled_or_disposing(error)) {
self = NM_DEVICE_OVS_PORT(data->device);
_LOGW(LOGD_DEVICE,
"device %s could not be added to a ovs port: %s",
nm_device_get_iface(data->port),
error->message);
nm_device_state_changed(data->port,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_OVSDB_FAILED);
}
g_object_unref(slave);
data->callback(data->device, error, data->callback_user_data);
g_object_unref(data->device);
g_object_unref(data->port);
nm_clear_g_cancellable(&data->cancellable);
nm_g_slice_free(data);
}
static gboolean
@ -115,14 +137,21 @@ set_mtu_cb(GError *error, gpointer user_data)
g_object_unref(self);
}
static gboolean
enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
static NMTernary
attach_port(NMDevice *device,
NMDevice *port,
NMConnection *connection,
gboolean configure,
GCancellable *cancellable,
NMDeviceAttachPortCallback callback,
gpointer user_data)
{
NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
NMActiveConnection *ac_port = NULL;
NMActiveConnection *ac_bridge = NULL;
NMDevice *bridge_device;
NMSettingWired *s_wired;
AttachPortData *data;
if (!configure)
return TRUE;
@ -131,42 +160,49 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
ac_bridge = nm_active_connection_get_master(ac_port);
if (!ac_bridge) {
_LOGW(LOGD_DEVICE,
"can't enslave %s: bridge active-connection not found",
nm_device_get_iface(slave));
"can't attach %s: bridge active-connection not found",
nm_device_get_iface(port));
return FALSE;
}
bridge_device = nm_active_connection_get_device(ac_bridge);
if (!bridge_device) {
_LOGW(LOGD_DEVICE, "can't enslave %s: bridge device not found", nm_device_get_iface(slave));
_LOGW(LOGD_DEVICE, "can't attach %s: bridge device not found", nm_device_get_iface(port));
return FALSE;
}
data = g_slice_new(AttachPortData);
*data = (AttachPortData){
.device = g_object_ref(device),
.port = g_object_ref(port),
.cancellable = g_object_ref(cancellable),
.callback = callback,
.callback_user_data = user_data,
};
nm_ovsdb_add_interface(nm_ovsdb_get(),
nm_active_connection_get_applied_connection(ac_bridge),
nm_device_get_applied_connection(device),
nm_device_get_applied_connection(slave),
nm_device_get_applied_connection(port),
bridge_device,
slave,
port,
add_iface_cb,
g_object_ref(slave));
data);
/* DPDK ports does not have a link after the devbind, so the MTU must be
* set on ovsdb after adding the interface. */
if (NM_IS_DEVICE_OVS_INTERFACE(slave) && _ovs_interface_is_dpdk(slave)) {
s_wired = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_WIRED);
if (!s_wired || !nm_setting_wired_get_mtu(s_wired))
return TRUE;
nm_ovsdb_set_interface_mtu(nm_ovsdb_get(),
nm_device_get_ip_iface(slave),
nm_setting_wired_get_mtu(s_wired),
set_mtu_cb,
g_object_ref(slave));
if (NM_IS_DEVICE_OVS_INTERFACE(port) && _ovs_interface_is_dpdk(port)) {
s_wired = nm_device_get_applied_setting(port, NM_TYPE_SETTING_WIRED);
if (s_wired && nm_setting_wired_get_mtu(s_wired)) {
nm_ovsdb_set_interface_mtu(nm_ovsdb_get(),
nm_device_get_ip_iface(port),
nm_setting_wired_get_mtu(s_wired),
set_mtu_cb,
g_object_ref(port));
}
}
return TRUE;
return NM_TERNARY_DEFAULT;
}
static void
@ -186,31 +222,31 @@ del_iface_cb(GError *error, gpointer user_data)
}
static void
release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
bool slave_not_managed = !NM_IN_SET(nm_device_sys_iface_state_get(slave),
NM_DEVICE_SYS_IFACE_STATE_MANAGED,
NM_DEVICE_SYS_IFACE_STATE_ASSUME);
NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
bool port_not_managed = !NM_IN_SET(nm_device_sys_iface_state_get(port),
NM_DEVICE_SYS_IFACE_STATE_MANAGED,
NM_DEVICE_SYS_IFACE_STATE_ASSUME);
_LOGI(LOGD_DEVICE, "releasing ovs interface %s", nm_device_get_ip_iface(slave));
_LOGI(LOGD_DEVICE, "detaching ovs interface %s", nm_device_get_ip_iface(port));
/* Even if the an interface's device has gone away (e.g. externally
* removed and thus we're called with configure=FALSE), we still need
* to make sure its OVSDB entry is gone.
*/
if (configure || slave_not_managed) {
if (configure || port_not_managed) {
nm_ovsdb_del_interface(nm_ovsdb_get(),
nm_device_get_iface(slave),
nm_device_get_iface(port),
del_iface_cb,
g_object_ref(slave));
g_object_ref(port));
}
if (configure) {
/* Open VSwitch is going to delete this one. We must ignore what happens
* next with the interface. */
if (NM_IS_DEVICE_OVS_INTERFACE(slave))
nm_device_update_from_platform_link(slave, NULL);
if (NM_IS_DEVICE_OVS_INTERFACE(port))
nm_device_update_from_platform_link(port, NULL);
}
}
@ -245,8 +281,8 @@ nm_device_ovs_port_class_init(NMDeviceOvsPortClass *klass)
device_class->get_generic_capabilities = get_generic_capabilities;
device_class->act_stage3_ip_config = act_stage3_ip_config;
device_class->ready_for_ip_config = ready_for_ip_config;
device_class->enslave_slave = enslave_slave;
device_class->release_slave = release_slave;
device_class->attach_port = attach_port;
device_class->detach_port = detach_port;
device_class->can_reapply_change_ovs_external_ids = TRUE;
device_class->reapply_connection = nm_device_ovs_reapply_connection;
}

View file

@ -376,6 +376,9 @@ ovsdb_call_method(NMOvsdb *self,
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
OvsdbMethodCall *call;
/* FIXME(shutdown): this function should accept a cancellable to
* interrupt the operation. */
/* Ensure we're not unsynchronized before we queue the method call. */
ovsdb_try_connect(self);
@ -1550,7 +1553,7 @@ _external_ids_to_string(const GArray *arr)
if (!arr)
return g_strdup("empty");
nm_str_buf_init(&strbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
nm_str_buf_append(&strbuf, "[");
for (i = 0; i < arr->len; i++) {
const NMUtilsNamedValue *n = &g_array_index(arr, NMUtilsNamedValue, i);

View file

@ -790,19 +790,25 @@ deactivate(NMDevice *device)
teamd_cleanup(self, TRUE);
}
static gboolean
enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
static NMTernary
attach_port(NMDevice *device,
NMDevice *port,
NMConnection *connection,
gboolean configure,
GCancellable *cancellable,
NMDeviceAttachPortCallback callback,
gpointer user_data)
{
NMDeviceTeam *self = NM_DEVICE_TEAM(device);
NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);
gboolean success = TRUE;
const char *slave_iface = nm_device_get_ip_iface(slave);
NMDeviceTeam *self = NM_DEVICE_TEAM(device);
NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);
gboolean success = TRUE;
const char *port_iface = nm_device_get_ip_iface(port);
NMSettingTeamPort *s_team_port;
nm_device_master_check_slave_physical_port(device, slave, LOGD_TEAM);
nm_device_master_check_slave_physical_port(device, port, LOGD_TEAM);
if (configure) {
nm_device_take_down(slave, TRUE);
nm_device_take_down(port, TRUE);
s_team_port = nm_connection_get_setting_team_port(connection);
if (s_team_port) {
@ -811,19 +817,19 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
if (config) {
if (!priv->tdc) {
_LOGW(LOGD_TEAM,
"enslaved team port %s config not changed, not connected to teamd",
slave_iface);
"attached team port %s config not changed, not connected to teamd",
port_iface);
} else {
gs_free char *sanitized_config = NULL;
int err;
sanitized_config = g_strdup(config);
g_strdelimit(sanitized_config, "\r\n", ' ');
err = teamdctl_port_config_update_raw(priv->tdc, slave_iface, sanitized_config);
err = teamdctl_port_config_update_raw(priv->tdc, port_iface, sanitized_config);
if (err != 0) {
_LOGE(LOGD_TEAM,
"failed to update config for port %s (err=%d)",
slave_iface,
port_iface,
err);
return FALSE;
}
@ -832,8 +838,8 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
}
success = nm_platform_link_enslave(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
nm_device_get_ip_ifindex(slave));
nm_device_bring_up(slave, TRUE, NULL);
nm_device_get_ip_ifindex(port));
nm_device_bring_up(port, TRUE, NULL);
if (!success)
return FALSE;
@ -841,21 +847,21 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
nm_clear_g_source(&priv->teamd_read_timeout);
priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self);
_LOGI(LOGD_TEAM, "enslaved team port %s", slave_iface);
_LOGI(LOGD_TEAM, "attached team port %s", port_iface);
} else
_LOGI(LOGD_TEAM, "team port %s was enslaved", slave_iface);
_LOGI(LOGD_TEAM, "team port %s was attached", port_iface);
return TRUE;
}
static void
release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceTeam *self = NM_DEVICE_TEAM(device);
NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);
gboolean do_release, success;
NMSettingTeamPort *s_port;
int ifindex_slave;
int ifindex_port;
int ifindex;
do_release = configure;
@ -865,39 +871,39 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
do_release = FALSE;
}
ifindex_slave = nm_device_get_ip_ifindex(slave);
ifindex_port = nm_device_get_ip_ifindex(port);
if (ifindex_slave <= 0) {
_LOGD(LOGD_TEAM, "team port %s is already released", nm_device_get_ip_iface(slave));
if (ifindex_port <= 0) {
_LOGD(LOGD_TEAM, "team port %s is already detached", nm_device_get_ip_iface(port));
} else if (do_release) {
success = nm_platform_link_release(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
ifindex_slave);
ifindex_port);
if (success)
_LOGI(LOGD_TEAM, "released team port %s", nm_device_get_ip_iface(slave));
_LOGI(LOGD_TEAM, "detached team port %s", nm_device_get_ip_iface(port));
else
_LOGW(LOGD_TEAM, "failed to release team port %s", nm_device_get_ip_iface(slave));
_LOGW(LOGD_TEAM, "failed to detach team port %s", nm_device_get_ip_iface(port));
/* Kernel team code "closes" the port when releasing it, (which clears
* IFF_UP), so we must bring it back up here to ensure carrier changes and
* other state is noticed by the now-released port.
*/
if (!nm_device_bring_up(slave, TRUE, NULL)) {
if (!nm_device_bring_up(port, TRUE, NULL)) {
_LOGW(LOGD_TEAM,
"released team port %s could not be brought up",
nm_device_get_ip_iface(slave));
"detached team port %s could not be brought up",
nm_device_get_ip_iface(port));
}
nm_clear_g_source(&priv->teamd_read_timeout);
priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self);
} else
_LOGI(LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface(slave));
_LOGI(LOGD_TEAM, "team port %s was detached", nm_device_get_ip_iface(port));
/* Delete any port configuration we previously set */
if (configure && priv->tdc
&& (s_port = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_TEAM_PORT))
&& (s_port = nm_device_get_applied_setting(port, NM_TYPE_SETTING_TEAM_PORT))
&& (nm_setting_team_port_get_config(s_port)))
teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(slave), "{}");
teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(port), "{}");
}
static gboolean
@ -1064,8 +1070,8 @@ nm_device_team_class_init(NMDeviceTeamClass *klass)
device_class->act_stage1_prepare = act_stage1_prepare;
device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
device_class->deactivate = deactivate;
device_class->enslave_slave = enslave_slave;
device_class->release_slave = release_slave;
device_class->attach_port = attach_port;
device_class->detach_port = detach_port;
obj_properties[PROP_CONFIG] = g_param_spec_string(NM_DEVICE_TEAM_CONFIG,
"",

View file

@ -291,6 +291,7 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co
if (!IS_IPv4 && l3cd) {
if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd, l3cd, &l3cd_merged)) {
_LOGD("lease merged with existing one");
l3cd = nm_l3_config_data_seal(l3cd_merged);
}
}
@ -327,14 +328,6 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co
keys[i],
(char *) g_hash_table_lookup(options, keys[i]));
}
if (priv->config.addr_family == AF_INET6) {
gs_free char *event_id = NULL;
event_id = nm_dhcp_utils_get_dhcp6_event_id(options);
if (event_id)
_LOGT("event-id: \"%s\"", event_id);
}
}
}
@ -1080,7 +1073,7 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src)
if (!config->send_hostname) {
nm_clear_g_free((gpointer *) &config->hostname);
} else if ((config->use_fqdn && !nm_sd_dns_name_is_valid(config->hostname))
|| (!config->use_fqdn && !nm_sd_hostname_is_valid(config->hostname, FALSE))) {
|| (!config->use_fqdn && !nm_hostname_is_valid(config->hostname, FALSE))) {
nm_log_warn(LOGD_DHCP,
"dhcp%c: %s '%s' is invalid, will be ignored",
nm_utils_addr_family_to_char(config->addr_family),

View file

@ -13,22 +13,24 @@
#include <ctype.h>
#include <net/if_arp.h>
#include "libnm-glib-aux/nm-dedup-multi.h"
#include "libnm-std-aux/unaligned.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "n-dhcp4/src/n-dhcp4.h"
#include "libnm-glib-aux/nm-dedup-multi.h"
#include "libnm-glib-aux/nm-io-utils.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-std-aux/unaligned.h"
#include "nm-l3-config-data.h"
#include "nm-utils.h"
#include "nm-config.h"
#include "nm-dhcp-utils.h"
#include "nm-dhcp-options.h"
#include "nm-core-utils.h"
#include "NetworkManagerUtils.h"
#include "libnm-platform/nm-platform.h"
#include "nm-config.h"
#include "nm-core-utils.h"
#include "nm-dhcp-client-logging.h"
#include "n-dhcp4/src/n-dhcp4.h"
#include "nm-dhcp-options.h"
#include "nm-dhcp-utils.h"
#include "nm-l3-config-data.h"
#include "nm-utils.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "libnm-systemd-core/nm-sd-utils-dhcp.h"
/*****************************************************************************/
@ -887,12 +889,15 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data)
r = n_dhcp4_client_dispatch(priv->client);
if (r < 0) {
/* FIXME: if any operation (e.g. send()) fails during the
/* If any operation (e.g. send()) fails during the
* dispatch, n-dhcp4 returns an error without arming timers
* or progressing state, so the only reasonable thing to do
* is to move to failed state so that the client will be
* restarted. Ideally n-dhcp4 should retry failed operations
* a predefined number of times (possibly infinite).
* restarted.
*
* That means, n_dhcp4_client_dispatch() must not fail if it can
* somehow workaround the problem. A failure is really fatal
* and the client needs to be restarted.
*/
_LOGE("error %d dispatching events", r);
nm_clear_g_source_inst(&priv->event_source);
@ -1107,18 +1112,20 @@ ip4_start(NMDhcpClient *client, GError **error)
if (client_config->v4.last_address)
inet_pton(AF_INET, client_config->v4.last_address, &last_addr);
else {
/*
* TODO: we stick to the systemd-networkd lease file format. Quite easy for now to
* just use the functions in systemd code. Anyway, as in the end we just use the
* ip address from all the options found in the lease, write a function that parses
* the lease file just for the assigned address and returns it in &last_address.
* Then drop reference to systemd-networkd structures and functions.
*/
nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
gs_free char *contents = NULL;
gs_free char *s_addr = NULL;
dhcp_lease_load(&lease, lease_file);
if (lease)
sd_dhcp_lease_get_address(lease, &last_addr);
nm_utils_file_get_contents(-1,
lease_file,
64 * 1024,
NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
&contents,
NULL,
NULL,
NULL);
nm_parse_env_file(contents, "ADDRESS", &s_addr);
if (s_addr)
nm_utils_parse_inaddr_bin(AF_INET, s_addr, NULL, &last_addr);
}
if (last_addr.s_addr) {

View file

@ -25,7 +25,6 @@
#include "libnm-platform/nm-platform.h"
#include "nm-dhcp-client-logging.h"
#include "libnm-systemd-core/nm-sd.h"
#include "libnm-systemd-core/nm-sd-utils-dhcp.h"
/*****************************************************************************/
@ -47,7 +46,6 @@ static GType nm_dhcp_systemd_get_type(void);
/*****************************************************************************/
typedef struct {
sd_dhcp_client *client4;
sd_dhcp6_client *client6;
char *lease_file;
@ -69,675 +67,6 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT)
/*****************************************************************************/
static NML3ConfigData *
lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
sd_dhcp_lease *lease,
GError **error)
{
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
gs_unref_hashtable GHashTable *options = NULL;
const struct in_addr *addr_list;
char addr_str[NM_UTILS_INET_ADDRSTRLEN];
const char *s;
nm_auto_free_gstring GString *str = NULL;
nm_auto_free sd_dhcp_route **routes_static = NULL;
nm_auto_free sd_dhcp_route **routes_classless = NULL;
const char *const *search_domains = NULL;
guint32 default_route_metric_offset;
guint16 mtu;
int i;
int num;
int is_classless;
int n_routes_static;
int n_routes_classless;
const void *data;
gsize data_len;
gboolean has_router_from_classless = FALSE;
const gint32 ts = nm_utils_get_monotonic_timestamp_sec();
gint64 ts_time = time(NULL);
struct in_addr a_address;
struct in_addr a_netmask;
struct in_addr a_next_server;
struct in_addr server_id;
struct in_addr broadcast;
const struct in_addr *a_router;
guint32 a_plen;
guint32 a_lifetime;
guint32 renewal;
guint32 rebinding;
gs_free nm_sd_dhcp_option *private_options = NULL;
nm_assert(lease != NULL);
if (sd_dhcp_lease_get_address(lease, &a_address) < 0) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_UNKNOWN,
"could not get address from lease");
return NULL;
}
if (sd_dhcp_lease_get_netmask(lease, &a_netmask) < 0) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_UNKNOWN,
"could not get netmask from lease");
return NULL;
}
if (sd_dhcp_lease_get_lifetime(lease, &a_lifetime) < 0) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_UNKNOWN,
"could not get lifetime from lease");
return NULL;
}
l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP);
options = nm_dhcp_option_create_options_dict();
_nm_utils_inet4_ntop(a_address.s_addr, addr_str);
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, addr_str);
a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask.s_addr);
nm_dhcp_option_add_option(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_SUBNET_MASK,
_nm_utils_inet4_ntop(a_netmask.s_addr, addr_str));
nm_dhcp_option_add_option_u64(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME,
a_lifetime);
nm_dhcp_option_add_option_u64(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_NM_EXPIRY,
(guint64) (ts_time + a_lifetime));
if (sd_dhcp_lease_get_next_server(lease, &a_next_server) == 0) {
_nm_utils_inet4_ntop(a_next_server.s_addr, addr_str);
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, addr_str);
}
nm_l3_config_data_add_address_4(l3cd,
&((const NMPlatformIP4Address){
.address = a_address.s_addr,
.peer_address = a_address.s_addr,
.plen = a_plen,
.addr_source = NM_IP_CONFIG_SOURCE_DHCP,
.timestamp = ts,
.lifetime = a_lifetime,
.preferred = a_lifetime,
}));
if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) {
_nm_utils_inet4_ntop(server_id.s_addr, addr_str);
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_SERVER_ID, addr_str);
}
if (sd_dhcp_lease_get_broadcast(lease, &broadcast) >= 0) {
_nm_utils_inet4_ntop(broadcast.s_addr, addr_str);
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_BROADCAST, addr_str);
}
num = sd_dhcp_lease_get_dns(lease, &addr_list);
if (num > 0) {
nm_gstring_prepare(&str);
for (i = 0; i < num; i++) {
_nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str);
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
if (addr_list[i].s_addr == 0 || nm_ip4_addr_is_localhost(addr_list[i].s_addr)) {
/* Skip localhost addresses, like also networkd does.
* See https://github.com/systemd/systemd/issues/4524. */
continue;
}
nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr_list[i].s_addr);
}
nm_dhcp_option_add_option(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER,
str->str);
}
num = sd_dhcp_lease_get_search_domains(lease, (char ***) &search_domains);
if (num > 0) {
nm_gstring_prepare(&str);
for (i = 0; i < num; i++) {
g_string_append(nm_gstring_add_space_delimiter(str), search_domains[i]);
nm_l3_config_data_add_search(l3cd, AF_INET, search_domains[i]);
}
nm_dhcp_option_add_option(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST,
str->str);
}
if (sd_dhcp_lease_get_domainname(lease, &s) >= 0) {
gs_strfreev char **domains = NULL;
char **d;
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, s);
/* Multiple domains sometimes stuffed into option 15 "Domain Name".
* As systemd escapes such characters, split them at \\032. */
domains = g_strsplit(s, "\\032", 0);
for (d = domains; *d; d++)
nm_l3_config_data_add_domain(l3cd, AF_INET, *d);
}
if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) {
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME, s);
}
default_route_metric_offset = 0;
n_routes_static = sd_dhcp_lease_get_static_routes(lease, &routes_static);
n_routes_classless = sd_dhcp_lease_get_classless_routes(lease, &routes_classless);
for (is_classless = 1; is_classless >= 0; is_classless--) {
int n_routes = (is_classless ? n_routes_classless : n_routes_static);
sd_dhcp_route *const *routes = (is_classless ? routes_classless : routes_static);
if (n_routes <= 0)
continue;
nm_gstring_prepare(&str);
for (i = 0; i < n_routes; i++) {
char network_net_str[NM_UTILS_INET_ADDRSTRLEN];
char gateway_str[NM_UTILS_INET_ADDRSTRLEN];
guint8 r_plen;
struct in_addr r_network;
struct in_addr r_gateway;
in_addr_t network_net;
guint32 m;
if (sd_dhcp_route_get_destination(routes[i], &r_network) < 0)
continue;
if (sd_dhcp_route_get_destination_prefix_length(routes[i], &r_plen) < 0 || r_plen > 32)
continue;
if (sd_dhcp_route_get_gateway(routes[i], &r_gateway) < 0)
continue;
network_net = nm_utils_ip4_address_clear_host_address(r_network.s_addr, r_plen);
_nm_utils_inet4_ntop(network_net, network_net_str);
_nm_utils_inet4_ntop(r_gateway.s_addr, gateway_str);
g_string_append_printf(nm_gstring_add_space_delimiter(str),
"%s/%d %s",
network_net_str,
(int) r_plen,
gateway_str);
if (!is_classless && n_routes_classless > 0) {
/* RFC 3443: if the DHCP server returns both a Classless Static Routes
* option and a Static Routes option, the DHCP client MUST ignore the
* Static Routes option. */
continue;
}
if (r_plen == 0) {
if (!is_classless) {
/* for option 33 (static route), RFC 2132 says:
*
* The default route (0.0.0.0) is an illegal destination for a static
* route. */
continue;
}
/* if there are multiple default routes, we add them with differing
* metrics. */
m = default_route_metric_offset++;
has_router_from_classless = TRUE;
} else
m = 0;
nm_l3_config_data_add_route_4(l3cd,
&((const NMPlatformIP4Route){
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
.network = network_net,
.plen = r_plen,
.gateway = r_gateway.s_addr,
.pref_src = a_address.s_addr,
.metric_any = TRUE,
.metric = m,
.table_any = TRUE,
.table_coerced = 0,
}));
}
if (str->len > 0) {
nm_dhcp_option_add_option(options,
AF_INET,
is_classless ? NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE
: NM_DHCP_OPTION_DHCP4_STATIC_ROUTE,
str->str);
}
}
num = sd_dhcp_lease_get_router(lease, &a_router);
if (num > 0) {
default_route_metric_offset = 0;
nm_gstring_prepare(&str);
for (i = 0; i < num; i++) {
guint32 m;
s = _nm_utils_inet4_ntop(a_router[i].s_addr, addr_str);
g_string_append(nm_gstring_add_space_delimiter(str), s);
if (a_router[i].s_addr == 0) {
/* silently skip 0.0.0.0 */
continue;
}
if (has_router_from_classless) {
/* If the DHCP server returns both a Classless Static Routes option and a
* Router option, the DHCP client MUST ignore the Router option [RFC 3442].
*
* Be more lenient and ignore the Router option only if Classless Static
* Routes contain a default gateway (as other DHCP backends do).
*/
continue;
}
/* if there are multiple default routes, we add them with differing
* metrics. */
m = default_route_metric_offset++;
nm_l3_config_data_add_route_4(l3cd,
&((const NMPlatformIP4Route){
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
.gateway = a_router[i].s_addr,
.pref_src = a_address.s_addr,
.table_any = TRUE,
.table_coerced = 0,
.metric_any = TRUE,
.metric = m,
}));
}
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROUTER, str->str);
}
if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) {
nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, mtu);
nm_l3_config_data_set_mtu(l3cd, mtu);
}
num = sd_dhcp_lease_get_ntp(lease, &addr_list);
if (num > 0) {
nm_gstring_prepare(&str);
for (i = 0; i < num; i++) {
_nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str);
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
}
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NTP_SERVER, str->str);
}
if (sd_dhcp_lease_get_root_path(lease, &s) >= 0) {
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROOT_PATH, s);
}
if (sd_dhcp_lease_get_t1(lease, &renewal) >= 0) {
nm_dhcp_option_add_option_u64(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME,
renewal);
}
if (sd_dhcp_lease_get_t2(lease, &rebinding) >= 0) {
nm_dhcp_option_add_option_u64(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME,
rebinding);
}
if (sd_dhcp_lease_get_timezone(lease, &s) >= 0) {
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, s);
}
if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) {
if (!!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")))
nm_l3_config_data_set_metered(l3cd, TRUE);
}
num = nm_sd_dhcp_lease_get_private_options(lease, &private_options);
if (num > 0) {
for (i = 0; i < num; i++) {
guint8 code = private_options[i].code;
const guint8 *l_data = private_options[i].data;
gsize l_data_len = private_options[i].data_len;
char *option_string;
if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY) {
if (nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) {
gs_free char *to_free = NULL;
const char *escaped;
escaped =
nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free);
nm_dhcp_option_add_option(options,
AF_INET,
NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY,
escaped ?: "");
nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO);
nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: "");
}
continue;
}
if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE) {
/* nettools and dhclient parse option 249 (Microsoft Classless Static Route)
* as fallback for routes and ignores them from private options.
*
* The systemd plugin does not, and for consistency with nettools we
* also don't expose it as private option either. */
continue;
}
option_string = nm_utils_bin2hexstr_full(l_data, l_data_len, ':', FALSE, NULL);
nm_dhcp_option_take_option(options, AF_INET, code, option_string);
}
}
nm_dhcp_option_add_requests_to_options(options, AF_INET);
nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options));
return g_steal_pointer(&l3cd);
}
/*****************************************************************************/
static void
bound4_handle(NMDhcpSystemd *self, gboolean extended)
{
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
const char *iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self));
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
sd_dhcp_lease *lease = NULL;
GError *error = NULL;
if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) {
_LOGW("no lease!");
nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL);
return;
}
_LOGD("lease available");
l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)),
iface,
nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)),
lease,
&error);
if (!l3cd) {
_LOGW("%s", error->message);
g_clear_error(&error);
nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL);
return;
}
dhcp_lease_save(lease, priv->lease_file);
nm_dhcp_client_set_state(NM_DHCP_CLIENT(self),
extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND,
l3cd);
}
static int
dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data)
{
NMDhcpSystemd *self = NM_DHCP_SYSTEMD(user_data);
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
char addr_str[INET_ADDRSTRLEN];
sd_dhcp_lease *lease = NULL;
struct in_addr addr;
int r;
nm_assert(priv->client4 == client);
_LOGD("client event %d", event);
switch (event) {
case SD_DHCP_CLIENT_EVENT_EXPIRED:
nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL);
break;
case SD_DHCP_CLIENT_EVENT_STOP:
nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL);
break;
case SD_DHCP_CLIENT_EVENT_RENEW:
case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
bound4_handle(self, TRUE);
break;
case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
bound4_handle(self, FALSE);
break;
case SD_DHCP_CLIENT_EVENT_SELECTING:
r = sd_dhcp_client_get_lease(priv->client4, &lease);
if (r < 0)
return r;
r = sd_dhcp_lease_get_server_identifier(lease, &addr);
if (r < 0)
return r;
if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(user_data), &addr)) {
_LOGD("server-id %s is in the reject-list, ignoring",
nm_utils_inet_ntop(AF_INET, &addr, addr_str));
return -ENOMSG;
}
break;
case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE:
break;
default:
_LOGW("unhandled DHCP event %d", event);
break;
}
return 0;
}
static gboolean
ip4_start(NMDhcpClient *client, GError **error)
{
nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL;
NMDhcpSystemd *self = NM_DHCP_SYSTEMD(client);
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
const NMDhcpClientConfig *client_config;
gs_free char *lease_file = NULL;
GBytes *hwaddr;
const uint8_t *hwaddr_arr;
gsize hwaddr_len;
int arp_type;
GBytes *client_id;
gs_unref_bytes GBytes *client_id_new = NULL;
GBytes *vendor_class_identifier;
const uint8_t *client_id_arr;
size_t client_id_len;
struct in_addr last_addr = {0};
const char *hostname;
const char *mud_url;
int r, i;
GBytes *bcast_hwaddr;
const uint8_t *bcast_hwaddr_arr;
gsize bcast_hwaddr_len;
g_return_val_if_fail(!priv->client4, FALSE);
g_return_val_if_fail(!priv->client6, FALSE);
client_config = nm_dhcp_client_get_config(client);
/* TODO: honor nm_dhcp_client_get_anycast_address() */
r = sd_dhcp_client_new(&sd_client, FALSE);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to create dhcp-client: %s");
return FALSE;
}
_LOGT("dhcp-client4: set " NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(sd_client));
r = sd_dhcp_client_attach_event(sd_client, NULL, 0);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to attach event: %s");
return FALSE;
}
hwaddr = client_config->hwaddr;
if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len))
|| (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) {
nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address");
return FALSE;
}
bcast_hwaddr_arr = NULL;
bcast_hwaddr = client_config->bcast_hwaddr;
if (bcast_hwaddr) {
bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len);
if (bcast_hwaddr_len != hwaddr_len)
bcast_hwaddr_arr = NULL;
}
r = sd_dhcp_client_set_mac(sd_client,
hwaddr_arr,
bcast_hwaddr_arr,
hwaddr_len,
(guint16) arp_type);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set MAC address: %s");
return FALSE;
}
r = sd_dhcp_client_set_ifindex(sd_client, nm_dhcp_client_get_ifindex(client));
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set ifindex: %s");
return FALSE;
}
nm_dhcp_utils_get_leasefile_path(AF_INET,
"internal",
client_config->iface,
client_config->uuid,
&lease_file);
if (client_config->v4.last_address)
inet_pton(AF_INET, client_config->v4.last_address, &last_addr);
else {
nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
dhcp_lease_load(&lease, lease_file);
if (lease)
sd_dhcp_lease_get_address(lease, &last_addr);
}
r = sd_dhcp_client_set_request_broadcast(sd_client, client_config->v4.request_broadcast);
nm_assert(r >= 0);
if (last_addr.s_addr) {
r = sd_dhcp_client_set_request_address(sd_client, &last_addr);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set last IPv4 address: %s");
return FALSE;
}
}
client_id = client_config->client_id;
if (!client_id) {
client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len);
client_id = client_id_new;
}
if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) {
/* invalid client-ids are not expected. */
nm_assert_not_reached();
nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id");
return FALSE;
}
/* Note that we always set a client-id. In particular for infiniband that is necessary,
* see https://tools.ietf.org/html/rfc4390#section-2.1 . */
r = sd_dhcp_client_set_client_id(sd_client,
client_id_arr[0],
client_id_arr + 1,
NM_MIN(client_id_len - 1, _NM_MAX_CLIENT_ID_LEN));
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set IPv4 client-id: %s");
return FALSE;
}
/* Add requested options */
for (i = 0; i < (int) G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options); i++) {
if (_nm_dhcp_option_dhcp4_options[i].include) {
nm_assert(_nm_dhcp_option_dhcp4_options[i].option_num <= 255);
r = sd_dhcp_client_set_request_option(sd_client,
_nm_dhcp_option_dhcp4_options[i].option_num);
nm_assert(r >= 0 || r == -EEXIST);
}
}
hostname = client_config->hostname;
if (hostname) {
/* FIXME: sd-dhcp decides which hostname/FQDN option to send (12 or 81)
* only based on whether the hostname has a domain part or not. At the
* moment there is no way to force one or another.
*/
r = sd_dhcp_client_set_hostname(sd_client, hostname);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set DHCP hostname: %s");
return FALSE;
}
}
mud_url = client_config->mud_url;
if (mud_url) {
r = sd_dhcp_client_set_mud_url(sd_client, mud_url);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set DHCP MUDURL: %s");
return FALSE;
}
}
vendor_class_identifier = client_config->vendor_class_identifier;
if (vendor_class_identifier) {
const char *option_data;
gsize len;
option_data = g_bytes_get_data(vendor_class_identifier, &len);
nm_assert(option_data);
nm_assert(len <= 255);
option_data = nm_strndup_a(300, option_data, len, NULL);
r = sd_dhcp_client_set_vendor_class_identifier(sd_client, option_data);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set DHCP vendor class identifier: %s");
return FALSE;
}
}
r = sd_dhcp_client_set_callback(sd_client, dhcp_event_cb, client);
if (r < 0) {
nm_utils_error_set_errno(error, r, "failed to set callback: %s");
return FALSE;
}
priv->client4 = g_steal_pointer(&sd_client);
g_free(priv->lease_file);
priv->lease_file = g_steal_pointer(&lease_file);
nm_dhcp_client_set_effective_client_id(client, client_id);
r = sd_dhcp_client_start(priv->client4);
if (r < 0) {
sd_dhcp_client_set_callback(priv->client4, NULL, NULL);
nm_clear_pointer(&priv->client4, sd_dhcp_client_unref);
nm_utils_error_set_errno(error, r, "failed to start DHCP client: %s");
return FALSE;
}
return TRUE;
}
static NML3ConfigData *
lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
const char *iface,
@ -952,7 +281,6 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
GBytes *duid;
gboolean prefix_delegation;
g_return_val_if_fail(!priv->client4, FALSE);
g_return_val_if_fail(!priv->client6, FALSE);
client_config = nm_dhcp_client_get_config(client);
@ -1079,18 +407,13 @@ stop(NMDhcpClient *client, gboolean release)
NM_DHCP_CLIENT_CLASS(nm_dhcp_systemd_parent_class)->stop(client, release);
_LOGT("dhcp-client%d: stop %p",
priv->client4 ? '4' : '6',
priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6);
_LOGT("dhcp-client6: stop");
if (priv->client4) {
sd_dhcp_client_set_callback(priv->client4, NULL, NULL);
r = sd_dhcp_client_stop(priv->client4);
} else if (priv->client6) {
sd_dhcp6_client_set_callback(priv->client6, NULL, NULL);
r = sd_dhcp6_client_stop(priv->client6);
}
if (!priv->client6)
return;
sd_dhcp6_client_set_callback(priv->client6, NULL, NULL);
r = sd_dhcp6_client_stop(priv->client6);
if (r)
_LOGW("failed to stop client (%d)", r);
}
@ -1108,12 +431,6 @@ dispose(GObject *object)
nm_clear_g_free(&priv->lease_file);
if (priv->client4) {
sd_dhcp_client_stop(priv->client4);
sd_dhcp_client_unref(priv->client4);
priv->client4 = NULL;
}
if (priv->client6) {
sd_dhcp6_client_stop(priv->client6);
sd_dhcp6_client_unref(priv->client6);
@ -1131,14 +448,13 @@ nm_dhcp_systemd_class_init(NMDhcpSystemdClass *sdhcp_class)
object_class->dispose = dispose;
client_class->ip4_start = ip4_start;
client_class->ip6_start = ip6_start;
client_class->stop = stop;
}
const NMDhcpClientFactory _nm_dhcp_client_factory_systemd = {
.name = "systemd",
.get_type_4 = nm_dhcp_systemd_get_type,
.get_type_4 = nm_dhcp_nettools_get_type,
.get_type_6 = nm_dhcp_systemd_get_type,
.undocumented = TRUE,
};

View file

@ -295,7 +295,7 @@ process_classful_routes(const char *iface,
return;
if ((NM_PTRARRAY_LEN(searches) % 2) != 0) {
_LOG2I(LOGD_DHCP, iface, " static routes provided, but invalid");
_LOG2I(LOGD_DHCP4, iface, " static routes provided, but invalid");
return;
}
@ -305,11 +305,11 @@ process_classful_routes(const char *iface,
guint32 rt_addr, rt_route;
if (inet_pton(AF_INET, *s, &rt_addr) <= 0) {
_LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route address: '%s'", *s);
_LOG2W(LOGD_DHCP4, iface, "DHCP provided invalid static route address: '%s'", *s);
continue;
}
if (inet_pton(AF_INET, *(s + 1), &rt_route) <= 0) {
_LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1));
_LOG2W(LOGD_DHCP4, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1));
continue;
}
@ -340,7 +340,7 @@ process_classful_routes(const char *iface,
nm_l3_config_data_add_route_4(l3cd, &route);
_LOG2I(LOGD_DHCP,
_LOG2I(LOGD_DHCP4,
iface,
" static route %s",
nm_platform_ip4_route_to_string(&route, sbuf, sizeof(sbuf)));
@ -352,6 +352,7 @@ process_domain_search(int addr_family, const char *iface, const char *str, NML3C
{
gs_free const char **searches = NULL;
gs_free char *unescaped = NULL;
NMLogDomain logd = NM_IS_IPv4(addr_family) ? LOGD_DHCP4 : LOGD_DHCP6;
const char **s;
char *p;
int i;
@ -373,13 +374,13 @@ process_domain_search(int addr_family, const char *iface, const char *str, NML3C
} while (*p++);
if (strchr(unescaped, '\\')) {
_LOG2W(LOGD_DHCP, iface, " invalid domain search: '%s'", unescaped);
_LOG2W(logd, iface, " invalid domain search: '%s'", unescaped);
return;
}
searches = nm_strsplit_set(unescaped, " ");
for (s = searches; searches && *s; s++) {
_LOG2I(LOGD_DHCP, iface, " domain search '%s'", *s);
_LOG2I(logd, iface, " domain search '%s'", *s);
nm_l3_config_data_add_search(l3cd, addr_family, *s);
}
}
@ -822,26 +823,6 @@ nm_dhcp_utils_get_leasefile_path(int addr_family,
return FALSE;
}
char *
nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease)
{
const char *start;
const char *iaid;
if (!lease)
return NULL;
iaid = g_hash_table_lookup(lease, "iaid");
if (!iaid)
return NULL;
start = g_hash_table_lookup(lease, "life_starts");
if (!start)
return NULL;
return g_strdup_printf("%s|%s", iaid, start);
}
gboolean
nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData *l3cd_old,
const NML3ConfigData *l3cd_new,

View file

@ -678,19 +678,23 @@ typedef struct {
char *name_owner;
GSource *main_timeout_source;
GSource *burst_retry_timeout_source;
gint64 burst_start_at;
GPid process_pid;
guint name_owner_changed_id;
guint main_timeout_id;
guint burst_retry_timeout_id;
guint8 burst_count;
bool is_stopped : 1;
bool set_server_ex_args_dirty : 1;
bool update_pending : 1;
} NMDnsDnsmasqPrivate;
struct _NMDnsDnsmasq {
@ -704,7 +708,8 @@ struct _NMDnsDnsmasqClass {
G_DEFINE_TYPE(NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
#define NM_DNS_DNSMASQ_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDnsDnsmasq, NM_IS_DNS_DNSMASQ)
#define NM_DNS_DNSMASQ_GET_PRIVATE(self) \
_NM_GET_PRIVATE(self, NMDnsDnsmasq, NM_IS_DNS_DNSMASQ, NMDnsPlugin)
/*****************************************************************************/
@ -717,6 +722,55 @@ static gboolean start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError *
/*****************************************************************************/
static gboolean
_update_pending_detect(NMDnsDnsmasq *self)
{
NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
if (priv->is_stopped)
return FALSE;
if (priv->main_timeout_source) {
/* we are waiting for dnsmasq to start. */
return TRUE;
}
if (priv->update_cancellable) {
/* An update is in progress. Busy. */
return TRUE;
}
if (priv->set_server_ex_args_dirty) {
/* the args just changed and were not yet sent. Busy. */
return TRUE;
}
return FALSE;
}
static void
_update_pending_maybe_changed(NMDnsDnsmasq *self)
{
NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
gboolean update_pending;
update_pending = _update_pending_detect(self);
if (priv->update_pending == update_pending)
return;
priv->update_pending = update_pending;
_nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self));
}
static gboolean
get_update_pending(NMDnsPlugin *plugin)
{
NMDnsDnsmasq *self = NM_DNS_DNSMASQ(plugin);
NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
nm_assert(priv->update_pending == _update_pending_detect(self));
return priv->update_pending;
}
/*****************************************************************************/
static void
add_dnsmasq_nameserver(NMDnsDnsmasq *self,
GVariantBuilder *servers,
@ -871,6 +925,7 @@ static void
dnsmasq_update_done(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
NMDnsDnsmasq *self;
NMDnsDnsmasqPrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *response = NULL;
@ -880,10 +935,16 @@ dnsmasq_update_done(GObject *source_object, GAsyncResult *res, gpointer user_dat
return;
self = user_data;
priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
nm_clear_g_cancellable(&priv->update_cancellable);
if (!response)
_LOGW("dnsmasq update failed: %s", error->message);
else
_LOGD("dnsmasq update successful");
_update_pending_maybe_changed(self);
}
static void
@ -899,6 +960,8 @@ send_dnsmasq_update(NMDnsDnsmasq *self)
nm_clear_g_cancellable(&priv->update_cancellable);
priv->update_cancellable = g_cancellable_new();
priv->set_server_ex_args_dirty = FALSE;
g_dbus_connection_call(priv->dbus_connection,
priv->name_owner,
DNSMASQ_DBUS_PATH,
@ -911,6 +974,8 @@ send_dnsmasq_update(NMDnsDnsmasq *self)
priv->update_cancellable,
dnsmasq_update_done,
self);
_update_pending_maybe_changed(self);
}
/*****************************************************************************/
@ -928,17 +993,19 @@ _main_cleanup(NMDnsDnsmasq *self, gboolean emit_failed)
nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id);
nm_clear_g_source(&priv->main_timeout_id);
nm_clear_g_source_inst(&priv->main_timeout_source);
nm_clear_g_cancellable(&priv->update_cancellable);
/* cancelling the main_cancellable will also cause _gl_pid_spawn*() to terminate the
* process in the background. */
nm_clear_g_cancellable(&priv->main_cancellable);
if (!priv->is_stopped && priv->burst_retry_timeout_id == 0) {
if (!priv->is_stopped && !priv->burst_retry_timeout_source) {
start_dnsmasq(self, FALSE, NULL);
send_dnsmasq_update(self);
}
_update_pending_maybe_changed(self);
}
static void
@ -961,8 +1028,10 @@ name_owner_changed(NMDnsDnsmasq *self, const char *name_owner)
}
_LOGT("D-Bus name for dnsmasq got owner %s", name_owner);
nm_clear_g_source(&priv->main_timeout_id);
nm_clear_g_source_inst(&priv->main_timeout_source);
send_dnsmasq_update(self);
_update_pending_maybe_changed(self);
}
static void
@ -1047,11 +1116,11 @@ _burst_retry_timeout_cb(gpointer user_data)
NMDnsDnsmasq *self = user_data;
NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
priv->burst_retry_timeout_id = 0;
nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
start_dnsmasq(self, TRUE, NULL);
send_dnsmasq_update(self);
return G_SOURCE_REMOVE;
return G_SOURCE_CONTINUE;
}
static gboolean
@ -1090,33 +1159,35 @@ start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError **error)
|| priv->burst_start_at + RATELIMIT_INTERVAL_MSEC <= now) {
priv->burst_start_at = now;
priv->burst_count = 1;
nm_clear_g_source(&priv->burst_retry_timeout_id);
nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
_LOGT("rate-limit: start burst interval of %d seconds %s",
RATELIMIT_INTERVAL_MSEC / 1000,
force_start ? " (force)" : "");
} else if (priv->burst_count < RATELIMIT_BURST) {
nm_assert(priv->burst_retry_timeout_id == 0);
nm_assert(!priv->burst_retry_timeout_source);
priv->burst_count++;
_LOGT("rate-limit: %u try within burst interval of %d seconds",
(guint) priv->burst_count,
RATELIMIT_INTERVAL_MSEC / 1000);
} else {
if (priv->burst_retry_timeout_id == 0) {
if (!priv->burst_retry_timeout_source) {
_LOGW("dnsmasq dies and gets respawned too quickly. Back off. Something is very wrong");
priv->burst_retry_timeout_id =
g_timeout_add_seconds((2 * RATELIMIT_INTERVAL_MSEC) / 1000,
_burst_retry_timeout_cb,
self);
priv->burst_retry_timeout_source =
nm_g_timeout_add_seconds_source((2 * RATELIMIT_INTERVAL_MSEC) / 1000,
_burst_retry_timeout_cb,
self);
} else
_LOGT("rate-limit: currently rate-limited from restart");
return TRUE;
}
priv->main_timeout_id = g_timeout_add(10000, spawn_timeout_cb, self);
priv->main_timeout_source = nm_g_timeout_add_source(10000, spawn_timeout_cb, self);
priv->main_cancellable = g_cancellable_new();
_gl_pid_spawn(dm_binary, priv->main_cancellable, spawn_notify, self);
_update_pending_maybe_changed(self);
return TRUE;
}
@ -1136,8 +1207,11 @@ update(NMDnsPlugin *plugin,
nm_clear_pointer(&priv->set_server_ex_args, g_variant_unref);
priv->set_server_ex_args =
g_variant_ref_sink(create_update_args(self, global_config, ip_data_lst_head, hostdomain));
priv->set_server_ex_args_dirty = TRUE;
send_dnsmasq_update(self);
_update_pending_maybe_changed(self);
return TRUE;
}
@ -1151,11 +1225,13 @@ stop(NMDnsPlugin *plugin)
priv->is_stopped = TRUE;
priv->burst_start_at = 0;
nm_clear_g_source(&priv->burst_retry_timeout_id);
nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
/* Cancelling the cancellable will also terminate the
* process (in the background). */
_main_cleanup(self, FALSE);
_update_pending_maybe_changed(self);
}
/*****************************************************************************/
@ -1178,7 +1254,7 @@ dispose(GObject *object)
priv->is_stopped = TRUE;
nm_clear_g_source(&priv->burst_retry_timeout_id);
nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
_main_cleanup(self, FALSE);
@ -1197,8 +1273,9 @@ nm_dns_dnsmasq_class_init(NMDnsDnsmasqClass *dns_class)
object_class->dispose = dispose;
plugin_class->plugin_name = "dnsmasq";
plugin_class->is_caching = TRUE;
plugin_class->stop = stop;
plugin_class->update = update;
plugin_class->plugin_name = "dnsmasq";
plugin_class->is_caching = TRUE;
plugin_class->stop = stop;
plugin_class->update = update;
plugin_class->get_update_pending = get_update_pending;
}

View file

@ -26,7 +26,6 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "NetworkManagerUtils.h"
#include "devices/nm-device.h"
@ -35,7 +34,6 @@
#include "nm-dns-dnsmasq.h"
#include "nm-dns-plugin.h"
#include "nm-dns-systemd-resolved.h"
#include "nm-dns-unbound.h"
#include "nm-ip-config.h"
#include "nm-l3-config-data.h"
#include "nm-manager.h"
@ -57,6 +55,8 @@
#define HAS_NETCONFIG 1
#endif
#define UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC 5000
/*****************************************************************************/
typedef enum { SR_SUCCESS, SR_NOTFOUND, SR_ERROR } SpawnResult;
@ -78,7 +78,11 @@ enum {
LAST_SIGNAL
};
NM_GOBJECT_PROPERTIES_DEFINE(NMDnsManager, PROP_MODE, PROP_RC_MANAGER, PROP_CONFIGURATION, );
NM_GOBJECT_PROPERTIES_DEFINE(NMDnsManager,
PROP_MODE,
PROP_RC_MANAGER,
PROP_CONFIGURATION,
PROP_UPDATE_PENDING, );
static guint signals[LAST_SIGNAL] = {0};
@ -89,6 +93,11 @@ typedef struct {
CList ip_data_lst_head;
GVariant *config_variant;
/* A DNS plugin should not be marked as pending indefinitely.
* We are only blocked if "update_pending" is TRUE and we have
* "update_pending_unblock" timer ticking. */
GSource *update_pending_unblock;
bool ip_data_lst_need_sort : 1;
bool configs_lst_need_sort : 1;
@ -98,6 +107,8 @@ typedef struct {
bool config_changed : 1;
bool update_pending : 1;
char *hostdomain;
guint updates_queue;
@ -109,6 +120,9 @@ typedef struct {
NMDnsPlugin *sd_resolve_plugin;
NMDnsPlugin *plugin;
gulong update_changed_signal_id_sd;
gulong update_changed_signal_id;
NMConfig *config;
struct {
@ -137,28 +151,23 @@ NM_DEFINE_SINGLETON_GETTER(NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER
#define _NMLOG_PREFIX_NAME "dns-mgr"
#define _NMLOG_DOMAIN LOGD_DNS
#define _NMLOG(level, ...) \
G_STMT_START \
{ \
const NMLogLevel __level = (level); \
\
if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
char __prefix[20]; \
const NMDnsManager *const __self = (self); \
\
_nm_log(__level, \
_NMLOG_DOMAIN, \
0, \
NULL, \
NULL, \
"%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
_NMLOG_PREFIX_NAME, \
((!__self || __self == singleton_instance) \
? "" \
: nm_sprintf_buf(__prefix, "[%p]", __self)) \
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} \
} \
#define _NMLOG(level, ...) \
G_STMT_START \
{ \
const NMLogLevel __level = (level); \
\
if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
_nm_unused const NMDnsManager *const __self = (self); \
\
_nm_log(__level, \
_NMLOG_DOMAIN, \
0, \
NULL, \
NULL, \
"%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
_NMLOG_PREFIX_NAME _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} \
} \
G_STMT_END
/*****************************************************************************/
@ -207,6 +216,85 @@ static NM_UTILS_LOOKUP_STR_DEFINE(
/*****************************************************************************/
static gboolean
_update_pending_detect(NMDnsManager *self)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
if (priv->plugin && nm_dns_plugin_get_update_pending(priv->plugin))
return TRUE;
if (priv->sd_resolve_plugin && nm_dns_plugin_get_update_pending(priv->sd_resolve_plugin))
return TRUE;
return FALSE;
}
static gboolean
_update_pending_unblock_cb(gpointer user_data)
{
NMDnsManager *self = user_data;
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
nm_assert(priv->update_pending);
nm_assert(priv->update_pending_unblock);
nm_assert(_update_pending_detect(self));
nm_clear_g_source_inst(&priv->update_pending_unblock);
_LOGW(
"update-pending changed: DNS plugin did not become ready again. Assume something is wrong");
_notify(self, PROP_UPDATE_PENDING);
return G_SOURCE_CONTINUE;
}
static void
_update_pending_maybe_changed(NMDnsManager *self)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
gboolean update_pending;
update_pending = _update_pending_detect(self);
if (priv->update_pending == update_pending)
return;
if (update_pending) {
nm_assert(!priv->update_pending_unblock);
priv->update_pending_unblock = nm_g_timeout_add_source(UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC,
_update_pending_unblock_cb,
self);
} else
nm_clear_g_source_inst(&priv->update_pending_unblock);
priv->update_pending = update_pending;
_LOGD("update-pending changed: %spending", update_pending ? "" : "not ");
_notify(self, PROP_UPDATE_PENDING);
}
static void
_update_pending_changed_cb(NMDnsPlugin *plugin, gboolean update_pending, NMDnsManager *self)
{
_update_pending_maybe_changed(self);
}
gboolean
nm_dns_manager_get_update_pending(NMDnsManager *self)
{
NMDnsManagerPrivate *priv;
g_return_val_if_fail(NM_IS_DNS_MANAGER(self), FALSE);
priv = NM_DNS_MANAGER_GET_PRIVATE(self);
nm_assert(priv->update_pending == _update_pending_detect(self));
nm_assert(priv->update_pending || !priv->update_pending_unblock);
/* update-pending can only be TRUE for a certain time (before we assume
* something is really wrong with the plugin). That is, as long as
* update_pending_unblock is ticking. */
return !!priv->update_pending_unblock;
}
/*****************************************************************************/
static int
_dns_config_ip_data_get_dns_priority1(const NML3ConfigData *l3cd, int addr_family)
{
@ -2015,7 +2103,7 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s
domain = hostname;
}
if (!nm_sd_hostname_is_valid(domain, FALSE))
if (!nm_hostname_is_valid(domain, FALSE))
domain = NULL;
}
}
@ -2120,6 +2208,7 @@ _clear_plugin(NMDnsManager *self)
nm_clear_g_source(&priv->plugin_ratelimit.timer);
if (priv->plugin) {
nm_clear_g_signal_handler(priv->plugin, &priv->update_changed_signal_id);
nm_dns_plugin_stop(priv->plugin);
g_clear_object(&priv->plugin);
return TRUE;
@ -2127,6 +2216,20 @@ _clear_plugin(NMDnsManager *self)
return FALSE;
}
static gboolean
_clear_sd_resolved_plugin(NMDnsManager *self)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
if (priv->sd_resolve_plugin) {
nm_clear_g_signal_handler(priv->sd_resolve_plugin, &priv->update_changed_signal_id_sd);
nm_dns_plugin_stop(priv->sd_resolve_plugin);
g_clear_object(&priv->sd_resolve_plugin);
return TRUE;
}
return FALSE;
}
static NMDnsManagerResolvConfManager
_check_resconf_immutable(NMDnsManagerResolvConfManager rc_manager)
{
@ -2313,16 +2416,14 @@ again:
priv->plugin = nm_dns_dnsmasq_new();
plugin_changed = TRUE;
}
} else if (nm_streq0(mode, "unbound")) {
if (force_reload_plugin || !NM_IS_DNS_UNBOUND(priv->plugin)) {
_clear_plugin(self);
priv->plugin = nm_dns_unbound_new();
plugin_changed = TRUE;
}
} else {
if (!NM_IN_STRSET(mode, "none", "default")) {
if (mode)
_LOGW("init: unknown dns mode '%s'", mode);
if (mode) {
if (nm_streq(mode, "unbound"))
_LOGW("init: ns mode 'unbound' was removed. Update your configuration");
else
_LOGW("init: unknown dns mode '%s'", mode);
}
mode = "default";
}
if (_clear_plugin(self))
@ -2359,7 +2460,7 @@ again:
priv->sd_resolve_plugin = nm_dns_systemd_resolved_new();
systemd_resolved_changed = TRUE;
}
} else if (nm_clear_g_object(&priv->sd_resolve_plugin))
} else if (_clear_sd_resolved_plugin(self))
systemd_resolved_changed = TRUE;
g_object_freeze_notify(G_OBJECT(self));
@ -2390,6 +2491,23 @@ again:
""));
}
if (plugin_changed && priv->plugin && priv->update_changed_signal_id == 0) {
priv->update_changed_signal_id = g_signal_connect(priv->plugin,
NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED,
G_CALLBACK(_update_pending_changed_cb),
self);
}
if (systemd_resolved_changed && priv->sd_resolve_plugin
&& priv->update_changed_signal_id_sd == 0) {
priv->update_changed_signal_id_sd = g_signal_connect(priv->sd_resolve_plugin,
NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED,
G_CALLBACK(_update_pending_changed_cb),
self);
}
_update_pending_maybe_changed(self);
g_object_thaw_notify(G_OBJECT(self));
}
@ -2594,6 +2712,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
case PROP_CONFIGURATION:
g_value_set_variant(value, _get_config_variant(self));
break;
case PROP_UPDATE_PENDING:
g_value_set_boolean(value, nm_dns_manager_get_update_pending(self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@ -2641,9 +2762,11 @@ dispose(GObject *object)
if (priv->config)
g_signal_handlers_disconnect_by_func(priv->config, config_changed_cb, self);
g_clear_object(&priv->sd_resolve_plugin);
_clear_sd_resolved_plugin(self);
_clear_plugin(self);
nm_clear_g_source_inst(&priv->update_pending_unblock);
c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_data_lst_head, ip_data_lst)
_dns_config_ip_data_free(ip_data);
@ -2719,6 +2842,13 @@ nm_dns_manager_class_init(NMDnsManagerClass *klass)
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties[PROP_UPDATE_PENDING] =
g_param_spec_boolean(NM_DNS_MANAGER_UPDATE_PENDING,
"",
"",
FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[CONFIG_CHANGED] = g_signal_new(NM_DNS_MANAGER_CONFIG_CHANGED,

View file

@ -80,9 +80,10 @@ typedef struct _NMDnsConfigData {
(G_TYPE_INSTANCE_GET_CLASS((o), NM_TYPE_DNS_MANAGER, NMDnsManagerClass))
/* properties */
#define NM_DNS_MANAGER_MODE "mode"
#define NM_DNS_MANAGER_RC_MANAGER "rc-manager"
#define NM_DNS_MANAGER_CONFIGURATION "configuration"
#define NM_DNS_MANAGER_MODE "mode"
#define NM_DNS_MANAGER_RC_MANAGER "rc-manager"
#define NM_DNS_MANAGER_CONFIGURATION "configuration"
#define NM_DNS_MANAGER_UPDATE_PENDING "update-pending"
/* internal signals */
#define NM_DNS_MANAGER_CONFIG_CHANGED "config-changed"
@ -149,6 +150,8 @@ void nm_dns_manager_stop(NMDnsManager *self);
NMDnsPlugin *nm_dns_manager_get_systemd_resolved(NMDnsManager *self);
gboolean nm_dns_manager_get_update_pending(NMDnsManager *self);
/*****************************************************************************/
char *nmtst_dns_create_resolv_conf(const char *const *searches,

View file

@ -17,11 +17,16 @@
/*****************************************************************************/
enum {
UPDATE_PENDING_CHANGED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = {0};
typedef struct _NMDnsPluginPrivate {
GPid pid;
guint watch_id;
char *progname;
char *pidfile;
bool update_pending_inited : 1;
bool update_pending : 1;
} NMDnsPluginPrivate;
G_DEFINE_ABSTRACT_TYPE(NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT)
@ -32,26 +37,29 @@ G_DEFINE_ABSTRACT_TYPE(NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT)
#define _NMLOG_PREFIX_NAME "dns-plugin"
#define _NMLOG_DOMAIN LOGD_DNS
#define _NMLOG(level, ...) \
G_STMT_START \
{ \
const NMLogLevel __level = (level); \
\
if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
char __prefix[20]; \
const NMDnsPlugin *const __self = (self); \
\
_nm_log(__level, \
_NMLOG_DOMAIN, \
0, \
NULL, \
NULL, \
"%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
_NMLOG_PREFIX_NAME, \
(!__self ? "" : nm_sprintf_buf(__prefix, "[%p]", __self)) \
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} \
} \
#define _NMLOG(level, ...) \
G_STMT_START \
{ \
const NMLogLevel __level = (level); \
\
if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
char __prefix[20]; \
const NMDnsPlugin *const __self = (self); \
\
_nm_log(__level, \
_NMLOG_DOMAIN, \
0, \
NULL, \
NULL, \
"%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
_NMLOG_PREFIX_NAME, \
(!__self ? "" \
: nm_sprintf_buf(__prefix, \
"[" NM_HASH_OBFUSCATE_PTR_FMT "]", \
NM_HASH_OBFUSCATE_PTR( \
__self))) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} \
} \
G_STMT_END
/*****************************************************************************/
@ -104,10 +112,109 @@ nm_dns_plugin_stop(NMDnsPlugin *self)
/*****************************************************************************/
static void
nm_dns_plugin_init(NMDnsPlugin *self)
{}
static gboolean
_get_update_pending(NMDnsPlugin *self)
{
NMDnsPluginClass *klass;
nm_assert(NM_IS_DNS_PLUGIN(self));
klass = NM_DNS_PLUGIN_GET_CLASS(self);
if (klass->get_update_pending) {
if (klass->get_update_pending(self))
return TRUE;
}
return FALSE;
}
gboolean
nm_dns_plugin_get_update_pending(NMDnsPlugin *self)
{
NMDnsPluginPrivate *priv;
g_return_val_if_fail(NM_IS_DNS_PLUGIN(self), FALSE);
priv = NM_DNS_PLUGIN_GET_PRIVATE(self);
/* We cache the boolean and rely on the subclass to call
* _nm_dns_plugin_update_pending_maybe_changed(). The subclass
* anyway must get it right to notify us when the value (maybe)
* changes. By caching the value, the subclass is free to notify
* even if the value did not actually change.
*
* Also, this allows the base implementation to combine multiple
* sources/reasons (if we need that in the future). */
if (!priv->update_pending_inited) {
priv->update_pending_inited = TRUE;
priv->update_pending = _get_update_pending(self);
_LOGD("[%s] update-pending changed (%spending)",
nm_dns_plugin_get_name(self),
priv->update_pending ? "" : "not ");
} else
nm_assert(priv->update_pending == _get_update_pending(self));
return priv->update_pending;
}
void
_nm_dns_plugin_update_pending_maybe_changed(NMDnsPlugin *self)
{
NMDnsPluginPrivate *priv;
gboolean v;
g_return_if_fail(NM_IS_DNS_PLUGIN(self));
priv = NM_DNS_PLUGIN_GET_PRIVATE(self);
v = _get_update_pending(self);
if (!priv->update_pending_inited)
priv->update_pending_inited = TRUE;
else if (priv->update_pending == v)
return;
priv->update_pending = v;
_LOGD("[%s] update-pending changed (%spending)",
nm_dns_plugin_get_name(self),
priv->update_pending ? "" : "not ");
g_signal_emit(self, signals[UPDATE_PENDING_CHANGED], 0, (gboolean) priv->update_pending);
}
/*****************************************************************************/
static void
nm_dns_plugin_class_init(NMDnsPluginClass *plugin_class)
{}
nm_dns_plugin_init(NMDnsPlugin *self)
{
NMDnsPluginPrivate *priv;
priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_DNS_PLUGIN, NMDnsPluginPrivate);
self->_priv = priv;
nm_assert(priv->update_pending_inited == FALSE);
nm_assert(priv->update_pending == FALSE);
nm_shutdown_wait_obj_register_object(self, "dns-plugin");
}
static void
nm_dns_plugin_class_init(NMDnsPluginClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
g_type_class_add_private(object_class, sizeof(NMDnsPluginPrivate));
signals[UPDATE_PENDING_CHANGED] = g_signal_new(NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED,
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
1,
G_TYPE_BOOLEAN);
}

View file

@ -19,8 +19,13 @@
#define NM_DNS_PLUGIN_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass))
#define NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED "update-pending-changed"
struct _NMDnsPluginPrivate;
typedef struct {
GObject parent;
GObject parent;
struct _NMDnsPluginPrivate *_priv;
} NMDnsPlugin;
typedef struct {
@ -39,6 +44,8 @@ typedef struct {
void (*stop)(NMDnsPlugin *self);
gboolean (*get_update_pending)(NMDnsPlugin *self);
const char *plugin_name;
/* Types should set to TRUE if they start a local caching nameserver
@ -63,4 +70,8 @@ gboolean nm_dns_plugin_update(NMDnsPlugin *self,
void nm_dns_plugin_stop(NMDnsPlugin *self);
gboolean nm_dns_plugin_get_update_pending(NMDnsPlugin *self);
void _nm_dns_plugin_update_pending_maybe_changed(NMDnsPlugin *self);
#endif /* __NM_DNS_PLUGIN_H__ */

View file

@ -40,8 +40,8 @@ static const char *const DBUS_OP_SET_LINK_DNS_OVER_TLS = "SetLinkDNSOverTLS";
/*****************************************************************************/
typedef struct {
int ifindex;
CList configs_lst_head;
int ifindex;
GPtrArray *ip_data_list;
} InterfaceConfig;
typedef struct {
@ -50,6 +50,7 @@ typedef struct {
GVariant *argument;
NMDnsSystemdResolved *self;
int ifindex;
int ref_count;
} RequestItem;
struct _NMDnsSystemdResolvedResolveHandle {
@ -82,10 +83,13 @@ typedef struct {
char *dbus_owner;
CList handle_lst_head;
guint name_owner_changed_id;
guint n_pending;
bool send_updates_warn_ratelimited : 1;
bool try_start_blocked : 1;
bool stopped : 1;
bool dbus_initied : 1;
bool send_updates_waiting : 1;
bool update_pending : 1;
/* These two variables ensure that the log is not spammed with
* API (not) supported messages.
* They can be removed when no distro uses systemd-resolved < v240 anymore
@ -106,7 +110,7 @@ struct _NMDnsSystemdResolvedClass {
G_DEFINE_TYPE(NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN)
#define NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self) \
_NM_GET_PRIVATE(self, NMDnsSystemdResolved, NM_IS_DNS_SYSTEMD_RESOLVED)
_NM_GET_PRIVATE(self, NMDnsSystemdResolved, NM_IS_DNS_SYSTEMD_RESOLVED, NMDnsPlugin)
/*****************************************************************************/
@ -146,10 +150,88 @@ static void _resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResol
/*****************************************************************************/
static void
_request_item_free(RequestItem *request_item)
static gboolean
_update_pending_detect(NMDnsSystemdResolved *self)
{
c_list_unlink_stale(&request_item->request_queue_lst);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
if (priv->n_pending > 0) {
/* we have pending calls. We definitely want to wait for them to complete. */
return TRUE;
}
if (!priv->dbus_initied) {
if (!priv->dbus_connection)
return FALSE;
/* D-Bus not yet initialized (and we don't know the name owner yet). Pending. */
return TRUE;
}
if (priv->try_start_timeout_source) {
/* We are waiting to D-Bus activate resolved. Pending. */
return TRUE;
}
if (priv->try_start_blocked) {
/* We earlier tried to start resolved, but are rate limited. We are not pending an update
* (that we expect to complete any time soon). */
return FALSE;
}
if (priv->send_updates_waiting) {
/* we wait to send updates. We are pending. */
return TRUE;
}
return FALSE;
}
static void
_update_pending_maybe_changed(NMDnsSystemdResolved *self)
{
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
gboolean update_pending;
/* Important: we need to make sure that we call _update_pending_maybe_changed(), when
* the state changes. */
update_pending = _update_pending_detect(self);
if (priv->update_pending != update_pending) {
priv->update_pending = update_pending;
_nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self));
}
}
static gboolean
get_update_pending(NMDnsPlugin *plugin)
{
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
nm_assert(priv->update_pending == _update_pending_detect(self));
return priv->update_pending;
}
/*****************************************************************************/
static RequestItem *
_request_item_ref(RequestItem *request_item)
{
nm_assert(request_item);
nm_assert(request_item->ref_count > 0);
nm_assert(request_item->ref_count < G_MAXINT);
nm_assert(!c_list_is_empty(&request_item->request_queue_lst));
request_item->ref_count++;
return request_item;
}
static void
_request_item_unref(RequestItem *request_item)
{
nm_assert(request_item);
nm_assert(request_item->ref_count > 0);
if (--request_item->ref_count > 0)
return;
nm_assert(c_list_is_empty(&request_item->request_queue_lst));
g_variant_unref(request_item->argument);
nm_g_slice_free(request_item);
}
@ -165,6 +247,7 @@ _request_item_append(NMDnsSystemdResolved *self,
request_item = g_slice_new(RequestItem);
*request_item = (RequestItem){
.ref_count = 1,
.operation = operation,
.argument = g_variant_ref_sink(argument),
.self = self,
@ -178,8 +261,8 @@ _request_item_append(NMDnsSystemdResolved *self,
static void
_interface_config_free(InterfaceConfig *config)
{
nm_c_list_elem_free_all(&config->configs_lst_head, NULL);
g_slice_free(InterfaceConfig, config);
nm_g_ptr_array_unref(config->ip_data_list);
nm_g_slice_free(config);
}
static void
@ -191,42 +274,48 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data)
NMDnsSystemdResolvedPrivate *priv;
RequestItem *request_item;
NMLogLevel log_level;
v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), r, &error);
if (nm_utils_error_is_cancelled(error))
return;
const char *operation;
int ifindex;
request_item = user_data;
self = request_item->self;
priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
operation = request_item->operation;
ifindex = request_item->ifindex;
_request_item_unref(request_item);
priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), r, &error);
if (nm_utils_error_is_cancelled(error))
goto out_dec_pending;
if (v) {
if (request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE
if (operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE
&& priv->has_link_default_route == NM_TERNARY_DEFAULT) {
priv->has_link_default_route = NM_TERNARY_TRUE;
_LOGD("systemd-resolved support for SetLinkDefaultRoute(): API supported");
}
if (request_item->operation == DBUS_OP_SET_LINK_DNS_OVER_TLS
if (operation == DBUS_OP_SET_LINK_DNS_OVER_TLS
&& priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT) {
priv->has_link_dns_over_tls = NM_TERNARY_TRUE;
_LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API supported");
}
priv->send_updates_warn_ratelimited = FALSE;
return;
goto out_dec_pending;
}
if (nm_g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
if (priv->has_link_default_route == NM_TERNARY_DEFAULT
&& request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) {
&& operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) {
priv->has_link_default_route = NM_TERNARY_FALSE;
_LOGD("systemd-resolved support for SetLinkDefaultRoute(): API not supported");
}
if (priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT
&& request_item->operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) {
&& operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) {
priv->has_link_dns_over_tls = NM_TERNARY_FALSE;
_LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API not supported");
}
return;
goto out_dec_pending;
}
log_level = LOGL_DEBUG;
@ -234,18 +323,25 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data)
priv->send_updates_warn_ratelimited = TRUE;
log_level = LOGL_WARN;
}
_NMLOG(log_level,
"send-updates %s@%d failed: %s",
request_item->operation,
request_item->ifindex,
error->message);
_NMLOG(log_level, "send-updates %s@%d failed: %s", operation, ifindex, error->message);
out_dec_pending:
nm_assert(priv->n_pending > 0);
if (--priv->n_pending <= 0) {
_update_pending_maybe_changed(self);
/* We keep @self alive while pending operations are in progress. It's simpler
* to implement. But this requires that we implement "stop()" signal to cancel
* all pending requests. Cancelling is necessary, because during shutdown,
* we must wrap up fast, and not hang an undefined amount time. */
g_object_unref(self);
}
}
static gboolean
update_add_ip_config(NMDnsSystemdResolved *self,
GVariantBuilder *dns,
GVariantBuilder *domains,
NMDnsConfigIPData *ip_data)
update_add_ip_config(NMDnsSystemdResolved *self,
GVariantBuilder *dns,
GVariantBuilder *domains,
const NMDnsConfigIPData *ip_data)
{
gsize addr_size;
guint n;
@ -258,8 +354,12 @@ update_add_ip_config(NMDnsSystemdResolved *self,
addr_size = nm_utils_addr_family_to_size(ip_data->addr_family);
if ((!ip_data->domains.search || !ip_data->domains.search[0])
&& !ip_data->domains.has_default_route_exclusive && !ip_data->domains.has_default_route)
&& !ip_data->domains.has_default_route_exclusive && !ip_data->domains.has_default_route) {
/* we have no search domain (which systemd-resolved uses to routing the request), but
* also the "DefaultRoute" is not set on the interface. This setting has no effect and
* gets ignored. */
return FALSE;
}
nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &n);
for (i = 0; i < n; i++) {
@ -295,23 +395,28 @@ free_pending_updates(NMDnsSystemdResolved *self)
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
RequestItem *request_item;
while ((request_item =
c_list_first_entry(&priv->request_queue_lst_head, RequestItem, request_queue_lst)))
_request_item_free(request_item);
while (
(request_item =
c_list_first_entry(&priv->request_queue_lst_head, RequestItem, request_queue_lst))) {
c_list_unlink(&request_item->request_queue_lst);
_request_item_unref(request_item);
}
}
static gboolean
prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic)
{
GVariantBuilder dns;
GVariantBuilder domains;
NMCListElem *elem;
NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT;
const char *mdns_arg = NULL, *llmnr_arg = NULL, *dns_over_tls_arg = NULL;
NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT;
const char *mdns_arg = NULL;
const char *llmnr_arg = NULL;
const char *dns_over_tls_arg = NULL;
gboolean has_config = FALSE;
gboolean has_default_route = FALSE;
guint i;
g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))"));
g_variant_builder_add(&dns, "i", ic->ifindex);
@ -321,18 +426,22 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
g_variant_builder_add(&domains, "i", ic->ifindex);
g_variant_builder_open(&domains, G_VARIANT_TYPE("a(sb)"));
c_list_for_each_entry (elem, &ic->configs_lst_head, lst) {
NMDnsConfigIPData *ip_data = elem->data;
if (ic->ip_data_list) {
for (i = 0; i < ic->ip_data_list->len; i++) {
const NMDnsConfigIPData *ip_data = ic->ip_data_list->pdata[i];
has_config |= update_add_ip_config(self, &dns, &domains, ip_data);
if (update_add_ip_config(self, &dns, &domains, ip_data))
has_config = TRUE;
if (ip_data->domains.has_default_route)
has_default_route = TRUE;
if (ip_data->domains.has_default_route)
has_default_route = TRUE;
if (NM_IS_IPv4(ip_data->addr_family)) {
mdns = NM_MAX(mdns, nm_l3_config_data_get_mdns(ip_data->l3cd));
llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd));
dns_over_tls = NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd));
if (NM_IS_IPv4(ip_data->addr_family)) {
mdns = NM_MAX(mdns, nm_l3_config_data_get_mdns(ip_data->l3cd));
llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd));
dns_over_tls =
NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd));
}
}
}
@ -439,6 +548,7 @@ again:
goto again;
}
_update_pending_maybe_changed(self);
return G_SOURCE_CONTINUE;
}
@ -447,6 +557,9 @@ ensure_resolved_running(NMDnsSystemdResolved *self)
{
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
if (priv->stopped)
return NM_TERNARY_FALSE;
if (!priv->dbus_initied)
return NM_TERNARY_DEFAULT;
@ -469,6 +582,7 @@ ensure_resolved_running(NMDnsSystemdResolved *self)
NULL,
NULL,
NULL);
_update_pending_maybe_changed(self);
return NM_TERNARY_DEFAULT;
}
@ -523,6 +637,12 @@ send_updates(NMDnsSystemdResolved *self)
request_item->operation,
(ss = g_variant_print(request_item->argument, FALSE)));
if (priv->n_pending++ == 0) {
/* We are inside send_updates(). All callers are already calling
* _update_pending_maybe_changed() afterwards. */
g_object_ref(self);
}
g_dbus_connection_call(priv->dbus_connection,
priv->dbus_owner,
SYSTEMD_RESOLVED_DBUS_PATH,
@ -534,7 +654,7 @@ send_updates(NMDnsSystemdResolved *self)
-1,
priv->cancellable,
call_done,
request_item);
_request_item_ref(request_item));
}
start_resolve:
@ -554,43 +674,54 @@ update(NMDnsPlugin *plugin,
const char *hostdomain,
GError **error)
{
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
gs_unref_hashtable GHashTable *interfaces = NULL;
gs_free gpointer *interfaces_keys = NULL;
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
gs_unref_hashtable GHashTable *interfaces = NULL;
const NMUtilsNamedValue *interfaces_arr;
NMUtilsNamedValue interfaces_arr_stack[50];
gs_free NMUtilsNamedValue *interfaces_arr_heap = NULL;
guint interfaces_len;
int ifindex;
gpointer pointer;
NMDnsConfigIPData *ip_data;
GHashTableIter iter;
gs_unref_array GArray *dirty_array = NULL;
guint i;
nm_assert(!priv->stopped);
/* Group configs by ifindex/interfaces. */
interfaces =
g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) _interface_config_free);
c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) {
InterfaceConfig *ic = NULL;
InterfaceConfig *ic = NULL;
int ifindex = ip_data->data->ifindex;
ifindex = ip_data->data->ifindex;
nm_assert(ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd));
ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex));
if (!ic) {
ic = g_slice_new(InterfaceConfig);
ic->ifindex = ifindex;
c_list_init(&ic->configs_lst_head);
ic = g_slice_new(InterfaceConfig);
*ic = (InterfaceConfig){
.ifindex = ifindex,
.ip_data_list = g_ptr_array_sized_new(4),
};
g_hash_table_insert(interfaces, GINT_TO_POINTER(ifindex), ic);
}
c_list_link_tail(&ic->configs_lst_head, &nm_c_list_elem_new_stale(ip_data)->lst);
g_ptr_array_add(ic->ip_data_list, ip_data);
}
free_pending_updates(self);
interfaces_keys =
nm_utils_hash_keys_to_array(interfaces, nm_cmp_int2ptr_p_with_data, NULL, &interfaces_len);
interfaces_arr = nm_utils_hash_to_array_with_buffer(interfaces,
&interfaces_len,
nm_cmp_int2ptr_p_with_data,
NULL,
interfaces_arr_stack,
&interfaces_arr_heap);
for (i = 0; i < interfaces_len; i++) {
InterfaceConfig *ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(interfaces_keys[i]));
const InterfaceConfig *ic = interfaces_arr[i].value_ptr;
if (prepare_one_interface(self, ic))
g_hash_table_add(priv->dirty_interfaces, GINT_TO_POINTER(ic->ifindex));
@ -602,23 +733,38 @@ update(NMDnsPlugin *plugin,
* resolved, and the current update doesn't contain that interface,
* reset the resolved configuration for that ifindex. */
g_hash_table_iter_init(&iter, priv->dirty_interfaces);
while (g_hash_table_iter_next(&iter, (gpointer *) &pointer, NULL)) {
ifindex = GPOINTER_TO_INT(pointer);
if (!g_hash_table_contains(interfaces, GINT_TO_POINTER(ifindex))) {
while (g_hash_table_iter_next(&iter, &pointer, NULL)) {
int ifindex = GPOINTER_TO_INT(pointer);
if (g_hash_table_contains(interfaces, GINT_TO_POINTER(ifindex))) {
/* the interface is still tracked and still dirty. Keep. */
continue;
}
if (!dirty_array)
dirty_array = g_array_new(FALSE, FALSE, sizeof(int));
g_array_append_val(dirty_array, ifindex);
g_hash_table_iter_remove(&iter);
}
if (dirty_array) {
g_array_sort_with_data(dirty_array, nm_cmp_int2ptr_p_with_data, NULL);
for (i = 0; i < dirty_array->len; i++) {
int ifindex = g_array_index(dirty_array, int, i);
InterfaceConfig ic;
_LOGT("clear previously configured ifindex %d", ifindex);
ic = (InterfaceConfig){
.ifindex = ifindex,
.configs_lst_head = C_LIST_INIT(ic.configs_lst_head),
.ifindex = ifindex,
.ip_data_list = NULL,
};
prepare_one_interface(self, &ic);
g_hash_table_iter_remove(&iter);
}
}
priv->send_updates_waiting = TRUE;
send_updates(self);
_update_pending_maybe_changed(self);
return TRUE;
}
@ -649,6 +795,7 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner)
}
send_updates(self);
_update_pending_maybe_changed(self);
}
static void
@ -956,6 +1103,48 @@ nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle
/*****************************************************************************/
static void
stop(NMDnsPlugin *plugin)
{
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
NMDnsSystemdResolvedResolveHandle *handle;
/* This function must be re-entrant!!
*
* Currently there is no concept of unregistering/shutting down. It's not
* clear whether we should de-configure anything in systemd-resolved, we
* don't.
*
* Implementing stop() is important because pending operations take a
* reference on @self. We can only cancel (fast shutdown) the instance
* by cancelling those requests. */
priv->stopped = TRUE;
priv->try_start_blocked = TRUE;
nm_clear_g_cancellable(&priv->cancellable);
nm_clear_g_free(&priv->dbus_owner);
while ((handle = c_list_first_entry(&priv->handle_lst_head,
NMDnsSystemdResolvedResolveHandle,
handle_lst))) {
gs_free_error GError *error = NULL;
nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved");
_resolve_complete_error(handle, error);
}
free_pending_updates(self);
nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id);
nm_clear_g_source_inst(&priv->try_start_timeout_source);
}
/*****************************************************************************/
static void
nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self)
{
@ -974,6 +1163,8 @@ nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self)
return;
}
priv->update_pending = TRUE;
priv->name_owner_changed_id =
nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection,
SYSTEMD_RESOLVED_DBUS_SERVICE,
@ -998,33 +1189,15 @@ nm_dns_systemd_resolved_new(void)
static void
dispose(GObject *object)
{
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(object);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
NMDnsSystemdResolvedResolveHandle *handle;
NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(object);
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
while ((handle = c_list_first_entry(&priv->handle_lst_head,
NMDnsSystemdResolvedResolveHandle,
handle_lst))) {
gs_free_error GError *error = NULL;
nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved");
_resolve_complete_error(handle, error);
}
free_pending_updates(self);
nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id);
nm_clear_g_cancellable(&priv->cancellable);
nm_clear_g_source_inst(&priv->try_start_timeout_source);
stop(NM_DNS_PLUGIN(self));
g_clear_object(&priv->dbus_connection);
nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_unref);
nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_destroy);
G_OBJECT_CLASS(nm_dns_systemd_resolved_parent_class)->dispose(object);
nm_clear_g_free(&priv->dbus_owner);
}
static void
@ -1035,7 +1208,9 @@ nm_dns_systemd_resolved_class_init(NMDnsSystemdResolvedClass *dns_class)
object_class->dispose = dispose;
plugin_class->plugin_name = "systemd-resolved";
plugin_class->is_caching = TRUE;
plugin_class->update = update;
plugin_class->plugin_name = "systemd-resolved";
plugin_class->is_caching = TRUE;
plugin_class->stop = stop;
plugin_class->update = update;
plugin_class->get_update_pending = get_update_pending;
}

View file

@ -1,84 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2014 Red Hat, Inc.
* Author: Pavel Šimerda <psimerda@redhat.com>
*/
#include "src/core/nm-default-daemon.h"
#include "nm-dns-unbound.h"
#include "NetworkManagerUtils.h"
/*****************************************************************************/
struct _NMDnsUnbound {
NMDnsPlugin parent;
};
struct _NMDnsUnboundClass {
NMDnsPluginClass parent;
};
G_DEFINE_TYPE(NMDnsUnbound, nm_dns_unbound, NM_TYPE_DNS_PLUGIN)
/*****************************************************************************/
static gboolean
update(NMDnsPlugin *plugin,
const NMGlobalDnsConfig *global_config,
const CList *ip_config_lst_head,
const char *hostdomain,
GError **error)
{
char *argv[] = {DNSSEC_TRIGGER_PATH, "--async", "--update", NULL};
gs_free_error GError *local = NULL;
int status;
/* TODO: We currently call a script installed with the dnssec-trigger
* package that queries all information itself. Later, the dependency
* on that package will be optional and the only hard dependency will
* be unbound.
*
* Unbound configuration should be later handled by this plugin directly,
* without calling custom scripts. The dnssec-trigger functionality
* may be eventually merged into NetworkManager.
*/
if (!g_spawn_sync("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, &local)) {
nm_utils_error_set(error,
NM_UTILS_ERROR_UNKNOWN,
"error spawning dns-trigger: %s",
local->message);
return FALSE;
}
if (status != 0) {
nm_utils_error_set(error,
NM_UTILS_ERROR_UNKNOWN,
"dns-trigger exited with error code %d",
status);
return FALSE;
}
return TRUE;
}
/*****************************************************************************/
static void
nm_dns_unbound_init(NMDnsUnbound *unbound)
{}
NMDnsPlugin *
nm_dns_unbound_new(void)
{
return g_object_new(NM_TYPE_DNS_UNBOUND, NULL);
}
static void
nm_dns_unbound_class_init(NMDnsUnboundClass *klass)
{
NMDnsPluginClass *plugin_class = NM_DNS_PLUGIN_CLASS(klass);
plugin_class->plugin_name = "unbound";
plugin_class->is_caching = TRUE;
plugin_class->update = update;
}

View file

@ -1,27 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2014 Red Hat, Inc.
*/
#ifndef __NETWORKMANAGER_DNS_UNBOUND_H__
#define __NETWORKMANAGER_DNS_UNBOUND_H__
#include "nm-dns-plugin.h"
#define NM_TYPE_DNS_UNBOUND (nm_dns_unbound_get_type())
#define NM_DNS_UNBOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_UNBOUND, NMDnsUnbound))
#define NM_DNS_UNBOUND_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_UNBOUND, NMDnsUnboundClass))
#define NM_IS_DNS_UNBOUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNS_UNBOUND))
#define NM_IS_DNS_UNBOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DNS_UNBOUND))
#define NM_DNS_UNBOUND_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_UNBOUND, NMDnsUnboundClass))
typedef struct _NMDnsUnbound NMDnsUnbound;
typedef struct _NMDnsUnboundClass NMDnsUnboundClass;
GType nm_dns_unbound_get_type(void);
NMDnsPlugin *nm_dns_unbound_new(void);
#endif /* __NETWORKMANAGER_DNS_UNBOUND_H__ */

View file

@ -123,7 +123,6 @@ libNetworkManager = static_library(
'dns/nm-dns-manager.c',
'dns/nm-dns-plugin.c',
'dns/nm-dns-systemd-resolved.c',
'dns/nm-dns-unbound.c',
'dnsmasq/nm-dnsmasq-manager.c',
'dnsmasq/nm-dnsmasq-utils.c',
'ppp/nm-ppp-manager-call.c',

View file

@ -11,7 +11,9 @@
#include <stdio.h>
#include "nm-utils.h"
#include "nm-dhcp-config.h"
#include "devices/nm-device.h"
#include "dhcp/nm-dhcp-options.h"
#include "NetworkManagerUtils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-core-intern/nm-keyfile-internal.h"
@ -2573,13 +2575,16 @@ nm_config_device_state_write(int ifindex,
NMTernary nm_owned,
guint32 route_metric_default_aspired,
guint32 route_metric_default_effective,
const char *next_server,
const char *root_path,
const char *dhcp_bootfile)
NMDhcpConfig *dhcp4_config,
NMDhcpConfig *dhcp6_config)
{
char path[NM_STRLEN(NM_CONFIG_DEVICE_STATE_DIR "/") + DEVICE_STATE_FILENAME_LEN_MAX + 1];
GError *local = NULL;
nm_auto_unref_keyfile GKeyFile *kf = NULL;
GError *local = NULL;
nm_auto_unref_keyfile GKeyFile *kf = NULL;
const char *root_path = NULL;
const char *next_server = NULL;
const char *dhcp_bootfile = NULL;
int IS_IPv4;
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(!connection_uuid || *connection_uuid, FALSE);
@ -2630,6 +2635,15 @@ nm_config_device_state_write(int ifindex,
route_metric_default_aspired);
}
}
if (dhcp4_config) {
next_server = nm_dhcp_config_get_option(dhcp4_config, "next_server");
root_path = nm_dhcp_config_get_option(dhcp4_config, "root_path");
dhcp_bootfile = nm_dhcp_config_get_option(dhcp4_config, "filename");
if (!dhcp_bootfile)
dhcp_bootfile = nm_dhcp_config_get_option(dhcp4_config, "bootfile_name");
}
if (next_server) {
g_key_file_set_string(kf,
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
@ -2649,6 +2663,28 @@ nm_config_device_state_write(int ifindex,
dhcp_bootfile);
}
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
NMDhcpConfig *dhcp_config = IS_IPv4 ? dhcp4_config : dhcp6_config;
gs_free NMUtilsNamedValue *values = NULL;
guint i;
guint num;
if (!dhcp_config)
continue;
values = nm_dhcp_config_get_option_values(dhcp_config, &num);
for (i = 0; i < num; i++) {
gs_free char *name_full = NULL;
const char *prefix = IS_IPv4 ? "dhcp4" : "dhcp6";
if (NM_STR_HAS_PREFIX(values[i].name, NM_DHCP_OPTION_REQPREFIX))
continue;
name_full = g_strdup_printf("%s.%s", prefix, values[i].name);
g_key_file_set_string(kf, prefix, name_full, values[i].value_str);
}
}
if (!g_key_file_save_to_file(kf, path, &local)) {
_LOGW("device-state: write #%d (%s) failed: %s", ifindex, path, local->message);
g_error_free(local);

View file

@ -183,9 +183,8 @@ gboolean nm_config_device_state_write(int
NMTernary nm_owned,
guint32 route_metric_default_aspired,
guint32 route_metric_default_effective,
const char *next_server,
const char *root_path,
const char *dhcp_bootfile);
NMDhcpConfig *dhcp4_config,
NMDhcpConfig *dhcp6_config);
void nm_config_device_state_prune_stale(GHashTable *preserve_ifindexes,
NMPlatform *preserve_in_platform);

View file

@ -30,7 +30,6 @@
#include "libnm-glib-aux/nm-secret-utils.h"
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "nm-utils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-setting-connection.h"
@ -5114,7 +5113,7 @@ nm_utils_spawn_helper(const char *const *args,
fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
/* Watch process stdin */
nm_str_buf_init(&info->out_buffer, 32, TRUE);
info->out_buffer = NM_STR_BUF_INIT(32, TRUE);
for (arg = args; *arg; arg++) {
nm_str_buf_append(&info->out_buffer, *arg);
nm_str_buf_append_c(&info->out_buffer, '\0');
@ -5128,7 +5127,7 @@ nm_utils_spawn_helper(const char *const *args,
g_source_attach(info->output_source, g_main_context_get_thread_default());
/* Watch process stdout */
nm_str_buf_init(&info->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
info->in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
info->input_source = nm_g_unix_fd_source_new(info->child_stdout,
G_IO_IN | G_IO_ERR | G_IO_HUP,
G_PRIORITY_DEFAULT,
@ -5223,7 +5222,7 @@ again:
* @shortened: (out) (transfer full): on return, the shortened hostname
*
* Checks whether the input hostname is valid. If not, tries to shorten it
* to HOST_NAME_MAX or to the first dot, whatever comes earlier.
* to HOST_NAME_MAX (64) or to the first dot, whatever comes earlier.
* The new hostname is returned in @shortened.
*
* Returns: %TRUE if the input hostname was already valid or if was shortened
@ -5239,7 +5238,7 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened)
nm_assert(hostname);
nm_assert(shortened);
if (nm_sd_hostname_is_valid(hostname, FALSE)) {
if (nm_hostname_is_valid(hostname, FALSE)) {
*shortened = NULL;
return TRUE;
}
@ -5249,11 +5248,11 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened)
l = (dot - hostname);
else
l = strlen(hostname);
l = MIN(l, (gsize) HOST_NAME_MAX);
l = MIN(l, (gsize) NM_HOST_NAME_MAX);
s = g_strndup(hostname, l);
if (!nm_sd_hostname_is_valid(s, FALSE)) {
if (!nm_hostname_is_valid(s, FALSE)) {
*shortened = NULL;
return FALSE;
}

View file

@ -125,6 +125,29 @@ nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd)
_notify(self, PROP_OPTIONS);
}
NMUtilsNamedValue *
nm_dhcp_config_get_option_values(NMDhcpConfig *self, guint *num)
{
NMDhcpConfigPrivate *priv = NM_DHCP_CONFIG_GET_PRIVATE(self);
NMDhcpLease *lease;
NMUtilsNamedValue *buffer = NULL;
if (!priv->l3cd) {
NM_SET_OUT(num, 0);
return NULL;
}
lease = nm_l3_config_data_get_dhcp_lease(priv->l3cd, nm_dhcp_config_get_addr_family(self));
nm_utils_named_values_from_strdict_full(nm_dhcp_lease_get_options(lease),
num,
nm_strcmp_p_with_data,
NULL,
NULL,
0,
&buffer);
return buffer;
}
const char *
nm_dhcp_config_get_option(NMDhcpConfig *self, const char *key)
{

View file

@ -30,7 +30,8 @@ int nm_dhcp_config_get_addr_family(NMDhcpConfig *self);
void nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd);
const char *nm_dhcp_config_get_option(NMDhcpConfig *self, const char *option);
NMUtilsNamedValue *nm_dhcp_config_get_option_values(NMDhcpConfig *self, guint *num);
const char *nm_dhcp_config_get_option(NMDhcpConfig *self, const char *option);
GVariant *nm_dhcp_config_get_options(NMDhcpConfig *self);

View file

@ -679,8 +679,7 @@ _fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen)
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
&ss1));
stdin_buf = g_bytes_new_static(nm_str_buf_get_str(&strbuf), strbuf.len);
stdin_buf = nm_str_buf_finalize_to_gbytes(&strbuf);
_fw_nft_call_sync(stdin_buf, NULL);
}

View file

@ -20,6 +20,7 @@
#include "devices/nm-device-factory.h"
#include "devices/nm-device-generic.h"
#include "devices/nm-device.h"
#include "dns/nm-dns-manager.h"
#include "dhcp/nm-dhcp-manager.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "libnm-core-intern/nm-core-internal.h"
@ -144,6 +145,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMManager,
typedef struct {
NMPlatform *platform;
NMDnsManager *dns_mgr;
gulong dns_mgr_update_pending_signal_id;
GArray *capabilities;
CList active_connections_lst_head; /* Oldest ACs at the beginning */
@ -346,6 +350,9 @@ static NMActiveConnection *_new_active_connection(NMManager *self,
static void policy_activating_ac_changed(GObject *object, GParamSpec *pspec, gpointer user_data);
static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self);
static void check_if_startup_complete(NMManager *self);
static gboolean find_master(NMManager *self,
NMConnection *connection,
NMDevice *device,
@ -1601,7 +1608,11 @@ manager_device_state_changed(NMDevice *device,
nm_settings_device_added(priv->settings, device);
}
static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self);
static void
_dns_mgr_update_pending_cb(NMDevice *device, GParamSpec *pspec, NMManager *self)
{
check_if_startup_complete(self);
}
static void
check_if_startup_complete(NMManager *self)
@ -1616,6 +1627,20 @@ check_if_startup_complete(NMManager *self)
if (!priv->devices_inited)
return;
if (nm_dns_manager_get_update_pending(nm_manager_get_dns_manager(self))) {
if (priv->dns_mgr_update_pending_signal_id == 0) {
priv->dns_mgr_update_pending_signal_id =
g_signal_connect(nm_manager_get_dns_manager(self),
"notify::" NM_DNS_MANAGER_UPDATE_PENDING,
G_CALLBACK(_dns_mgr_update_pending_cb),
self);
}
return;
}
nm_clear_g_signal_handler(nm_manager_get_dns_manager(self),
&priv->dns_mgr_update_pending_signal_id);
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
reason = nm_device_has_pending_action_reason(device);
if (reason) {
@ -7014,10 +7039,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
guint32 route_metric_default_aspired;
guint32 route_metric_default_effective;
NMTernary nm_owned;
NMDhcpConfig *dhcp_config;
const char *next_server = NULL;
const char *root_path = NULL;
const char *dhcp_bootfile = NULL;
NM_SET_OUT(out_ifindex, 0);
@ -7059,15 +7080,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
TRUE,
&route_metric_default_aspired);
dhcp_config = nm_device_get_dhcp_config(device, AF_INET);
if (dhcp_config) {
root_path = nm_dhcp_config_get_option(dhcp_config, "root_path");
next_server = nm_dhcp_config_get_option(dhcp_config, "next_server");
dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "filename");
if (!dhcp_bootfile)
dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "bootfile_name");
}
if (!nm_config_device_state_write(ifindex,
managed_type,
perm_hw_addr_fake,
@ -7075,9 +7087,8 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
nm_owned,
route_metric_default_aspired,
route_metric_default_effective,
next_server,
root_path,
dhcp_bootfile))
nm_device_get_dhcp_config(device, AF_INET),
nm_device_get_dhcp_config(device, AF_INET6)))
return FALSE;
NM_SET_OUT(out_ifindex, ifindex);
@ -7790,6 +7801,28 @@ impl_manager_checkpoint_adjust_rollback_timeout(NMDBusObject
/*****************************************************************************/
NMDnsManager *
nm_manager_get_dns_manager(NMManager *self)
{
NMManagerPrivate *priv;
g_return_val_if_fail(NM_IS_MANAGER(self), NULL);
priv = NM_MANAGER_GET_PRIVATE(self);
if (G_UNLIKELY(!priv->dns_mgr)) {
/* Initialize lazily on first use.
*
* But keep a reference. This is to ensure proper lifetimes between
* singleton instances (i.e. nm_dns_manager_get() outlives NMManager). */
priv->dns_mgr = g_object_ref(nm_dns_manager_get());
}
return priv->dns_mgr;
}
/*****************************************************************************/
static void
auth_mgr_changed(NMAuthManager *auth_manager, gpointer user_data)
{
@ -8250,6 +8283,9 @@ dispose(GObject *object)
g_clear_object(&priv->concheck_mgr);
}
nm_clear_g_signal_handler(priv->dns_mgr, &priv->dns_mgr_update_pending_signal_id);
g_clear_object(&priv->dns_mgr);
if (priv->auth_mgr) {
g_signal_handlers_disconnect_by_func(priv->auth_mgr, G_CALLBACK(auth_mgr_changed), self);
g_clear_object(&priv->auth_mgr);

View file

@ -200,6 +200,10 @@ NMMetered nm_manager_get_metered(NMManager *self);
void nm_manager_notify_device_availability_maybe_changed(NMManager *self);
struct _NMDnsManager;
struct _NMDnsManager *nm_manager_get_dns_manager(NMManager *self);
/*****************************************************************************/
void nm_manager_device_auth_request(NMManager *self,

View file

@ -389,15 +389,15 @@ typedef struct {
gint64 startup_complete_start_timestamp_msec;
GHashTable *startup_complete_idx;
CList startup_complete_scd_lst_head;
guint startup_complete_timeout_id;
GSource *startup_complete_timeout_source;
GSource *kf_db_flush_idle_source_timestamps;
GSource *kf_db_flush_idle_source_seen_bssids;
guint connections_len;
guint connections_generation;
guint kf_db_flush_idle_id_timestamps;
guint kf_db_flush_idle_id_seen_bssids;
bool kf_db_pruned_timestamps;
bool kf_db_pruned_seen_bssid;
@ -541,9 +541,9 @@ _startup_complete_timeout_cb(gpointer user_data)
NMSettings *self = user_data;
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
priv->startup_complete_timeout_id = 0;
nm_clear_g_source_inst(&priv->startup_complete_timeout_source);
_startup_complete_check(self, 0);
return G_SOURCE_REMOVE;
return G_SOURCE_CONTINUE;
}
static void
@ -567,7 +567,7 @@ _startup_complete_check(NMSettings *self, gint64 now_msec)
return;
}
nm_clear_g_source(&priv->startup_complete_timeout_id);
nm_clear_g_source_inst(&priv->startup_complete_timeout_source);
if (c_list_is_empty(&priv->startup_complete_scd_lst_head))
goto ready;
@ -609,8 +609,10 @@ next_with_ready:
timeout_msec = priv->startup_complete_start_timestamp_msec + scd_not_ready->timeout_msec
- nm_utils_get_monotonic_timestamp_msec();
priv->startup_complete_timeout_id =
g_timeout_add(NM_CLAMP(0, timeout_msec, 60000), _startup_complete_timeout_cb, self);
priv->startup_complete_timeout_source =
nm_g_timeout_add_source(NM_CLAMP(0, timeout_msec, 60000),
_startup_complete_timeout_cb,
self);
_LOGT("startup-complete: wait for suitable device for connection \"%s\" (%s) which has "
"\"connection.wait-device-timeout\" set",
nm_settings_connection_get_id(scd_not_ready->sett_conn),
@ -637,7 +639,7 @@ ready:
_LOGT("startup-complete: ready, no more profiles to wait for");
priv->startup_complete_start_timestamp_msec = 0;
nm_assert(!priv->startup_complete_idx);
nm_assert(priv->startup_complete_timeout_id == 0);
nm_assert(!priv->startup_complete_timeout_source);
_notify(self, PROP_STARTUP_COMPLETE);
}
@ -3842,13 +3844,13 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps)
NMKeyFileDB *kf_db;
if (is_timestamps) {
prefix = "timestamps";
kf_db = priv->kf_db_timestamps;
priv->kf_db_flush_idle_id_timestamps = 0;
prefix = "timestamps";
kf_db = priv->kf_db_timestamps;
nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_timestamps);
} else {
prefix = "seen-bssids";
kf_db = priv->kf_db_seen_bssids;
priv->kf_db_flush_idle_id_seen_bssids = 0;
prefix = "seen-bssids";
kf_db = priv->kf_db_seen_bssids;
nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_seen_bssids);
}
if (nm_key_file_db_is_dirty(kf_db))
@ -3859,7 +3861,7 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps)
nm_key_file_db_get_filename(kf_db));
}
return G_SOURCE_REMOVE;
return G_SOURCE_CONTINUE;
}
static gboolean
@ -3880,26 +3882,27 @@ _kf_db_got_dirty_fcn(NMKeyFileDB *kf_db, gpointer user_data)
NMSettings *self = user_data;
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
GSourceFunc idle_func;
guint *p_id;
GSource **p_source;
const char *prefix;
if (priv->kf_db_timestamps == kf_db) {
prefix = "timestamps";
p_id = &priv->kf_db_flush_idle_id_timestamps;
p_source = &priv->kf_db_flush_idle_source_timestamps;
idle_func = _kf_db_got_dirty_flush_timestamps_cb;
} else if (priv->kf_db_seen_bssids == kf_db) {
prefix = "seen-bssids";
p_id = &priv->kf_db_flush_idle_id_seen_bssids;
p_source = &priv->kf_db_flush_idle_source_seen_bssids;
idle_func = _kf_db_got_dirty_flush_seen_bssids_cb;
} else {
nm_assert_not_reached();
return;
}
if (*p_id != 0)
if (*p_source)
return;
_LOGT("[%s-keyfile]: schedule flushing changes to disk", prefix);
*p_id = g_idle_add_full(G_PRIORITY_LOW, idle_func, self, NULL);
*p_source =
nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_LOW, idle_func, self, NULL), NULL);
}
void
@ -4100,7 +4103,7 @@ dispose(GObject *object)
nm_assert(c_list_is_empty(&priv->sce_dirty_lst_head));
nm_assert(g_hash_table_size(priv->sce_idx) == 0);
nm_clear_g_source(&priv->startup_complete_timeout_id);
nm_clear_g_source_inst(&priv->startup_complete_timeout_source);
nm_clear_pointer(&priv->startup_complete_idx, g_hash_table_destroy);
nm_assert(c_list_is_empty(&priv->startup_complete_scd_lst_head));
@ -4154,8 +4157,8 @@ finalize(GObject *object)
g_clear_object(&priv->agent_mgr);
nm_clear_g_source(&priv->kf_db_flush_idle_id_timestamps);
nm_clear_g_source(&priv->kf_db_flush_idle_id_seen_bssids);
nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_timestamps);
nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_seen_bssids);
_kf_db_to_file(self, TRUE, FALSE);
_kf_db_to_file(self, FALSE, FALSE);
nm_key_file_db_destroy(priv->kf_db_timestamps);

View file

@ -26,8 +26,6 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-core-intern/nm-keyfile-internal.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "settings/nm-settings-plugin.h"
#include "settings/nm-settings-storage.h"
#include "settings/nm-settings-utils.h"
@ -1247,9 +1245,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
/* dirname_libs are a set of read-only directories with lower priority than /etc or /run.
* There is nothing complicated about having multiple of such directories, so dirname_libs
* is a list (which currently only has at most one directory). */
priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB));
priv->dirname_libs[0] = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB));
priv->dirname_libs[1] = NULL;
priv->dirname_run = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN));
priv->dirname_run = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN));
priv->dirname_etc = nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG,
NM_CONFIG_KEYFILE_GROUP_KEYFILE,
NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH,
@ -1262,9 +1260,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
} else if (!priv->dirname_etc || priv->dirname_etc[0] != '/') {
/* either invalid path or unspecified. Use the default. */
g_free(priv->dirname_etc);
priv->dirname_etc = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT));
priv->dirname_etc = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT));
} else
nm_sd_utils_path_simplify(priv->dirname_etc);
nm_path_simplify(priv->dirname_etc);
/* no duplicates */
if (NM_IN_STRSET(priv->dirname_libs[0], priv->dirname_etc, priv->dirname_run))

View file

@ -1924,6 +1924,7 @@ test_write_bridge_main(void)
gs_unref_object NMConnection *connection = NULL;
NMSettingConnection *s_con;
NMSettingBridge *s_bridge;
NMSettingWired *s_wired;
NMSettingIPConfig *s_ip4;
NMSettingIPConfig *s_ip6;
@ -1953,6 +1954,11 @@ test_write_bridge_main(void)
g_assert(s_bridge);
nm_connection_add_setting(connection, NM_SETTING(s_bridge));
/* Ethernet setting */
s_wired = (NMSettingWired *) nm_setting_wired_new();
g_assert(s_wired);
nm_connection_add_setting(connection, NM_SETTING(s_wired));
/* IP4 setting */
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new();
g_assert(s_ip4);

View file

@ -15,7 +15,6 @@
#include "NetworkManagerUtils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-core-utils.h"
#include "libnm-systemd-core/nm-sd-utils-core.h"
#include "dns/nm-dns-manager.h"
#include "nm-connectivity.h"
@ -2314,7 +2313,6 @@ test_dns_create_resolv_conf(void)
static void
test_machine_id_read(void)
{
NMUuid machine_id_sd;
const NMUuid *machine_id;
char machine_id_str[33];
gpointer logstate;
@ -2346,27 +2344,6 @@ test_machine_id_read(void)
== machine_id_str);
g_assert(strlen(machine_id_str) == 32);
g_assert_cmpstr(machine_id_str, ==, nm_utils_machine_id_str());
/* double check with systemd's implementation... */
if (!nm_sd_utils_id128_get_machine(&machine_id_sd)) {
/* if systemd failed to read /etc/machine-id, the file likely
* is invalid. Our machine-id is fake, and we have nothing to
* compare against. */
if (g_file_test(LOCALSTATEDIR "/lib/dbus/machine-id", G_FILE_TEST_EXISTS)) {
/* Hm. So systemd failed to read /etc/machine-id, but we may have the one from D-Bus.
* With LOCALSTATEDIR"/lib/dbus/machine-id", we don't really know whether we
* parsed that file. Assume we don't know and skip the test on this system. */
g_assert(!nm_utils_machine_id_is_fake());
return;
}
/* OK, in this case, our function should have generated a random machine ID. */
g_assert(nm_utils_machine_id_is_fake());
} else {
g_assert(!nm_utils_machine_id_is_fake());
g_assert_cmpmem(&machine_id_sd, sizeof(NMUuid), machine_id, 16);
}
}
/*****************************************************************************/

View file

@ -12,27 +12,6 @@
/*****************************************************************************/
static void
test_dhcp_create(void)
{
sd_dhcp_client *client4 = NULL;
int r;
r = sd_dhcp_client_new(&client4, FALSE);
g_assert(r == 0);
g_assert(client4);
if (/* never true */ client4 == (gpointer) &r) {
/* we don't want to call this, but ensure that the linker
* includes all these symbols. */
sd_dhcp_client_start(client4);
}
sd_dhcp_client_unref(client4);
}
/*****************************************************************************/
static void
test_lldp_create(void)
{
@ -119,141 +98,6 @@ test_sd_event(void)
/*****************************************************************************/
static void
test_path_equal(void)
{
#define _path_equal_check(path, expected) \
G_STMT_START \
{ \
const char *_path0 = (path); \
const char *_expected = (expected); \
gs_free char *_path = g_strdup(_path0); \
const char *_path_result; \
\
_path_result = nm_sd_utils_path_simplify(_path); \
g_assert(_path_result == _path); \
g_assert_cmpstr(_path, ==, _expected); \
} \
G_STMT_END
_path_equal_check("", "");
_path_equal_check(".", ".");
_path_equal_check("..", "..");
_path_equal_check("/..", "/..");
_path_equal_check("//..", "/..");
_path_equal_check("/.", "/");
_path_equal_check("./", ".");
_path_equal_check("./.", ".");
_path_equal_check(".///.", ".");
_path_equal_check(".///./", ".");
_path_equal_check(".////", ".");
_path_equal_check("//..//foo/", "/../foo");
_path_equal_check("///foo//./bar/.", "/foo/bar");
_path_equal_check(".//./foo//./bar/.", "foo/bar");
}
/*****************************************************************************/
static void
_test_unbase64char(char ch, gboolean maybe_invalid)
{
int r;
r = nm_sd_utils_unbase64char(ch, FALSE);
if (ch == '=') {
g_assert(!maybe_invalid);
g_assert_cmpint(r, <, 0);
g_assert_cmpint(nm_sd_utils_unbase64char(ch, TRUE), ==, G_MAXINT);
} else {
g_assert_cmpint(r, ==, nm_sd_utils_unbase64char(ch, TRUE));
if (r >= 0)
g_assert_cmpint(r, <=, 255);
if (!maybe_invalid)
g_assert_cmpint(r, >=, 0);
}
}
static void
_test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expected_len)
{
gs_free char *expected_base64 = NULL;
int r;
nm_auto_free guint8 *exp2_arr = NULL;
nm_auto_free guint8 *exp3_arr = NULL;
gsize exp2_len;
gsize exp3_len;
gsize i;
expected_base64 = g_base64_encode(expected_arr, expected_len);
for (i = 0; expected_base64[i]; i++)
_test_unbase64char(expected_base64[i], FALSE);
r = nm_sd_utils_unbase64mem(expected_base64,
strlen(expected_base64),
TRUE,
&exp2_arr,
&exp2_len);
g_assert_cmpint(r, ==, 0);
g_assert_cmpmem(expected_arr, expected_len, exp2_arr, exp2_len);
if (!nm_streq(base64, expected_base64)) {
r = nm_sd_utils_unbase64mem(base64, strlen(base64), TRUE, &exp3_arr, &exp3_len);
g_assert_cmpint(r, ==, 0);
g_assert_cmpmem(expected_arr, expected_len, exp3_arr, exp3_len);
}
}
#define _test_unbase64mem(base64, expected_str) \
_test_unbase64mem_mem(base64, (const guint8 *) "" expected_str "", NM_STRLEN(expected_str))
static void
_test_unbase64mem_inval(const char *base64)
{
gs_free guint8 *exp_arr = NULL;
gsize exp_len = 0;
int r;
r = nm_sd_utils_unbase64mem(base64, strlen(base64), TRUE, &exp_arr, &exp_len);
g_assert_cmpint(r, <, 0);
g_assert(!exp_arr);
g_assert(exp_len == 0);
}
static void
test_nm_sd_utils_unbase64mem(void)
{
gs_free char *rnd_base64 = NULL;
guint8 rnd_buf[30];
guint i, rnd_len;
_test_unbase64mem("", "");
_test_unbase64mem(" ", "");
_test_unbase64mem(" Y Q == ", "a");
_test_unbase64mem(" Y WJjZGV mZ 2g = ", "abcdefgh");
_test_unbase64mem_inval(" Y %WJjZGV mZ 2g = ");
_test_unbase64mem_inval(" Y %WJjZGV mZ 2g = a");
_test_unbase64mem("YQ==", "a");
_test_unbase64mem_inval("YQ==a");
rnd_len = nmtst_get_rand_uint32() % sizeof(rnd_buf);
for (i = 0; i < rnd_len; i++)
rnd_buf[i] = nmtst_get_rand_uint32() % 256;
rnd_base64 = g_base64_encode(rnd_buf, rnd_len);
_test_unbase64mem_mem(rnd_base64, rnd_buf, rnd_len);
_test_unbase64char('=', FALSE);
for (i = 0; i < 10; i++) {
char ch = nmtst_get_rand_uint32() % 256;
if (ch != '=')
_test_unbase64char(ch, TRUE);
}
}
/*****************************************************************************/
NMTST_DEFINE();
int
@ -261,11 +105,8 @@ main(int argc, char **argv)
{
nmtst_init(&argc, &argv, TRUE);
g_test_add_func("/systemd/dhcp/create", test_dhcp_create);
g_test_add_func("/systemd/lldp/create", test_lldp_create);
g_test_add_func("/systemd/sd-event", test_sd_event);
g_test_add_func("/systemd/test_path_equal", test_path_equal);
g_test_add_func("/systemd/test_nm_sd_utils_unbase64mem", test_nm_sd_utils_unbase64mem);
return g_test_run();
}

View file

@ -234,8 +234,10 @@ test_shorten_hostname(void)
* system configuration (`getconf HOST_NAME_MAX`). On Linux
* it's typically 64 characters, but POSIX allows up to
* 255 characters.
*
* We use our own define NM_HOST_NAME_MAX, which is always 64.
*/
maxhost = g_strnfill(HOST_NAME_MAX, 'a');
maxhost = g_strnfill(NM_HOST_NAME_MAX, 'a');
do_test_shorten_hostname("name1", TRUE, NULL);

View file

@ -20,6 +20,7 @@
#include "nm-checkpoint.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-dbus-helpers.h"
#include "nm-wifi-p2p-peer.h"
#include "nm-device-6lowpan.h"
#include "nm-device-adsl.h"
#include "nm-device-bond.h"
@ -33,7 +34,6 @@
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
#include "nm-device-modem.h"
#include "nm-device-olpc-mesh.h"
#include "nm-device-ovs-bridge.h"
#include "nm-device-ovs-interface.h"
#include "nm-device-ovs-port.h"
@ -46,6 +46,7 @@
#include "nm-device-wifi.h"
#include "nm-device-wireguard.h"
#include "nm-device-wpan.h"
#include "nm-device-olpc-mesh.h"
#include "nm-dhcp-config.h"
#include "nm-dhcp4-config.h"
#include "nm-dhcp6-config.h"
@ -56,7 +57,6 @@
#include "nm-remote-connection.h"
#include "nm-utils.h"
#include "nm-vpn-connection.h"
#include "nm-wifi-p2p-peer.h"
/*****************************************************************************/
@ -8399,9 +8399,9 @@ nm_client_class_init(NMClientClass *client_class)
*
* Whether a connectivity checking service has been enabled.
*
* Since: 1.10
*
* The property setter is a synchronous D-Bus call. This is deprecated since 1.22.
*
* Since: 1.10
*/
obj_properties[PROP_CONNECTIVITY_CHECK_ENABLED] =
g_param_spec_boolean(NM_CLIENT_CONNECTIVITY_CHECK_ENABLED,
@ -8729,7 +8729,7 @@ nm_client_class_init(NMClientClass *client_class)
G_TYPE_UINT);
/**
* NMClient::connection-added:
* @client: the settings object that received the signal
* @client: the client that received the signal
* @connection: the new connection
*
* Notifies that a #NMConnection has been added.
@ -8747,7 +8747,7 @@ nm_client_class_init(NMClientClass *client_class)
/**
* NMClient::connection-removed:
* @client: the settings object that received the signal
* @client: the client that received the signal
* @connection: the removed connection
*
* Notifies that a #NMConnection has been removed.
@ -8765,7 +8765,7 @@ nm_client_class_init(NMClientClass *client_class)
/**
* NMClient::active-connection-added:
* @client: the settings object that received the signal
* @client: the client that received the signal
* @active_connection: the new active connection
*
* Notifies that a #NMActiveConnection has been added.
@ -8783,7 +8783,7 @@ nm_client_class_init(NMClientClass *client_class)
/**
* NMClient::active-connection-removed:
* @client: the settings object that received the signal
* @client: the client that received the signal
* @active_connection: the removed active connection
*
* Notifies that a #NMActiveConnection has been removed.

View file

@ -16,6 +16,16 @@
/*****************************************************************************/
#include "nm-version.h"
#include "nm-dbus-interface.h"
#include "nm-dhcp-config.h"
#include "nm-ip-config.h"
#include "nm-connection.h"
#include "nm-remote-connection.h"
#include "nm-active-connection.h"
#include "nm-device.h"
#include "nm-checkpoint.h"
#include "nm-client.h"
#include "nm-vpn-connection.h"
#include "nm-libnm-utils.h"
/*****************************************************************************/

View file

@ -120,11 +120,11 @@ nm_device_macvlan_get_tap(NMDeviceMacvlan *device)
* Returns: the hardware address. This is the internal string used by the
* device, and must not be modified.
*
* Since: 1.2
*
* This property is not implemented yet, and the function always return NULL.
*
* Deprecated: 1.24: Use nm_device_get_hw_address() instead.
*
* Since: 1.2
**/
const char *
nm_device_macvlan_get_hw_address(NMDeviceMacvlan *device)

View file

@ -5,12 +5,13 @@
#include "libnm-client-impl/nm-default-libnm.h"
#include "nm-access-point.h"
#include "nm-device-wifi.h"
#include "nm-device-olpc-mesh.h"
#include "nm-setting-connection.h"
#include "nm-setting-olpc-mesh.h"
#include "nm-object-private.h"
#include "nm-device-wifi.h"
/*****************************************************************************/

View file

@ -96,10 +96,10 @@ nm_device_vxlan_get_hw_address(NMDeviceVxlan *device)
*
* Returns: %TRUE if the device has carrier.
*
* Since: 1.2
*
* This property is not implemented yet, and the function always returns
* FALSE.
*
* Since: 1.2
**/
gboolean
nm_device_vxlan_get_carrier(NMDeviceVxlan *device)
@ -541,9 +541,9 @@ nm_device_vxlan_class_init(NMDeviceVxlanClass *klass)
*
* Whether the device has carrier.
*
* Since: 1.2
*
* This property is not implemented yet, and the property is always FALSE.
*
* Since: 1.2
**/
obj_properties[PROP_CARRIER] = g_param_spec_boolean(NM_DEVICE_VXLAN_CARRIER,
"",

View file

@ -5,13 +5,13 @@
#include "libnm-client-impl/nm-default-libnm.h"
#include "nm-wifi-p2p-peer.h"
#include "nm-device-wifi-p2p.h"
#include "libnm-glib-aux/nm-dbus-aux.h"
#include "nm-setting-connection.h"
#include "nm-setting-wifi-p2p.h"
#include "nm-utils.h"
#include "nm-wifi-p2p-peer.h"
#include "nm-object-private.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-dbus-helpers.h"

View file

@ -6,6 +6,7 @@
#include "libnm-client-impl/nm-default-libnm.h"
#include "nm-access-point.h"
#include "nm-device-wifi.h"
#include <linux/if_ether.h>
@ -15,7 +16,6 @@
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
#include "nm-utils.h"
#include "nm-access-point.h"
#include "nm-object-private.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-dbus-helpers.h"

View file

@ -6,9 +6,8 @@
#include "libnm-client-impl/nm-default-libnm.h"
#include "nm-device-wimax.h"
#include "nm-wimax-nsp.h"
#include "nm-device-wimax.h"
/*****************************************************************************/

View file

@ -7,12 +7,8 @@
#define __NM_LIBNM_UTILS_H__
#include "c-list/src/c-list.h"
#include "nm-device.h"
#include "libnm-glib-aux/nm-ref-string.h"
#include "libnm-glib-aux/nm-logging-fwd.h"
#include "nm-types.h"
#include "nm-object.h"
#include "nm-client.h"
/*****************************************************************************/

View file

@ -8,48 +8,19 @@
#define __NETWORKMANAGER_H_INSIDE__
#include "nm-access-point.h"
#include "nm-active-connection.h"
#include "nm-client.h"
#include "nm-connection.h"
#include "nm-core-enum-types.h"
#include <gio/gio.h>
#include "nm-version.h"
#include "nm-dbus-interface.h"
#include "nm-device-6lowpan.h"
#include "nm-device-adsl.h"
#include "nm-device-bond.h"
#include "nm-device-bridge.h"
#include "nm-device-bt.h"
#include "nm-device-dummy.h"
#include "nm-device-ethernet.h"
#include "nm-device-generic.h"
#include "nm-device-infiniband.h"
#include "nm-device-ip-tunnel.h"
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
#include "nm-device-modem.h"
#include "nm-device-olpc-mesh.h"
#include "nm-device-ovs-bridge.h"
#include "nm-device-ovs-interface.h"
#include "nm-device-ovs-port.h"
#include "nm-device-ppp.h"
#include "nm-device-team.h"
#include "nm-device-tun.h"
#include "nm-device-veth.h"
#include "nm-device-vlan.h"
#include "nm-device-vxlan.h"
#include "nm-device-wifi-p2p.h"
#include "nm-device-wifi.h"
#include "nm-device-wimax.h"
#include "nm-device-wireguard.h"
#include "nm-device-wpan.h"
#include "nm-device.h"
#include "nm-dhcp-config.h"
#include "nm-enum-types.h"
#include "nm-ethtool-utils.h"
#include "nm-ip-config.h"
#include "nm-core-enum-types.h"
#include "nm-connection.h"
#include "nm-simple-connection.h"
#include "nm-keyfile.h"
#include "nm-object.h"
#include "nm-remote-connection.h"
#include "nm-setting.h"
#include "nm-utils.h"
#include "nm-setting-6lowpan.h"
#include "nm-setting-8021x.h"
#include "nm-setting-adsl.h"
@ -102,18 +73,59 @@
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-wpan.h"
#include "nm-setting.h"
#include "nm-simple-connection.h"
#include "nm-utils.h"
#include "nm-version.h"
#include "nm-vpn-connection.h"
#include "nm-vpn-dbus-interface.h"
#include "nm-vpn-editor.h"
#include "nm-vpn-editor-plugin.h"
#include "nm-vpn-plugin-info.h"
#include "nm-vpn-service-plugin.h"
#include "nm-vpn-editor-plugin.h"
#include "nm-enum-types.h"
#include "nm-ethtool-utils.h"
#include "nm-object.h"
#include "nm-dhcp-config.h"
#include "nm-ip-config.h"
#include "nm-remote-connection.h"
#include "nm-active-connection.h"
#include "nm-checkpoint.h"
#include "nm-access-point.h"
#include "nm-wifi-p2p-peer.h"
#include "nm-wimax-nsp.h"
#include "nm-device.h"
#include "nm-vpn-connection.h"
#include "nm-vpn-editor.h"
#include "nm-vpn-service-plugin.h"
#include "nm-client.h"
#include "nm-device-6lowpan.h"
#include "nm-device-adsl.h"
#include "nm-device-bond.h"
#include "nm-device-bridge.h"
#include "nm-device-bt.h"
#include "nm-device-dummy.h"
#include "nm-device-ethernet.h"
#include "nm-device-generic.h"
#include "nm-device-infiniband.h"
#include "nm-device-ip-tunnel.h"
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
#include "nm-device-modem.h"
#include "nm-device-ovs-bridge.h"
#include "nm-device-ovs-interface.h"
#include "nm-device-ovs-port.h"
#include "nm-device-ppp.h"
#include "nm-device-team.h"
#include "nm-device-tun.h"
#include "nm-device-veth.h"
#include "nm-device-vlan.h"
#include "nm-device-vxlan.h"
#include "nm-device-wifi.h"
#include "nm-device-wifi-p2p.h"
#include "nm-device-olpc-mesh.h"
#include "nm-device-wimax.h"
#include "nm-device-wireguard.h"
#include "nm-device-wpan.h"
#include "nm-autoptr.h"

View file

@ -45,7 +45,6 @@ libnm_client_headers = files(
'nm-object.h',
'nm-remote-connection.h',
'nm-secret-agent-old.h',
'nm-types.h',
'nm-vpn-connection.h',
'nm-vpn-editor.h',
'nm-vpn-plugin-old.h',

Some files were not shown because too many files have changed in this diff Show more