[systemd-commits] 34 commits - configure.ac .gitignore hwdb/20-bluetooth-vendor-product.hwdb hwdb/60-keyboard.hwdb Makefile.am man/hwdb.xml man/sd_bus_creds_get_pid.xml man/systemd-gpt-auto-generator.xml man/systemd.kill.xml man/systemd.service.xml man/timesyncd.conf.xml src/core src/libsystemd src/libsystemd-network src/locale src/login src/machine src/network src/nspawn src/resolve src/systemctl src/systemd src/test src/timedate src/udev test/sysv-generator-test.py TODO

David Herrmann dvdhrm at kemper.freedesktop.org
Mon Jun 15 03:18:56 PDT 2015


 .gitignore                                       |    4 
 Makefile.am                                      |  119 -
 TODO                                             |    4 
 configure.ac                                     |    1 
 hwdb/20-bluetooth-vendor-product.hwdb            |   39 
 hwdb/60-keyboard.hwdb                            |    6 
 man/hwdb.xml                                     |    8 
 man/sd_bus_creds_get_pid.xml                     |    6 
 man/systemd-gpt-auto-generator.xml               |   15 
 man/systemd.kill.xml                             |    8 
 man/systemd.service.xml                          |   19 
 man/timesyncd.conf.xml                           |    4 
 src/core/loopback-setup.c                        |   20 
 src/libsystemd-network/test-pppoe.c              |   40 
 src/libsystemd/sd-netlink/Makefile               |    1 
 src/libsystemd/sd-netlink/local-addresses.c      |  276 +++
 src/libsystemd/sd-netlink/local-addresses.h      |   37 
 src/libsystemd/sd-netlink/netlink-internal.h     |  135 +
 src/libsystemd/sd-netlink/netlink-message.c      |  906 ++++++++++++
 src/libsystemd/sd-netlink/netlink-socket.c       |  322 ++++
 src/libsystemd/sd-netlink/netlink-types.c        |  561 +++++++
 src/libsystemd/sd-netlink/netlink-types.h        |  119 +
 src/libsystemd/sd-netlink/netlink-util.c         |  173 ++
 src/libsystemd/sd-netlink/netlink-util.h         |   47 
 src/libsystemd/sd-netlink/rtnl-message.c         |  588 +++++++
 src/libsystemd/sd-netlink/sd-netlink.c           |  916 ++++++++++++
 src/libsystemd/sd-netlink/test-local-addresses.c |   58 
 src/libsystemd/sd-netlink/test-netlink.c         |  440 +++++
 src/libsystemd/sd-rtnl/Makefile                  |    1 
 src/libsystemd/sd-rtnl/local-addresses.c         |  276 ---
 src/libsystemd/sd-rtnl/local-addresses.h         |   37 
 src/libsystemd/sd-rtnl/rtnl-internal.h           |  135 -
 src/libsystemd/sd-rtnl/rtnl-message.c            | 1699 -----------------------
 src/libsystemd/sd-rtnl/rtnl-types.c              |  561 -------
 src/libsystemd/sd-rtnl/rtnl-types.h              |  119 -
 src/libsystemd/sd-rtnl/rtnl-util.c               |  173 --
 src/libsystemd/sd-rtnl/rtnl-util.h               |   47 
 src/libsystemd/sd-rtnl/sd-rtnl.c                 | 1056 --------------
 src/libsystemd/sd-rtnl/test-local-addresses.c    |   58 
 src/libsystemd/sd-rtnl/test-rtnl.c               |  443 -----
 src/locale/localectl.c                           |   35 
 src/login/loginctl.c                             |  105 -
 src/machine/machinectl.c                         |   48 
 src/network/networkctl.c                         |   84 -
 src/network/networkd-address.c                   |   50 
 src/network/networkd-dhcp4.c                     |    8 
 src/network/networkd-dhcp6.c                     |    4 
 src/network/networkd-fdb.c                       |   14 
 src/network/networkd-ipv4ll.c                    |    8 
 src/network/networkd-link.c                      |  118 -
 src/network/networkd-link.h                      |   10 
 src/network/networkd-manager.c                   |   52 
 src/network/networkd-netdev-bond.c               |   48 
 src/network/networkd-netdev-ipvlan.c             |    4 
 src/network/networkd-netdev-macvlan.c            |    4 
 src/network/networkd-netdev-tunnel.c             |   78 -
 src/network/networkd-netdev-tuntap.c             |   51 
 src/network/networkd-netdev-veth.c               |   12 
 src/network/networkd-netdev-vlan.c               |    4 
 src/network/networkd-netdev-vxlan.c              |   32 
 src/network/networkd-netdev.c                    |   54 
 src/network/networkd-netdev.h                    |   10 
 src/network/networkd-route.c                     |   52 
 src/network/networkd-wait-online-link.c          |    4 
 src/network/networkd-wait-online-link.h          |    2 
 src/network/networkd-wait-online-manager.c       |   30 
 src/network/networkd-wait-online.h               |    4 
 src/network/networkd.h                           |   16 
 src/network/test-network-tables.c                |    2 
 src/nspawn/nspawn.c                              |  133 -
 src/resolve/resolved-link.c                      |    8 
 src/resolve/resolved-link.h                      |    4 
 src/resolve/resolved-manager.c                   |   50 
 src/resolve/resolved-manager.h                   |    4 
 src/systemctl/systemctl.c                        |   21 
 src/systemd/sd-netlink.h                         |  150 ++
 src/systemd/sd-rtnl.h                            |  152 --
 src/test/test-netlink-manual.c                   |  147 +
 src/test/test-rtnl-manual.c                      |  147 -
 src/timedate/timedatectl.c                       |   17 
 src/udev/net/link-config.c                       |    8 
 src/udev/udev-event.c                            |   29 
 src/udev/udev-rules.c                            |    4 
 src/udev/udev.h                                  |    5 
 src/udev/udevd.c                                 |    6 
 test/sysv-generator-test.py                      |    1 
 86 files changed, 5675 insertions(+), 5631 deletions(-)

New commits:
commit cceb20c75ca4eb14cb72866e9490691b543f0dd6
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 15 12:05:26 2015 +0200

    man: document that ExecStop= needs a synchronous tool
    
    As requested in #199.

diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 0fe694a..e261963 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -383,10 +383,21 @@
         run, all processes remaining for a service are terminated
         according to the <varname>KillMode=</varname> setting (see
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
-        If this option is not specified, the process is terminated
-        immediately when service stop is requested. Specifier and
-        environment variable substitution is supported (including
-        <varname>$MAINPID</varname>, see above).</para></listitem>
+        If this option is not specified, the process is terminated by
+        sending the signal specified in <varname>KillSignal=</varname>
+        when service stop is requested. Specifier and environment
+        variable substitution is supported (including
+        <varname>$MAINPID</varname>, see above).</para>
+
+        <para>Note that it is usually not sufficient to specify a
+        command for this setting that only asks the service to
+        terminate (for example by queuing some form of termination
+        signal for it), but does not wait for it to do so. Since the
+        remaining processes of the services are killed using
+        <constant>SIGKILL</constant> immediately after the command
+        exited this would not result in a clean stop. The specified
+        command should hence be a synchronous operation, not an
+        asynchronous one.</para></listitem>
       </varlistentry>
 
       <varlistentry>

commit e8c53936316288ea3b33b5997b175862f0efef92
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 15 12:05:11 2015 +0200

    man: document that SIGCONT always follows SIGTERM
    
    As requested in #199.

diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml
index ef828e0..c51cf81 100644
--- a/man/systemd.kill.xml
+++ b/man/systemd.kill.xml
@@ -139,7 +139,13 @@
         by <constant>SIGKILL</constant> (see above and below). For a
         list of valid signals, see
         <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
-        Defaults to <constant>SIGTERM</constant>. </para></listitem>
+        Defaults to <constant>SIGTERM</constant>. </para>
+
+        <para>Note that right after sending the signal specified in
+        this setting systemd will always send
+        <constant>SIGCONT</constant>, to ensure that even suspended
+        tasks can be terminated cleanly.</para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>

commit c6355b313e653bc33efe0ed7c047028bb5c42786
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 15 11:48:24 2015 +0200

    man: clarify overriding semantics of systemd-gpt-auto-generator
    
    Specifically: /etc/fstab overrides the units itself, but not the deps.
    
    See #168.

diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml
index 16ff100..d3e02d6 100644
--- a/man/systemd-gpt-auto-generator.xml
+++ b/man/systemd-gpt-auto-generator.xml
@@ -64,13 +64,16 @@
     <filename>/home</filename>, <filename>/srv</filename> and swap
     partitions and creates mount and swap units for them, based on the
     partition type GUIDs of GUID partition tables (GPT). It implements
-    the
-    <ulink url="http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable
+    the <ulink
+    url="http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable
     Partitions Specification</ulink>. Note that this generator has no
-    effect on non-GPT systems, on systems where the units are
-    explicitly configured (for example, listed in
-    <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
-    or where the mount points are non-empty.</para>
+    effect on non-GPT systems, or where the directories under the
+    mount points are already non-empty. Also, on systems where the
+    units are explicitly configured (for example, listed in
+    <citerefentry
+    project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+    the units this generator creates are overriden, but additional
+    automatic dependencies might be created.</para>
 
     <para>This generator will only look for root partitions on the
     same physical disk the EFI System Partition (ESP) is located on.

commit 5feece76fb55444f34cd8eb5394d0f079dab54de
Merge: bdfcbe2 9b1cbdc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 15 11:45:48 2015 +0200

    Merge pull request #205 from endocode/iaguis/seccomp-v2
    
    nspawn: make seccomp loading errors non-fatal


commit bdfcbe226204c1c4b4ea8de16d7be376ac941c97
Author: Marcel Holtmann <marcel at holtmann.org>
Date:   Mon Jun 15 11:28:15 2015 +0200

    hwdb: Update database of Bluetooth company identifiers

diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb
index 93241ca..b737e6b 100644
--- a/hwdb/20-bluetooth-vendor-product.hwdb
+++ b/hwdb/20-bluetooth-vendor-product.hwdb
@@ -1667,3 +1667,42 @@ bluetooth:v0228*
 
 bluetooth:v0229*
  ID_VENDOR_FROM_DATABASE=Muoverti Limited
+
+bluetooth:v022A*
+ ID_VENDOR_FROM_DATABASE=Stamer Musikanlagen GMBH
+
+bluetooth:v022B*
+ ID_VENDOR_FROM_DATABASE=Tesla Motors
+
+bluetooth:v022C*
+ ID_VENDOR_FROM_DATABASE=Pharynks Corporation
+
+bluetooth:v022D*
+ ID_VENDOR_FROM_DATABASE=Lupine
+
+bluetooth:v022E*
+ ID_VENDOR_FROM_DATABASE=Siemens AG
+
+bluetooth:v022F*
+ ID_VENDOR_FROM_DATABASE=Huami (Shanghai) Culture Communication CO., LTD
+
+bluetooth:v0230*
+ ID_VENDOR_FROM_DATABASE=Foster Electric Company, Ltd
+
+bluetooth:v0231*
+ ID_VENDOR_FROM_DATABASE=ETA SA
+
+bluetooth:v0232*
+ ID_VENDOR_FROM_DATABASE=x-Senso Solutions Kft
+
+bluetooth:v0233*
+ ID_VENDOR_FROM_DATABASE=Shenzhen SuLong Communication Ltd
+
+bluetooth:v0234*
+ ID_VENDOR_FROM_DATABASE=FengFan (BeiJing) Technology Co, Ltd
+
+bluetooth:v0235*
+ ID_VENDOR_FROM_DATABASE=Qrio Inc
+
+bluetooth:v0236*
+ ID_VENDOR_FROM_DATABASE=Pitpatpet Ltd

commit 9b1cbdc6e18ddeddc42df558e574322c64867b24
Author: Iago López Galeiras <iago at endocode.com>
Date:   Fri Jun 12 16:22:40 2015 +0200

    nspawn: make seccomp loading errors non-fatal
    
    seccomp_load returns -EINVAL when seccomp support is not enabled in the
    kernel [1]. This should be a debug log, not an error that interrupts nspawn.
    If the seccomp filter can't be set and audit is enabled, the user will
    get an error message anyway.
    
    [1]: http://man7.org/linux/man-pages/man2/prctl.2.html

diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 6a21ed5..5625799 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -3002,8 +3002,15 @@ static int setup_seccomp(void) {
         }
 
         r = seccomp_load(seccomp);
-        if (r < 0)
+        if (r == -EINVAL) {
+                log_debug_errno(r, "Kernel is probably not configured with CONFIG_SECCOMP. Disabling seccomp audit filter: %m");
+                r = 0;
+                goto finish;
+        }
+        if (r < 0) {
                 log_error_errno(r, "Failed to install seccomp audit filter: %m");
+                goto finish;
+        }
 
 finish:
         seccomp_release(seccomp);

commit 6b7d32add4733a83f86e18bb86f914037a6688b7
Author: Martin Pitt <martin.pitt at ubuntu.com>
Date:   Mon Jun 15 08:59:44 2015 +0200

    sysv-generator test: always log to console
    
    Set $SYSTEMD_LOG_TARGET so that the output always goes to stdout/stderr. This
    fixes running the test as root, as that logged to the journal previously.
    
    https://github.com/systemd/systemd/issues/195

diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py
index e74f853..af0493b 100644
--- a/test/sysv-generator-test.py
+++ b/test/sysv-generator-test.py
@@ -60,6 +60,7 @@ class SysvGeneratorTest(unittest.TestCase):
         '''
         env = os.environ.copy()
         env['SYSTEMD_LOG_LEVEL'] = 'debug'
+        env['SYSTEMD_LOG_TARGET'] = 'console'
         env['SYSTEMD_SYSVINIT_PATH'] = self.init_d_dir
         env['SYSTEMD_SYSVRCND_PATH'] = self.rcnd_dir
         env['SYSTEMD_UNIT_PATH'] = self.unit_dir

commit 63432f5d9570b76a8efe82702d69611c20645530
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 15 00:41:10 2015 +0200

    update TODO

diff --git a/TODO b/TODO
index d09219d..3cc3596 100644
--- a/TODO
+++ b/TODO
@@ -26,6 +26,8 @@ External:
 
 Features:
 
+* install: include generator dirs in unit file search paths
+
 * networkd: add ipv6 privacy extensions
 
 * introduce an NSS module that uses machined info to give container UIDs pretty names when user namespacing is used.

commit 0bea2e3dde7e0b7ea9f52e85891f9a7e2ddb930d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 15 00:15:12 2015 +0200

    update TODO

diff --git a/TODO b/TODO
index db3205c..d09219d 100644
--- a/TODO
+++ b/TODO
@@ -26,6 +26,8 @@ External:
 
 Features:
 
+* networkd: add ipv6 privacy extensions
+
 * introduce an NSS module that uses machined info to give container UIDs pretty names when user namespacing is used.
 
 * stop using off_t, it's a crazy type. Use uint64_t instead.

commit a611e8216615f10c65af66556df97bf9b4dfba35
Merge: 15daf6a 38ed9e3
Author: Kay Sievers <kay at vrfy.org>
Date:   Sun Jun 14 20:58:04 2015 +0200

    Merge pull request #201 from mbiebl/drop-include_prefix
    
    build-sys: Drop include_prefix


commit 38ed9e3c2254c6e5afa53ca15170fef8b4a78c68
Author: Michael Biebl <biebl at debian.org>
Date:   Sun Jun 14 20:48:54 2015 +0200

    build-sys: Drop include_prefix
    
    Appears to be unused and a leftover from the udev merge.

diff --git a/configure.ac b/configure.ac
index fcdccb1..b94dbd1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1571,7 +1571,6 @@ AC_MSG_RESULT([
         sysconf dir:             ${sysconfdir}
         datarootdir:             ${datarootdir}
         includedir:              ${includedir}
-        include_prefix:          ${INCLUDE_PREFIX}
         lib dir:                 ${libdir}
         rootlib dir:             ${with_rootlibdir}
         SysV init scripts:       ${SYSTEM_SYSVINIT_PATH}

commit 15daf6a834563fe5afc3143aaf41bd9a4adc24ed
Merge: 7258e97 5331851
Author: Kay Sievers <kay at vrfy.org>
Date:   Sun Jun 14 20:19:54 2015 +0200

    Merge pull request #144 from teg/udev-spawn-log-less-2
    
    udevd: event - don't log about failures of spawn processes when this …


commit 7258e9704f49f29dd6ef19657cbecc3ebbdeae01
Merge: 83cb143 9afc1aa
Author: Kay Sievers <kay at vrfy.org>
Date:   Sun Jun 14 20:17:19 2015 +0200

    Merge pull request #200 from kaysievers/wip
    
    build-sys: include libsystemd-journal and libudev in libshared


commit 9afc1aacfe05d81554e4bd23e58866829fa3ef81
Author: Kay Sievers <kay at vrfy.org>
Date:   Sun Jun 14 20:02:40 2015 +0200

    build-sys: include libsystemd-journal and libudev in libshared

diff --git a/Makefile.am b/Makefile.am
index 5b51948..a0327fd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1021,6 +1021,7 @@ libshared_la_CFLAGS = \
 libshared_la_LIBADD = \
 	libsystemd-internal.la \
 	libsystemd-journal-internal.la \
+	libudev-internal.la \
 	$(ACL_LIBS) \
 	$(LIBIDN_LIBS) \
 	$(SECCOMP_LIBS)
@@ -1190,7 +1191,6 @@ libcore_la_CFLAGS = \
 	$(MOUNT_CFLAGS)
 
 libcore_la_LIBADD = \
-	libudev-internal.la \
 	libshared.la \
 	$(PAM_LIBS) \
 	$(AUDIT_LIBS) \
@@ -1799,7 +1799,6 @@ test_tables_CFLAGS = \
 	$(SECCOMP_CFLAGS)
 
 test_tables_LDADD = \
-	libsystemd-journal-internal.la \
 	libjournal-core.la \
 	libcore.la \
 	libudev-core.la
@@ -2119,7 +2118,6 @@ systemd_shutdown_SOURCES = \
 	src/core/killall.c
 
 systemd_shutdown_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 # ------------------------------------------------------------------------------
@@ -2304,7 +2302,6 @@ systemd_fsck_SOURCES = \
 	src/fsck/fsck.c
 
 systemd_fsck_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 # ------------------------------------------------------------------------------
@@ -2324,7 +2321,6 @@ systemd_ac_power_SOURCES = \
 	src/ac-power/ac-power.c
 
 systemd_ac_power_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 # ------------------------------------------------------------------------------
@@ -2611,7 +2607,6 @@ systemd_gpt_auto_generator_SOURCES = \
 	src/basic/blkid-util.h
 
 systemd_gpt_auto_generator_LDADD = \
-	libudev-internal.la \
 	libshared.la \
 	$(BLKID_LIBS)
 
@@ -2688,7 +2683,6 @@ systemctl_SOURCES = \
 	src/systemctl/systemctl.c
 
 systemctl_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 # ------------------------------------------------------------------------------
@@ -2746,7 +2740,6 @@ systemd_nspawn_CFLAGS = \
 	$(BLKID_CFLAGS)
 
 systemd_nspawn_LDADD = \
-	libudev-internal.la \
 	libshared.la \
 	$(BLKID_LIBS)
 
@@ -3227,7 +3220,6 @@ test_dhcp_client_SOURCES = \
 
 test_dhcp_client_LDADD = \
 	libsystemd-network.la \
-	libudev-internal.la \
 	libshared.la
 
 test_dhcp_server_SOURCES = \
@@ -3361,7 +3353,6 @@ libsystemd_terminal_la_SOURCES = \
 	src/libsystemd-terminal/unifont.c
 
 libsystemd_terminal_la_LIBADD = \
-	libudev-internal.la \
 	libshared.la \
 	$(TERMINAL_LIBS)
 
@@ -3615,7 +3606,6 @@ libudev_core_la_CFLAGS = \
 	$(KMOD_CFLAGS)
 
 libudev_core_la_LIBADD = \
-	libudev-internal.la \
 	libsystemd-network.la \
 	libshared.la \
 	$(BLKID_LIBS) \
@@ -3674,7 +3664,6 @@ systemd_hwdb_SOURCES = \
 	src/hwdb/hwdb.c
 
 systemd_hwdb_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 rootbin_PROGRAMS += \
@@ -3742,7 +3731,6 @@ test_libudev_SOURCES = \
 	src/test/test-libudev.c
 
 test_libudev_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 test_udev_SOURCES = \
@@ -3779,7 +3767,6 @@ ata_id_SOURCES = \
 	src/udev/ata_id/ata_id.c
 
 ata_id_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 udevlibexec_PROGRAMS += \
@@ -3790,7 +3777,6 @@ cdrom_id_SOURCES = \
 	src/udev/cdrom_id/cdrom_id.c
 
 cdrom_id_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 udevlibexec_PROGRAMS += \
@@ -3804,7 +3790,6 @@ collect_SOURCES = \
 	src/udev/collect/collect.c
 
 collect_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 udevlibexec_PROGRAMS += \
@@ -3818,7 +3803,6 @@ scsi_id_SOURCES =\
 	src/udev/scsi_id/scsi_id.h
 
 scsi_id_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 udevlibexec_PROGRAMS += \
@@ -3832,7 +3816,6 @@ v4l_id_SOURCES = \
 	src/udev/v4l_id/v4l_id.c
 
 v4l_id_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 udevlibexec_PROGRAMS += \
@@ -3846,7 +3829,6 @@ accelerometer_SOURCES = \
 	src/udev/accelerometer/accelerometer.c
 
 accelerometer_LDADD = \
-	libudev-internal.la \
 	libshared.la
 
 udevlibexec_PROGRAMS += \
@@ -3982,7 +3964,6 @@ systemd_journal_upload_CFLAGS = \
 	$(LIBCURL_CFLAGS)
 
 systemd_journal_upload_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la \
 	$(LIBCURL_LIBS)
 
@@ -4006,7 +3987,6 @@ journalctl_SOURCES = \
 	src/journal/journalctl.c
 
 journalctl_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 if HAVE_QRENCODE
@@ -4101,14 +4081,12 @@ test_compress_SOURCES = \
 	src/journal/test-compress.c
 
 test_compress_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 test_compress_benchmark_SOURCES = \
 	src/journal/test-compress-benchmark.c
 
 test_compress_benchmark_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 test_audit_type_SOURCES = \
@@ -4142,8 +4120,6 @@ nodist_libjournal_core_la_SOURCES = \
 	src/journal/journald-gperf.c
 
 libjournal_core_la_LIBADD = \
-	libsystemd-journal-internal.la \
-	libudev-internal.la \
 	libshared.la
 
 noinst_LTLIBRARIES += \
@@ -4335,7 +4311,6 @@ systemd_journal_gatewayd_SOURCES = \
 	src/journal-remote/microhttpd-util.c
 
 systemd_journal_gatewayd_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la \
 	$(MICROHTTPD_LIBS)
 
@@ -4372,7 +4347,6 @@ systemd_socket_proxyd_SOURCES = \
 	src/socket-proxy/socket-proxyd.c
 
 systemd_socket_proxyd_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 # ------------------------------------------------------------------------------
@@ -4383,7 +4357,6 @@ systemd_coredump_SOURCES = \
 	src/journal/coredump-vacuum.h
 
 systemd_coredump_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 if HAVE_ELFUTILS
@@ -4405,7 +4378,6 @@ coredumpctl_SOURCES = \
 	src/journal/coredumpctl.c
 
 coredumpctl_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 bin_PROGRAMS += \
@@ -4505,7 +4477,6 @@ systemd_bootchart_SOURCES = \
 	src/bootchart/svg.h
 
 systemd_bootchart_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 rootlibexec_PROGRAMS += \
@@ -4576,7 +4547,6 @@ systemd_backlight_SOURCES = \
 	src/backlight/backlight.c
 
 systemd_backlight_LDADD = \
-	libudev-internal.la \
 	libshared.la
 endif
 
@@ -4595,7 +4565,6 @@ systemd_rfkill_SOURCES = \
 	src/rfkill/rfkill.c
 
 systemd_rfkill_LDADD = \
-	libudev-internal.la \
 	libshared.la
 endif
 
@@ -4622,7 +4591,6 @@ systemd_cryptsetup_CFLAGS = \
 	$(LIBCRYPTSETUP_CFLAGS)
 
 systemd_cryptsetup_LDADD = \
-	libudev-internal.la \
 	libshared.la \
 	$(LIBCRYPTSETUP_LIBS)
 
@@ -4903,7 +4871,6 @@ libmachine_core_la_SOURCES = \
 	src/machine/image-dbus.h
 
 libmachine_core_la_LIBADD = \
-	libudev-internal.la \
 	libshared.la
 
 noinst_LTLIBRARIES += \
@@ -4913,7 +4880,6 @@ machinectl_SOURCES = \
 	src/machine/machinectl.c
 
 machinectl_LDADD = \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 rootbin_PROGRAMS += \
@@ -5352,7 +5318,6 @@ nodist_libnetworkd_core_la_SOURCES = \
 	src/network/networkd-netdev-gperf.c
 
 libnetworkd_core_la_LIBADD = \
-	libudev-internal.la \
 	libsystemd-network.la \
 	libshared.la
 
@@ -5372,7 +5337,6 @@ systemd_networkd_wait_online_SOURCES = \
 
 systemd_networkd_wait_online_LDADD = \
 	libsystemd-network.la \
-	libudev-internal.la \
 	libshared.la
 
 rootbin_PROGRAMS += \
@@ -5382,7 +5346,6 @@ networkctl_SOURCES = \
 	src/network/networkctl.c
 
 networkctl_LDADD = \
-	libudev-internal.la \
 	libshared.la \
 	libsystemd-network.la
 
@@ -5488,7 +5451,6 @@ liblogind_core_la_SOURCES = \
 	src/login/logind-acl.h
 
 liblogind_core_la_LIBADD = \
-	libudev-internal.la \
 	libshared.la
 
 if HAVE_ACL
@@ -5508,8 +5470,6 @@ loginctl_SOURCES = \
 	src/login/sysfs-show.c
 
 loginctl_LDADD = \
-	libudev-internal.la \
-	libsystemd-journal-internal.la \
 	libshared.la
 
 rootbin_PROGRAMS += \
@@ -5872,7 +5832,7 @@ libsystemd_login_la_LDFLAGS = \
 	-Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-login.sym
 
 libsystemd_login_la_LIBADD = \
-	libshared.la
+	libsystemd-internal.la
 
 libsystemd_id128_la_SOURCES = \
 	libsystemd-id128.c \
@@ -5888,7 +5848,7 @@ libsystemd_id128_la_LDFLAGS = \
 	-Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-id128.sym
 
 libsystemd_id128_la_LIBADD = \
-	libshared.la
+	libsystemd-internal.la
 
 libsystemd_daemon_la_SOURCES = \
 	libsystemd-daemon.c \
@@ -5904,7 +5864,7 @@ libsystemd_daemon_la_LDFLAGS = \
 	-Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-daemon.sym
 
 libsystemd_daemon_la_LIBADD = \
-	libshared.la
+	libsystemd-internal.la
 
 lib_LTLIBRARIES += \
 	libsystemd-journal.la \

commit 83cb1438177497bd52430c314a6fa8e855863d7d
Merge: 7171ebc e7e55db
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Jun 14 19:35:30 2015 +0200

    Merge pull request #196 from dvdhrm/bus-map-props
    
    tree-wide: fix memory leaks in users of bus_map_all_properties()


commit 7171ebcf2f10aa9a5ff4cff8a3f52a6ae12a01bb
Merge: 0b30332 e26cb3b
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Jun 14 18:47:41 2015 +0200

    Merge pull request #198 from ivuk/fix_typo_timesyncd_conf
    
    Fix typos in man/timesyncd.conf.xml


commit 0b303327703f4049daeb1d7d799e3e2159f28763
Merge: aa75494 19fcba3
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Jun 14 18:46:54 2015 +0200

    Merge pull request #192 from phomes/master
    
    test-netlink-manual: typo fix


commit e26cb3b79abcf1dfe906c034108f526eb38a62c6
Author: Igor Vuk <parcijala at gmail.com>
Date:   Sun Jun 14 18:28:55 2015 +0200

    Fix typos in man/timesyncd.conf.xml

diff --git a/man/timesyncd.conf.xml b/man/timesyncd.conf.xml
index c297d32..ee054f9 100644
--- a/man/timesyncd.conf.xml
+++ b/man/timesyncd.conf.xml
@@ -75,13 +75,13 @@
 
       <varlistentry>
         <term><varname>NTP=</varname></term>
-        <listitem><para>A space separated list of NTP servers host
+        <listitem><para>A space separated list of NTP server host
         names or IP addresses. During runtime this list is combined
         with any per-interface NTP servers acquired from
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
         systemd-timesyncd will contact all configured system or
         per-interface servers in turn until one is found that
-        responds. This setting defaults to the empty
+        responds. This setting defaults to an empty
         list.</para></listitem>
       </varlistentry>
 

commit e7e55dbdc38f929805ab2407fbd50886043a9e7c
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Sun Jun 14 15:08:52 2015 +0200

    tree-wide: fix memory leaks in users of bus_map_all_properties()
    
    If you use bus_map_all_properties(), you must be aware that it might
    touch output variables even though it may fail. This is, because we parse
    many different bus-properties and cannot tell how to clean them up, in
    case we fail deep down in the parser.
    
    Fix all callers of bus_map_all_properties() to correctly cleanup any
    context structures at all times.

diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 8c60339..601839d 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -69,14 +69,27 @@ static void polkit_agent_open_if_enabled(void) {
 
 typedef struct StatusInfo {
         char **locale;
-        const char *vconsole_keymap;
-        const char *vconsole_keymap_toggle;
-        const char *x11_layout;
-        const char *x11_model;
-        const char *x11_variant;
-        const char *x11_options;
+        char *vconsole_keymap;
+        char *vconsole_keymap_toggle;
+        char *x11_layout;
+        char *x11_model;
+        char *x11_variant;
+        char *x11_options;
 } StatusInfo;
 
+static void status_info_clear(StatusInfo *info) {
+        if (info) {
+                strv_free(info->locale);
+                free(info->vconsole_keymap);
+                free(info->vconsole_keymap_toggle);
+                free(info->x11_layout);
+                free(info->x11_model);
+                free(info->x11_variant);
+                free(info->x11_options);
+                zero(*info);
+        }
+}
+
 static void print_overridden_variables(void) {
         int r;
         char *variables[_VARIABLE_LC_MAX] = {};
@@ -150,7 +163,7 @@ static void print_status_info(StatusInfo *i) {
 }
 
 static int show_status(sd_bus *bus, char **args, unsigned n) {
-        StatusInfo info = {};
+        _cleanup_(status_info_clear) StatusInfo info = {};
         static const struct bus_properties_map map[]  = {
                 { "VConsoleKeymap",       "s",  NULL, offsetof(StatusInfo, vconsole_keymap) },
                 { "VConsoleKeymap",       "s",  NULL, offsetof(StatusInfo, vconsole_keymap) },
@@ -171,16 +184,12 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
                                    "/org/freedesktop/locale1",
                                    map,
                                    &info);
-        if (r < 0) {
-                log_error_errno(r, "Could not get properties: %m");
-                goto fail;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not get properties: %m");
 
         print_overridden_variables();
         print_status_info(&info);
 
-fail:
-        strv_free(info.locale);
         return r;
 }
 
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 02d240c..06208bc 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -277,42 +277,81 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
 }
 
 typedef struct SessionStatusInfo {
-        const char *id;
+        char *id;
         uid_t uid;
-        const char *name;
+        char *name;
         struct dual_timestamp timestamp;
         unsigned int vtnr;
-        const char *seat;
-        const char *tty;
-        const char *display;
+        char *seat;
+        char *tty;
+        char *display;
         bool remote;
-        const char *remote_host;
-        const char *remote_user;
-        const char *service;
+        char *remote_host;
+        char *remote_user;
+        char *service;
         pid_t leader;
-        const char *type;
-        const char *class;
-        const char *state;
-        const char *scope;
-        const char *desktop;
+        char *type;
+        char *class;
+        char *state;
+        char *scope;
+        char *desktop;
 } SessionStatusInfo;
 
 typedef struct UserStatusInfo {
         uid_t uid;
-        const char *name;
+        char *name;
         struct dual_timestamp timestamp;
-        const char *state;
+        char *state;
         char **sessions;
-        const char *display;
-        const char *slice;
+        char *display;
+        char *slice;
 } UserStatusInfo;
 
 typedef struct SeatStatusInfo {
-        const char *id;
-        const char *active_session;
+        char *id;
+        char *active_session;
         char **sessions;
 } SeatStatusInfo;
 
+static void session_status_info_clear(SessionStatusInfo *info) {
+        if (info) {
+                free(info->id);
+                free(info->name);
+                free(info->seat);
+                free(info->tty);
+                free(info->display);
+                free(info->remote_host);
+                free(info->remote_user);
+                free(info->service);
+                free(info->type);
+                free(info->class);
+                free(info->state);
+                free(info->scope);
+                free(info->desktop);
+                zero(*info);
+        }
+}
+
+static void user_status_info_clear(UserStatusInfo *info) {
+        if (info) {
+                free(info->name);
+                free(info->state);
+                strv_free(info->sessions);
+                free(info->display);
+                free(info->slice);
+                zero(*info);
+        }
+}
+
+static void seat_status_info_clear(SeatStatusInfo *info) {
+        if (info) {
+                free(info->id);
+                free(info->active_session);
+                strv_free(info->sessions);
+                zero(*info);
+        }
+}
+
 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
         const char *contents;
         int r;
@@ -404,7 +443,7 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
 
         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
         char since2[FORMAT_TIMESTAMP_MAX], *s2;
-        SessionStatusInfo i = {};
+        _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
         int r;
 
         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
@@ -532,14 +571,12 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
 
         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
         char since2[FORMAT_TIMESTAMP_MAX], *s2;
-        UserStatusInfo i = {};
+        _cleanup_(user_status_info_clear) UserStatusInfo i = {};
         int r;
 
         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
-        if (r < 0) {
-                log_error_errno(r, "Could not get properties: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not get properties: %m");
 
         if (*new_line)
                 printf("\n");
@@ -594,10 +631,7 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
                                 NULL);
         }
 
-finish:
-        strv_free(i.sessions);
-
-        return r;
+        return 0;
 }
 
 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
@@ -609,14 +643,12 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
                 {}
         };
 
-        SeatStatusInfo i = {};
+        _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
         int r;
 
         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
-        if (r < 0) {
-                log_error_errno(r, "Could not get properties: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Could not get properties: %m");
 
         if (*new_line)
                 printf("\n");
@@ -653,10 +685,7 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
                 show_sysfs(i.id, "\t\t  ", c);
         }
 
-finish:
-        strv_free(i.sessions);
-
-        return r;
+        return 0;
 }
 
 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index c86c36c..719eb10 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -500,6 +500,18 @@ typedef struct MachineStatusInfo {
         unsigned n_netif;
 } MachineStatusInfo;
 
+static void machine_status_info_clear(MachineStatusInfo *info) {
+        if (info) {
+                free(info->name);
+                free(info->class);
+                free(info->service);
+                free(info->unit);
+                free(info->root_directory);
+                free(info->netif);
+                zero(*info);
+        }
+}
+
 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
         char since2[FORMAT_TIMESTAMP_MAX], *s2;
@@ -636,7 +648,7 @@ static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bo
                 {}
         };
 
-        MachineStatusInfo info = {};
+        _cleanup_(machine_status_info_clear) MachineStatusInfo info = {};
         int r;
 
         assert(verb);
@@ -658,13 +670,6 @@ static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bo
 
         print_machine_status_info(bus, &info);
 
-        free(info.name);
-        free(info.class);
-        free(info.service);
-        free(info.unit);
-        free(info.root_directory);
-        free(info.netif);
-
         return r;
 }
 
@@ -753,6 +758,15 @@ typedef struct ImageStatusInfo {
         uint64_t limit_exclusive;
 } ImageStatusInfo;
 
+static void image_status_info_clear(ImageStatusInfo *info) {
+        if (info) {
+                free(info->name);
+                free(info->path);
+                free(info->type);
+                zero(*info);
+        }
+}
+
 static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
         char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
         char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
@@ -823,7 +837,7 @@ static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
                 {}
         };
 
-        ImageStatusInfo info = {};
+        _cleanup_(image_status_info_clear) ImageStatusInfo info = {};
         int r;
 
         assert(bus);
@@ -844,10 +858,6 @@ static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
 
         print_image_status_info(bus, &info);
 
-        free(info.name);
-        free(info.path);
-        free(info.type);
-
         return r;
 }
 
@@ -857,6 +867,15 @@ typedef struct PoolStatusInfo {
         uint64_t limit;
 } PoolStatusInfo;
 
+static void pool_status_info_clear(PoolStatusInfo *info) {
+        if (info) {
+                free(info->path);
+                zero(*info);
+                info->usage = -1;
+                info->limit = -1;
+        }
+}
+
 static void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) {
         char bs[FORMAT_BYTES_MAX], *s;
 
@@ -881,7 +900,7 @@ static int show_pool_info(sd_bus *bus) {
                 {}
         };
 
-        PoolStatusInfo info = {
+        _cleanup_(pool_status_info_clear) PoolStatusInfo info = {
                 .usage = (uint64_t) -1,
                 .limit = (uint64_t) -1,
         };
@@ -899,7 +918,6 @@ static int show_pool_info(sd_bus *bus) {
 
         print_pool_status_info(bus, &info);
 
-        free(info.path);
         return 0;
 }
 
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 5075e4e..a2eb435 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -1678,17 +1678,23 @@ static const struct bus_properties_map machine_info_property_map[] = {
         {}
 };
 
+static void machine_info_clear(struct machine_info *info) {
+        if (info) {
+                free(info->name);
+                free(info->state);
+                free(info->control_group);
+                zero(*info);
+        }
+}
+
 static void free_machines_list(struct machine_info *machine_infos, int n) {
         int i;
 
         if (!machine_infos)
                 return;
 
-        for (i = 0; i < n; i++) {
-                free(machine_infos[i].name);
-                free(machine_infos[i].state);
-                free(machine_infos[i].control_group);
-        }
+        for (i = 0; i < n; i++)
+                machine_info_clear(&machine_infos[i]);
 
         free(machine_infos);
 }
@@ -4402,7 +4408,7 @@ static int show_all(
 static int show_system_status(sd_bus *bus) {
         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
         _cleanup_free_ char *hn = NULL;
-        struct machine_info mi = {};
+        _cleanup_(machine_info_clear) struct machine_info mi = {};
         const char *on, *off;
         int r;
 
@@ -4449,9 +4455,6 @@ static int show_system_status(sd_bus *bus) {
                 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
         }
 
-        free(mi.state);
-        free(mi.control_group);
-
         return 0;
 }
 
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 61b6e76..195d5f3 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -73,6 +73,13 @@ typedef struct StatusInfo {
         bool ntp_synced;
 } StatusInfo;
 
+static void status_info_clear(StatusInfo *info) {
+        if (info) {
+                free(info->timezone);
+                zero(*info);
+        }
+}
+
 static void print_status_info(const StatusInfo *i) {
         char a[FORMAT_TIMESTAMP_MAX];
         struct tm tm;
@@ -155,7 +162,7 @@ static void print_status_info(const StatusInfo *i) {
 }
 
 static int show_status(sd_bus *bus, char **args, unsigned n) {
-        StatusInfo info = {};
+        _cleanup_(status_info_clear) StatusInfo info = {};
         static const struct bus_properties_map map[]  = {
                 { "Timezone",        "s", NULL, offsetof(StatusInfo, timezone) },
                 { "LocalRTC",        "b", NULL, offsetof(StatusInfo, rtc_local) },
@@ -175,15 +182,11 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
                                    "/org/freedesktop/timedate1",
                                    map,
                                    &info);
-        if (r < 0) {
-                log_error_errno(r, "Failed to query server: %m");
-                goto fail;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to query server: %m");
 
         print_status_info(&info);
 
-fail:
-        free(info.timezone);
         return r;
 }
 

commit aa75494ad5cdf7bede947212ad8c8356d78580fa
Author: Mario Limonciello <mario_limonciello at dell.com>
Date:   Wed Jun 10 22:01:51 2015 -0500

    hwdb: add support for Alienware graphics amplifier
    
    Unplugging and plugging in the cable will create various scancodes
    on the keyboard controller.
    
    Userspace within X should be able to interact with these to show
    interesting messages. Assign them to generic prog1/prog2.
    
    (David: add comment to hwdb explaining that these keycodes are reserved)

diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index 007c6a8..d0fc914 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -144,6 +144,12 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAOA*:pvr*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*
  KEYBOARD_KEY_8a=ejectcd
 
+# Alienware/Dell reserves these keys; safe to apply on all their devices
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*:pvr*
+ KEYBOARD_KEY_bf=!prog1                                 #graphics amplifier, cable plug-in event
+ KEYBOARD_KEY_c1=!prog2                                 #graphics amplifier, undock-button event
+ KEYBOARD_KEY_c2=!power                                 #graphics amplifier, surprise undock event
+
 ###########################################################
 # Asus
 ###########################################################

commit 01856799a3113398da924d9b0dcc09d1e853d905
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Sun Jun 14 14:24:37 2015 +0200

    man: don't mention '/run' in hwdb.man
    
    We do not support '/run' for hwdb files. Drop it from the man-pages so
    people don't accidentally use it.
    
    This was reported by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/man/hwdb.xml b/man/hwdb.xml
index e6215df..8a6e26d 100644
--- a/man/hwdb.xml
+++ b/man/hwdb.xml
@@ -43,15 +43,13 @@
 
   <refsect1><title>Hardware Database Files</title>
       <para>The hwdb files are read from the files located in the
-      system hwdb directory <filename>&udevlibexecdir;/hwdb.d</filename>,
-      the volatile runtime directory <filename>/run/udev/hwdb.d</filename>
+      system hwdb directory <filename>&udevlibexecdir;/hwdb.d</filename>
       and the local administration directory <filename>/etc/udev/hwdb.d</filename>.
       All hwdb files are collectively sorted and processed in lexical order,
       regardless of the directories in which they live. However, files with
       identical filenames replace each other. Files in <filename>/etc</filename>
-      have the highest priority, files in <filename>/run</filename> take precedence
-      over files with the same name in <filename>&rootprefix;/lib</filename>. This can be
-      used to override a system-supplied hwdb file with a local file if needed;
+      take precedence over files with the same name in <filename>&rootprefix;/lib</filename>.
+      This can be used to override a system-supplied hwdb file with a local file if needed;
       a symlink in <filename>/etc</filename> with the same name as a hwdb file in
       <filename>&rootprefix;/lib</filename>, pointing to <filename>/dev/null</filename>,
       disables the hwdb file entirely. hwdb files must have the extension

commit 19fcba36e42d0447b3a7f7aebae7189e056e6ccb
Author: Thomas Hindoe Paaboel Andersen <phomes at gmail.com>
Date:   Sun Jun 14 13:55:05 2015 +0200

    test-netlink-manual: typo fix
    
    No functional change, but looked weird.

diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c
index 1498432..2879d74 100644
--- a/src/test/test-netlink-manual.c
+++ b/src/test/test-netlink-manual.c
@@ -127,7 +127,7 @@ static int test_tunnel_configure(sd_netlink *rtnl) {
 
         assert_se(sd_netlink_call(rtnl, n, -1, 0) == 1);
 
-        assert_se((m = sd_netlink_message_unref(n)) == NULL);
+        assert_se((n = sd_netlink_message_unref(n)) == NULL);
 
         return EXIT_SUCCESS;
 }

commit e7f25cf7d9ffb832d05a35164dd6658c6631c189
Merge: 485e590 b655a02
Author: David Herrmann <dh.herrmann at googlemail.com>
Date:   Sun Jun 14 13:22:44 2015 +0200

    Merge pull request #178 from utezduyar/man-sd_bus_message_get_creds
    
    Improve the documentation of bus credentials by mentioning send-time metadata. This needs more love, we should really clarify metadata details here. However, this is still better than nothing, so it's fine.


commit 485e590a6119bdef0d73449ffa406e7a702cec08
Merge: f3a8f45 ce67afb
Author: David Herrmann <dh.herrmann at googlemail.com>
Date:   Sun Jun 14 13:16:47 2015 +0200

    Merge pull request #183 from ssahani/net
    
    Improve tun/tap logging by using the new log_*errno*() functions that set 'errno' explicitly. Also fix a bunch of incorrect errno/r confusions.


commit f3a8f45b2128d0b396f000e8a55943857884ac29
Merge: 6113cec b3d5018
Author: David Herrmann <dh.herrmann at googlemail.com>
Date:   Sun Jun 14 13:09:06 2015 +0200

    Merge pull request #191 from kaysievers/resolv
    
    build-sys: merge convenience library libresolve


commit 6113cec066cd673a60e3bb32b9bd1280e86b2490
Merge: d11a602 b95cc75
Author: David Herrmann <dh.herrmann at googlemail.com>
Date:   Sun Jun 14 13:07:20 2015 +0200

    Merge pull request #189 from teg/rtnl-rename
    
    Rename sd_rtnl to sd_netlink to prepare for further netlink-protocol support. Anything rtnl specific still uses the sd_rtnl prefix, but the generic parts (including the bus and message objects) are now called sd_netlink.


commit b3d5018b022e3bab06fa30fd8ad73086172670b4
Author: Kay Sievers <kay at vrfy.org>
Date:   Sun Jun 14 12:46:07 2015 +0200

    build-sys: merge convenience library libresolve

diff --git a/Makefile.am b/Makefile.am
index 381701d..aa2a154 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2911,24 +2911,19 @@ libsystemd_internal_la_SOURCES = \
 	src/libsystemd/sd-device/device-enumerator-private.h \
 	src/libsystemd/sd-device/sd-device.c \
 	src/libsystemd/sd-device/device-private.c \
-	src/libsystemd/sd-device/device-private.h
+	src/libsystemd/sd-device/device-private.h \
+	src/libsystemd/sd-resolve/sd-resolve.c \
+	src/libsystemd/sd-resolve/resolve-util.h
 
 nodist_libsystemd_internal_la_SOURCES = \
 	src/libsystemd/libsystemd.sym
 
 libsystemd_internal_la_LIBADD = \
-	libbasic.la
-
-libsystemd_resolve_la_SOURCES = \
-	src/libsystemd/sd-resolve/sd-resolve.c \
-	src/libsystemd/sd-resolve/resolve-util.h
-
-libsystemd_resolve_la_LIBADD = \
+	libbasic.la \
 	-lresolv
 
 noinst_LTLIBRARIES += \
-	libsystemd-internal.la \
-	libsystemd-resolve.la
+	libsystemd-internal.la
 
 EXTRA_DIST += \
 	src/libsystemd/libsystemd.sym.m4 \
@@ -2941,7 +2936,6 @@ BUILT_SOURCES += \
 
 libsystemd_la_SOURCES = \
 	$(libsystemd_internal_la_SOURCES) \
-	$(libsystemd_resolve_la_SOURCES) \
 	$(libsystemd_journal_internal_la_SOURCES)
 
 nodist_libsystemd_la_SOURCES = \
@@ -2949,7 +2943,6 @@ nodist_libsystemd_la_SOURCES = \
 
 libsystemd_la_CFLAGS = \
 	$(libsystemd_internal_la_CFLAGS) \
-	$(libsystemd_resolve_la_CFLAGS) \
 	$(libsystemd_journal_internal_la_CFLAGS)
 
 libsystemd_la_LDFLAGS = \
@@ -2959,8 +2952,7 @@ libsystemd_la_LDFLAGS = \
 
 libsystemd_la_LIBADD = \
 	$(libsystemd_internal_la_LIBADD) \
-	$(libsystemd_journal_internal_la_LIBADD) \
-	$(libsystemd_resolve_la_LIBADD)
+	$(libsystemd_journal_internal_la_LIBADD)
 
 libsystemd-install-hook:
 	libname=libsystemd.so && $(move-to-rootlibdir)
@@ -3146,7 +3138,6 @@ test_resolve_SOURCES = \
 	src/libsystemd/sd-resolve/test-resolve.c
 
 test_resolve_LDADD = \
-	libsystemd-resolve.la \
 	libshared.la
 
 busctl_SOURCES = \
@@ -4380,8 +4371,7 @@ systemd_socket_proxyd_SOURCES = \
 
 systemd_socket_proxyd_LDADD = \
 	libsystemd-journal-internal.la \
-	libshared.la \
-	libsystemd-resolve.la
+	libshared.la
 
 # ------------------------------------------------------------------------------
 if ENABLE_COREDUMP
@@ -4845,7 +4835,6 @@ gperf_gperf_sources += \
 	src/timesync/timesyncd-gperf.gperf
 
 systemd_timesyncd_LDADD = \
-	libsystemd-resolve.la \
 	libsystemd-network.la \
 	libshared.la
 

commit ce67afb04320c5b94435dd171af68629b54bb7b5
Author: Susant Sahani <susant at redhat.com>
Date:   Fri Jun 12 14:01:51 2015 +0530

    networkd: tuntap improve logging
    
    Replaces  strerror() usage with log_netdev_error_errno()

diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 4e97492..378312f 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -69,18 +69,12 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
         assert(ifr);
 
         fd = open(TUN_DEV, O_RDWR);
-        if (fd < 0) {
-                log_netdev_error(netdev, "Failed to open tun dev: %m");
-                return -errno;
-        }
+        if (fd < 0)
+                return log_netdev_error_errno(netdev, -errno,  "Failed to open tun dev: %m");
 
         r = ioctl(fd, TUNSETIFF, ifr);
-        if (r < 0) {
-                log_netdev_error(netdev,
-                                 "TUNSETIFF failed on tun dev: %s",
-                                 strerror(-r));
-                return r;
-        }
+        if (r < 0)
+                return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
 
         if (netdev->kind == NETDEV_KIND_TAP)
                 t = TAP(netdev);
@@ -94,18 +88,12 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
                 user = t->user_name;
 
                 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
-                if (r < 0) {
-                        log_error_errno(r, "Cannot resolve user name %s: %m",
-                                        t->user_name);
-                        return 0;
-                }
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
 
                 r = ioctl(fd, TUNSETOWNER, uid);
-                if ( r < 0) {
-                        log_netdev_error(netdev,
-                                         "TUNSETOWNER failed on tun dev: %s",
-                                         strerror(-r));
-                }
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
         }
 
         if (t->group_name) {
@@ -113,29 +101,18 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
                 group = t->group_name;
 
                 r = get_group_creds(&group, &gid);
-                if (r < 0) {
-                        log_error_errno(r, "Cannot resolve group name %s: %m",
-                                        t->group_name);
-                        return 0;
-                }
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
 
                 r = ioctl(fd, TUNSETGROUP, gid);
-                if( r < 0) {
-                        log_netdev_error(netdev,
-                                         "TUNSETGROUP failed on tun dev: %s",
-                                         strerror(-r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
 
         }
 
         r = ioctl(fd, TUNSETPERSIST, 1);
-        if (r < 0) {
-                log_netdev_error(netdev,
-                                 "TUNSETPERSIST failed on tun dev: %s",
-                                 strerror(-r));
-                return r;
-        }
+        if (r < 0)
+                return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
 
         return 0;
 }

commit b95cc756de7a27f7546e42dd9acf6da0669da402
Author: Tom Gundersen <teg at jklm.no>
Date:   Sat Jun 13 21:25:05 2015 +0200

    sd-netlink: socket - move some functions from main source file

diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index 763acbb..7290f4e 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -113,6 +113,9 @@ struct sd_netlink_message {
 int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type);
 int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
 
+int socket_open(int family);
+int socket_bind(sd_netlink *nl);
+int socket_join_broadcast_group(sd_netlink *nl, unsigned group);
 int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
 int socket_read_message(sd_netlink *nl);
 
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c
index 2e2826a..8136cf3 100644
--- a/src/libsystemd/sd-netlink/netlink-socket.c
+++ b/src/libsystemd/sd-netlink/netlink-socket.c
@@ -34,6 +34,53 @@
 #include "netlink-internal.h"
 #include "netlink-types.h"
 
+int socket_open(int family) {
+        int fd;
+
+        fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, family);
+        if (fd < 0)
+                return -errno;
+
+        return fd;
+}
+
+int socket_bind(sd_netlink *nl) {
+        socklen_t addrlen;
+        int r, one = 1;
+
+        r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
+        if (r < 0)
+                return -errno;
+
+        addrlen = sizeof(nl->sockaddr);
+
+        r = bind(nl->fd, &nl->sockaddr.sa, addrlen);
+        /* ignore EINVAL to allow opening an already bound socket */
+        if (r < 0 && errno != EINVAL)
+                return -errno;
+
+        r = getsockname(nl->fd, &nl->sockaddr.sa, &addrlen);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+
+int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
+        int r;
+
+        assert(nl);
+        assert(nl->fd >= 0);
+        assert(group > 0);
+
+        r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
 /* returns the number of bytes sent, or a negative error code */
 int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
         union {
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index 572de90..c413b1c 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -103,8 +103,7 @@ static bool rtnl_pid_changed(sd_netlink *rtnl) {
 
 int sd_netlink_open_fd(sd_netlink **ret, int fd) {
         _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
-        socklen_t addrlen;
-        int r, one = 1;
+        int r;
 
         assert_return(ret, -EINVAL);
         assert_return(fd >= 0, -EINVAL);
@@ -113,22 +112,11 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
         if (r < 0)
                 return r;
 
-        r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
-        if (r < 0)
-                return -errno;
-
-        addrlen = sizeof(rtnl->sockaddr);
-
-        r = bind(fd, &rtnl->sockaddr.sa, addrlen);
-        /* ignore EINVAL to allow opening an already bound socket */
-        if (r < 0 && errno != EINVAL)
-                return -errno;
+        rtnl->fd = fd;
 
-        r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
+        r = socket_bind(rtnl);
         if (r < 0)
-                return -errno;
-
-        rtnl->fd = fd;
+                return r;
 
         *ret = rtnl;
         rtnl = NULL;
@@ -140,9 +128,9 @@ int sd_netlink_open(sd_netlink **ret) {
         _cleanup_close_ int fd = -1;
         int r;
 
-        fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
+        fd = socket_open(NETLINK_ROUTE);
         if (fd < 0)
-                return -errno;
+                return fd;
 
         r = sd_netlink_open_fd(ret, fd);
         if (r < 0)
@@ -153,20 +141,6 @@ int sd_netlink_open(sd_netlink **ret) {
         return 0;
 }
 
-static int rtnl_join_broadcast_group(sd_netlink *rtnl, unsigned group) {
-        int r;
-
-        assert(rtnl);
-        assert(rtnl->fd >= 0);
-        assert(group > 0);
-
-        r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
 int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size) {
         return fd_inc_rcvbuf(rtnl->fd, size);
 }
@@ -885,7 +859,7 @@ int sd_netlink_add_match(sd_netlink *rtnl,
                 case RTM_SETLINK:
                 case RTM_GETLINK:
                 case RTM_DELLINK:
-                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_LINK);
+                        r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK);
                         if (r < 0)
                                 return r;
 
@@ -893,11 +867,11 @@ int sd_netlink_add_match(sd_netlink *rtnl,
                 case RTM_NEWADDR:
                 case RTM_GETADDR:
                 case RTM_DELADDR:
-                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
+                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
                         if (r < 0)
                                 return r;
 
-                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
+                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
                         if (r < 0)
                                 return r;
 

commit 89489ef7d451d61e176764deb608a84e29b1fd38
Author: Tom Gundersen <teg at jklm.no>
Date:   Sat Jun 13 21:10:39 2015 +0200

    sd-netlink: message - split up source file
    
    Split netlink-socket.c and rtnl-message.c from netlink-message.c.

diff --git a/Makefile.am b/Makefile.am
index 0f779d1..78acefb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2913,6 +2913,8 @@ libsystemd_internal_la_SOURCES = \
 	src/libsystemd/sd-netlink/sd-netlink.c \
 	src/libsystemd/sd-netlink/netlink-internal.h \
 	src/libsystemd/sd-netlink/netlink-message.c \
+	src/libsystemd/sd-netlink/netlink-socket.c \
+	src/libsystemd/sd-netlink/rtnl-message.c \
 	src/libsystemd/sd-netlink/netlink-types.h \
 	src/libsystemd/sd-netlink/netlink-types.c \
 	src/libsystemd/sd-netlink/netlink-util.h \
diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index 24ebbbe..763acbb 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -111,6 +111,7 @@ struct sd_netlink_message {
 };
 
 int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type);
+int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
 
 int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
 int socket_read_message(sd_netlink *nl);
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index fe9714a..87324fc 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -39,7 +39,7 @@
 
 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
 
-static int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
+int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
         sd_netlink_message *m;
 
         assert_return(ret, -EINVAL);
@@ -95,305 +95,6 @@ int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
         return 0;
 }
 
-int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
-            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
-                return -ERANGE;
-
-        rtm->rtm_dst_len = prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
-            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
-                return -ERANGE;
-
-        rtm->rtm_src_len = prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        rtm->rtm_scope = scope;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(family, -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        *family = rtm->rtm_family;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(dst_len, -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        *dst_len = rtm->rtm_dst_len;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(src_len, -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        *src_len = rtm->rtm_src_len;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
-                              uint16_t nlmsg_type, int rtm_family,
-                              unsigned char rtm_protocol) {
-        struct rtmsg *rtm;
-        int r;
-
-        assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
-        assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
-                      rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_NEWROUTE)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
-
-        rtm = NLMSG_DATA((*ret)->hdr);
-
-        rtm->rtm_family = rtm_family;
-        rtm->rtm_scope = RT_SCOPE_UNIVERSE;
-        rtm->rtm_type = RTN_UNICAST;
-        rtm->rtm_table = RT_TABLE_MAIN;
-        rtm->rtm_protocol = rtm_protocol;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        ndm->ndm_flags |= flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        ndm->ndm_state |= state;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        *flags = ndm->ndm_flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        *state = ndm->ndm_state;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(family, -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-
-        *family = ndm->ndm_family;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(index, -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-
-        *index = ndm->ndm_ifindex;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_neigh(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
-        struct ndmsg *ndm;
-        int r;
-
-        assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
-        assert_return(ndm_family == AF_INET  ||
-                      ndm_family == AF_INET6 ||
-                      ndm_family == PF_BRIDGE, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_NEWNEIGH)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
-
-        ndm = NLMSG_DATA((*ret)->hdr);
-
-        ndm->ndm_family = ndm_family;
-        ndm->ndm_ifindex = index;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(change, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_flags = flags;
-        ifi->ifi_change = change;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_type = type;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_family = family;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
-                             uint16_t nlmsg_type, int index) {
-        struct ifinfomsg *ifi;
-        int r;
-
-        assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
-        assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_NEWLINK)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
-
-        ifi = NLMSG_DATA((*ret)->hdr);
-
-        ifi->ifi_family = AF_UNSPEC;
-        ifi->ifi_index = index;
-
-        return 0;
-}
-
 int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
         assert_return(m, -EINVAL);
         assert_return(m->hdr, -EINVAL);
@@ -411,172 +112,6 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
         return 0;
 }
 
-int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
-            (ifa->ifa_family == AF_INET6 && prefixlen > 128))
-                return -ERANGE;
-
-        ifa->ifa_prefixlen = prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        ifa->ifa_flags = flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        ifa->ifa_scope = scope;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(family, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *family = ifa->ifa_family;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(prefixlen, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *prefixlen = ifa->ifa_prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(scope, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *scope = ifa->ifa_scope;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(flags, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *flags = ifa->ifa_flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(ifindex, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *ifindex = ifa->ifa_index;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_addr(sd_netlink *rtnl, sd_netlink_message **ret,
-                             uint16_t nlmsg_type, int index,
-                             int family) {
-        struct ifaddrmsg *ifa;
-        int r;
-
-        assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
-        assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
-                      index > 0, -EINVAL);
-        assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
-                      family == AF_INET || family == AF_INET6, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_GETADDR)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
-
-        ifa = NLMSG_DATA((*ret)->hdr);
-
-        ifa->ifa_index = index;
-        ifa->ifa_family = family;
-        if (family == AF_INET)
-                ifa->ifa_prefixlen = 32;
-        else if (family == AF_INET6)
-                ifa->ifa_prefixlen = 128;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_addr_update(sd_netlink *rtnl, sd_netlink_message **ret,
-                             int index, int family) {
-        int r;
-
-        r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
-        if (r < 0)
-                return r;
-
-        (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
-
-        return 0;
-}
-
 sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
         if (m)
                 assert_se(REFCNT_INC(m->n_ref) >= 2);
@@ -610,100 +145,12 @@ int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
         return 0;
 }
 
-int sd_netlink_message_get_family(sd_netlink_message *m, int *family) {
-        assert_return(m, -EINVAL);
-        assert_return(family, -EINVAL);
-
-        assert(m->hdr);
-
-        if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
-                struct ifinfomsg *ifi;
-
-                ifi = NLMSG_DATA(m->hdr);
-
-                *family = ifi->ifi_family;
-
-                return 0;
-        } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
-                struct rtmsg *rtm;
-
-                rtm = NLMSG_DATA(m->hdr);
-
-                *family = rtm->rtm_family;
-
-                return 0;
-        } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
-                struct ndmsg *ndm;
-
-                ndm = NLMSG_DATA(m->hdr);
-
-                *family = ndm->ndm_family;
-
-                return 0;
-        } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
-                struct ifaddrmsg *ifa;
-
-                ifa = NLMSG_DATA(m->hdr);
-
-                *family = ifa->ifa_family;
-
-                return 0;
-        }
-
-        return -EOPNOTSUPP;
-}
-
 int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
         assert_return(m, -EINVAL);
 
         return m->broadcast;
 }
 
-int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(ifindex, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *ifindex = ifi->ifi_index;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(flags, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *flags = ifi->ifi_flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(type, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *type = ifi->ifi_type;
-
-        return 0;
-}
-
 /* If successful the updated message will be correctly aligned, if
    unsuccessful the old message is untouched. */
 static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
@@ -951,7 +398,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type
                         return r;
                 size = (size_t) r;
 
-                r = sd_netlink_message_get_family(m, &family);
+                r = sd_rtnl_message_get_family(m, &family);
                 if (r < 0)
                         return r;
 
@@ -1274,7 +721,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
                 {
                         int family;
 
-                        r = sd_netlink_message_get_family(m, &family);
+                        r = sd_rtnl_message_get_family(m, &family);
                         if (r < 0)
                                 return r;
 
@@ -1393,246 +840,6 @@ int rtnl_message_parse(sd_netlink_message *m,
         return 0;
 }
 
-/* returns the number of bytes sent, or a negative error code */
-int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } addr = {
-                .nl.nl_family = AF_NETLINK,
-        };
-        ssize_t k;
-
-        assert(nl);
-        assert(m);
-        assert(m->hdr);
-
-        k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
-                        0, &addr.sa, sizeof(addr));
-        if (k < 0)
-                return -errno;
-
-        return k;
-}
-
-static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
-        union sockaddr_union sender;
-        uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
-        struct msghdr msg = {
-                .msg_iov = iov,
-                .msg_iovlen = 1,
-                .msg_name = &sender,
-                .msg_namelen = sizeof(sender),
-                .msg_control = cmsg_buffer,
-                .msg_controllen = sizeof(cmsg_buffer),
-        };
-        struct cmsghdr *cmsg;
-        uint32_t group = 0;
-        int r;
-
-        assert(fd >= 0);
-        assert(iov);
-
-        r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
-        if (r < 0) {
-                /* no data */
-                if (errno == ENOBUFS)
-                        log_debug("rtnl: kernel receive buffer overrun");
-                else if (errno == EAGAIN)
-                        log_debug("rtnl: no data in socket");
-
-                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
-        }
-
-        if (sender.nl.nl_pid != 0) {
-                /* not from the kernel, ignore */
-                log_debug("rtnl: ignoring message from portid %"PRIu32, sender.nl.nl_pid);
-
-                if (peek) {
-                        /* drop the message */
-                        r = recvmsg(fd, &msg, 0);
-                        if (r < 0)
-                                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
-                }
-
-                return 0;
-        }
-
-        CMSG_FOREACH(cmsg, &msg) {
-                if (cmsg->cmsg_level == SOL_NETLINK &&
-                    cmsg->cmsg_type == NETLINK_PKTINFO &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
-                        struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
-
-                        /* multi-cast group */
-                        group = pktinfo->group;
-                }
-        }
-
-        if (_group)
-                *_group = group;
-
-        return r;
-}
-
-/* On success, the number of bytes received is returned and *ret points to the received message
- * which has a valid header and the correct size.
- * If nothing useful was received 0 is returned.
- * On failure, a negative error code is returned.
- */
-int socket_read_message(sd_netlink *rtnl) {
-        _cleanup_netlink_message_unref_ sd_netlink_message *first = NULL;
-        struct iovec iov = {};
-        uint32_t group = 0;
-        bool multi_part = false, done = false;
-        struct nlmsghdr *new_msg;
-        size_t len;
-        int r;
-        unsigned i = 0;
-
-        assert(rtnl);
-        assert(rtnl->rbuffer);
-        assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
-
-        /* read nothing, just get the pending message size */
-        r = socket_recv_message(rtnl->fd, &iov, NULL, true);
-        if (r <= 0)
-                return r;
-        else
-                len = (size_t)r;
-
-        /* make room for the pending message */
-        if (!greedy_realloc((void **)&rtnl->rbuffer,
-                            &rtnl->rbuffer_allocated,
-                            len, sizeof(uint8_t)))
-                return -ENOMEM;
-
-        iov.iov_base = rtnl->rbuffer;
-        iov.iov_len = rtnl->rbuffer_allocated;
-
-        /* read the pending message */
-        r = socket_recv_message(rtnl->fd, &iov, &group, false);
-        if (r <= 0)
-                return r;
-        else
-                len = (size_t)r;
-
-        if (len > rtnl->rbuffer_allocated)
-                /* message did not fit in read buffer */
-                return -EIO;
-
-        if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
-                multi_part = true;
-
-                for (i = 0; i < rtnl->rqueue_partial_size; i++) {
-                        if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
-                            rtnl->rbuffer->nlmsg_seq) {
-                                first = rtnl->rqueue_partial[i];
-                                break;
-                        }
-                }
-        }
-
-        for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
-                _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
-                const NLType *nl_type;
-
-                if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
-                        /* not broadcast and not for us */
-                        continue;
-
-                if (new_msg->nlmsg_type == NLMSG_NOOP)
-                        /* silently drop noop messages */
-                        continue;
-
-                if (new_msg->nlmsg_type == NLMSG_DONE) {
-                        /* finished reading multi-part message */
-                        done = true;
-
-                        /* if first is not defined, put NLMSG_DONE into the receive queue. */
-                        if (first)
-                                continue;
-                }
-
-                /* check that we support this message type */
-                r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
-                if (r < 0) {
-                        if (r == -EOPNOTSUPP)
-                                log_debug("sd-netlink: ignored message with unknown type: %i",
-                                          new_msg->nlmsg_type);
-
-                        continue;
-                }
-
-                /* check that the size matches the message type */
-                if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
-                        log_debug("sd-netlink: message larger than expected, dropping");
-                        continue;
-                }
-
-                r = message_new_empty(rtnl, &m);
-                if (r < 0)
-                        return r;
-
-                m->broadcast = !!group;
-
-                m->hdr = memdup(new_msg, new_msg->nlmsg_len);
-                if (!m->hdr)
-                        return -ENOMEM;
-
-                /* seal and parse the top-level message */
-                r = sd_netlink_message_rewind(m);
-                if (r < 0)
-                        return r;
-
-                /* push the message onto the multi-part message stack */
-                if (first)
-                        m->next = first;
-                first = m;
-                m = NULL;
-        }
-
-        if (len)
-                log_debug("sd-netlink: discarding %zu bytes of incoming message", len);
-
-        if (!first)
-                return 0;
-
-        if (!multi_part || done) {
-                /* we got a complete message, push it on the read queue */
-                r = rtnl_rqueue_make_room(rtnl);
-                if (r < 0)
-                        return r;
-
-                rtnl->rqueue[rtnl->rqueue_size ++] = first;
-                first = NULL;
-
-                if (multi_part && (i < rtnl->rqueue_partial_size)) {
-                        /* remove the message form the partial read queue */
-                        memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
-                                sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1));
-                        rtnl->rqueue_partial_size --;
-                }
-
-                return 1;
-        } else {
-                /* we only got a partial multi-part message, push it on the
-                   partial read queue */
-                if (i < rtnl->rqueue_partial_size) {
-                        rtnl->rqueue_partial[i] = first;
-                } else {
-                        r = rtnl_rqueue_partial_make_room(rtnl);
-                        if (r < 0)
-                                return r;
-
-                        rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
-                }
-                first = NULL;
-
-                return 0;
-        }
-}
-
 int sd_netlink_message_rewind(sd_netlink_message *m) {
         const NLType *type;
         unsigned i;
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c
new file mode 100644
index 0000000..2e2826a
--- /dev/null
+++ b/src/libsystemd/sd-netlink/netlink-socket.c
@@ -0,0 +1,275 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "socket-util.h"
+#include "formats-util.h"
+#include "refcnt.h"
+#include "missing.h"
+
+#include "sd-netlink.h"
+#include "netlink-util.h"
+#include "netlink-internal.h"
+#include "netlink-types.h"
+
+/* returns the number of bytes sent, or a negative error code */
+int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } addr = {
+                .nl.nl_family = AF_NETLINK,
+        };
+        ssize_t k;
+
+        assert(nl);
+        assert(m);
+        assert(m->hdr);
+
+        k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
+                        0, &addr.sa, sizeof(addr));
+        if (k < 0)
+                return -errno;
+
+        return k;
+}
+
+static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
+        union sockaddr_union sender;
+        uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
+        struct msghdr msg = {
+                .msg_iov = iov,
+                .msg_iovlen = 1,
+                .msg_name = &sender,
+                .msg_namelen = sizeof(sender),
+                .msg_control = cmsg_buffer,
+                .msg_controllen = sizeof(cmsg_buffer),
+        };
+        struct cmsghdr *cmsg;
+        uint32_t group = 0;
+        int r;
+
+        assert(fd >= 0);
+        assert(iov);
+
+        r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
+        if (r < 0) {
+                /* no data */
+                if (errno == ENOBUFS)
+                        log_debug("rtnl: kernel receive buffer overrun");
+                else if (errno == EAGAIN)
+                        log_debug("rtnl: no data in socket");
+
+                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
+        }
+
+        if (sender.nl.nl_pid != 0) {
+                /* not from the kernel, ignore */
+                log_debug("rtnl: ignoring message from portid %"PRIu32, sender.nl.nl_pid);
+
+                if (peek) {
+                        /* drop the message */
+                        r = recvmsg(fd, &msg, 0);
+                        if (r < 0)
+                                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
+                }
+
+                return 0;
+        }
+
+        CMSG_FOREACH(cmsg, &msg) {
+                if (cmsg->cmsg_level == SOL_NETLINK &&
+                    cmsg->cmsg_type == NETLINK_PKTINFO &&
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
+                        struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
+
+                        /* multi-cast group */
+                        group = pktinfo->group;
+                }
+        }
+
+        if (_group)
+                *_group = group;
+
+        return r;
+}
+
+/* On success, the number of bytes received is returned and *ret points to the received message
+ * which has a valid header and the correct size.
+ * If nothing useful was received 0 is returned.
+ * On failure, a negative error code is returned.
+ */
+int socket_read_message(sd_netlink *rtnl) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *first = NULL;
+        struct iovec iov = {};
+        uint32_t group = 0;
+        bool multi_part = false, done = false;
+        struct nlmsghdr *new_msg;
+        size_t len;
+        int r;
+        unsigned i = 0;
+
+        assert(rtnl);
+        assert(rtnl->rbuffer);
+        assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
+
+        /* read nothing, just get the pending message size */
+        r = socket_recv_message(rtnl->fd, &iov, NULL, true);
+        if (r <= 0)
+                return r;
+        else
+                len = (size_t)r;
+
+        /* make room for the pending message */
+        if (!greedy_realloc((void **)&rtnl->rbuffer,
+                            &rtnl->rbuffer_allocated,
+                            len, sizeof(uint8_t)))
+                return -ENOMEM;
+
+        iov.iov_base = rtnl->rbuffer;
+        iov.iov_len = rtnl->rbuffer_allocated;
+
+        /* read the pending message */
+        r = socket_recv_message(rtnl->fd, &iov, &group, false);
+        if (r <= 0)
+                return r;
+        else
+                len = (size_t)r;
+
+        if (len > rtnl->rbuffer_allocated)
+                /* message did not fit in read buffer */
+                return -EIO;
+
+        if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
+                multi_part = true;
+
+                for (i = 0; i < rtnl->rqueue_partial_size; i++) {
+                        if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
+                            rtnl->rbuffer->nlmsg_seq) {
+                                first = rtnl->rqueue_partial[i];
+                                break;
+                        }
+                }
+        }
+
+        for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
+                _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+                const NLType *nl_type;
+
+                if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
+                        /* not broadcast and not for us */
+                        continue;
+
+                if (new_msg->nlmsg_type == NLMSG_NOOP)
+                        /* silently drop noop messages */
+                        continue;
+
+                if (new_msg->nlmsg_type == NLMSG_DONE) {
+                        /* finished reading multi-part message */
+                        done = true;
+
+                        /* if first is not defined, put NLMSG_DONE into the receive queue. */
+                        if (first)
+                                continue;
+                }
+
+                /* check that we support this message type */
+                r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
+                if (r < 0) {
+                        if (r == -EOPNOTSUPP)
+                                log_debug("sd-netlink: ignored message with unknown type: %i",
+                                          new_msg->nlmsg_type);
+
+                        continue;
+                }
+
+                /* check that the size matches the message type */
+                if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
+                        log_debug("sd-netlink: message larger than expected, dropping");
+                        continue;
+                }
+
+                r = message_new_empty(rtnl, &m);
+                if (r < 0)
+                        return r;
+
+                m->broadcast = !!group;
+
+                m->hdr = memdup(new_msg, new_msg->nlmsg_len);
+                if (!m->hdr)
+                        return -ENOMEM;
+
+                /* seal and parse the top-level message */
+                r = sd_netlink_message_rewind(m);
+                if (r < 0)
+                        return r;
+
+                /* push the message onto the multi-part message stack */
+                if (first)
+                        m->next = first;
+                first = m;
+                m = NULL;
+        }
+
+        if (len)
+                log_debug("sd-netlink: discarding %zu bytes of incoming message", len);
+
+        if (!first)
+                return 0;
+
+        if (!multi_part || done) {
+                /* we got a complete message, push it on the read queue */
+                r = rtnl_rqueue_make_room(rtnl);
+                if (r < 0)
+                        return r;
+
+                rtnl->rqueue[rtnl->rqueue_size ++] = first;
+                first = NULL;
+
+                if (multi_part && (i < rtnl->rqueue_partial_size)) {
+                        /* remove the message form the partial read queue */
+                        memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
+                                sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1));
+                        rtnl->rqueue_partial_size --;
+                }
+
+                return 1;
+        } else {
+                /* we only got a partial multi-part message, push it on the
+                   partial read queue */
+                if (i < rtnl->rqueue_partial_size) {
+                        rtnl->rqueue_partial[i] = first;
+                } else {
+                        r = rtnl_rqueue_partial_make_room(rtnl);
+                        if (r < 0)
+                                return r;
+
+                        rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
+                }
+                first = NULL;
+
+                return 0;
+        }
+}
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
new file mode 100644
index 0000000..2f31f4e
--- /dev/null
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -0,0 +1,588 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "socket-util.h"
+#include "formats-util.h"
+#include "refcnt.h"
+#include "missing.h"
+
+#include "sd-netlink.h"
+#include "netlink-util.h"
+#include "netlink-internal.h"
+#include "netlink-types.h"
+
+int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
+            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
+                return -ERANGE;
+
+        rtm->rtm_dst_len = prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
+            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
+                return -ERANGE;
+
+        rtm->rtm_src_len = prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        rtm->rtm_scope = scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(family, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *family = rtm->rtm_family;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(dst_len, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *dst_len = rtm->rtm_dst_len;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(src_len, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *src_len = rtm->rtm_src_len;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
+                              uint16_t nlmsg_type, int rtm_family,
+                              unsigned char rtm_protocol) {
+        struct rtmsg *rtm;
+        int r;
+
+        assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
+        assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
+                      rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_NEWROUTE)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
+
+        rtm = NLMSG_DATA((*ret)->hdr);
+
+        rtm->rtm_family = rtm_family;
+        rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+        rtm->rtm_type = RTN_UNICAST;
+        rtm->rtm_table = RT_TABLE_MAIN;
+        rtm->rtm_protocol = rtm_protocol;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        ndm->ndm_flags |= flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        ndm->ndm_state |= state;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        *flags = ndm->ndm_flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        *state = ndm->ndm_state;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(family, -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+
+        *family = ndm->ndm_family;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(index, -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+
+        *index = ndm->ndm_ifindex;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_neigh(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
+        struct ndmsg *ndm;
+        int r;
+
+        assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
+        assert_return(ndm_family == AF_INET  ||
+                      ndm_family == AF_INET6 ||
+                      ndm_family == PF_BRIDGE, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_NEWNEIGH)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
+
+        ndm = NLMSG_DATA((*ret)->hdr);
+
+        ndm->ndm_family = ndm_family;
+        ndm->ndm_ifindex = index;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(change, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_flags = flags;
+        ifi->ifi_change = change;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_type = type;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_family = family;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
+                             uint16_t nlmsg_type, int index) {
+        struct ifinfomsg *ifi;
+        int r;
+
+        assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
+        assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_NEWLINK)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+
+        ifi = NLMSG_DATA((*ret)->hdr);
+
+        ifi->ifi_family = AF_UNSPEC;
+        ifi->ifi_index = index;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
+            (ifa->ifa_family == AF_INET6 && prefixlen > 128))
+                return -ERANGE;
+
+        ifa->ifa_prefixlen = prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        ifa->ifa_flags = flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        ifa->ifa_scope = scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(family, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *family = ifa->ifa_family;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(prefixlen, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *prefixlen = ifa->ifa_prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(scope, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *scope = ifa->ifa_scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(flags, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *flags = ifa->ifa_flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(ifindex, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *ifindex = ifa->ifa_index;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_addr(sd_netlink *rtnl, sd_netlink_message **ret,
+                             uint16_t nlmsg_type, int index,
+                             int family) {
+        struct ifaddrmsg *ifa;
+        int r;
+
+        assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
+        assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
+                      index > 0, -EINVAL);
+        assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
+                      family == AF_INET || family == AF_INET6, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_GETADDR)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
+
+        ifa = NLMSG_DATA((*ret)->hdr);
+
+        ifa->ifa_index = index;
+        ifa->ifa_family = family;
+        if (family == AF_INET)
+                ifa->ifa_prefixlen = 32;
+        else if (family == AF_INET6)
+                ifa->ifa_prefixlen = 128;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_addr_update(sd_netlink *rtnl, sd_netlink_message **ret,
+                             int index, int family) {
+        int r;
+
+        r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(ifindex, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *ifindex = ifi->ifi_index;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(flags, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *flags = ifi->ifi_flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(type, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *type = ifi->ifi_type;
+
+        return 0;
+}
+
+int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
+        assert_return(m, -EINVAL);
+        assert_return(family, -EINVAL);
+
+        assert(m->hdr);
+
+        if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
+                struct ifinfomsg *ifi;
+
+                ifi = NLMSG_DATA(m->hdr);
+
+                *family = ifi->ifi_family;
+
+                return 0;
+        } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
+                struct rtmsg *rtm;
+
+                rtm = NLMSG_DATA(m->hdr);
+
+                *family = rtm->rtm_family;
+
+                return 0;
+        } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
+                struct ndmsg *ndm;
+
+                ndm = NLMSG_DATA(m->hdr);
+
+                *family = ndm->ndm_family;
+
+                return 0;
+        } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
+                struct ifaddrmsg *ifa;
+
+                ifa = NLMSG_DATA(m->hdr);
+
+                *family = ifa->ifa_family;
+
+                return 0;
+        }
+
+        return -EOPNOTSUPP;
+}
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index 7f6af54..24a9ed8 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -113,7 +113,7 @@ int sd_rtnl_message_new_addr(sd_netlink *nl, sd_netlink_message **ret, uint16_t
 int sd_rtnl_message_new_route(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, int rtm_family, unsigned char rtm_protocol);
 int sd_rtnl_message_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int nda_family);
 
-int sd_netlink_message_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_get_family(sd_netlink_message *m, int *family);
 
 int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
 int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope);

commit bbe181b489921e5afeaa2b0bc1c16c62aeef8f65
Author: Tom Gundersen <teg at jklm.no>
Date:   Sat Jun 13 20:51:56 2015 +0200

    sd-netlink: drop the write-queue
    
    AF_NETLINK is not write-buffered, so this was actually never used.

diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index ff663f9..24ebbbe 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -72,10 +72,6 @@ struct sd_netlink {
         unsigned rqueue_partial_size;
         size_t rqueue_partial_allocated;
 
-        sd_netlink_message **wqueue;
-        unsigned wqueue_size;
-        size_t wqueue_allocated;
-
         struct nlmsghdr *rbuffer;
         size_t rbuffer_allocated;
 
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 9c280b1..fe9714a 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -1410,7 +1410,7 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
                         0, &addr.sa, sizeof(addr));
         if (k < 0)
-                return (errno == EAGAIN) ? 0 : -errno;
+                return -errno;
 
         return k;
 }
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index 14cc759..572de90 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -50,11 +50,6 @@ static int sd_netlink_new(sd_netlink **ret) {
 
         LIST_HEAD_INIT(rtnl->match_callbacks);
 
-        /* We guarantee that wqueue always has space for at least
-         * one entry */
-        if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
-                return -ENOMEM;
-
         /* We guarantee that the read buffer has at least space for
          * a message header */
         if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
@@ -204,10 +199,6 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
                         sd_netlink_message_unref(rtnl->rqueue_partial[i]);
                 free(rtnl->rqueue_partial);
 
-                for (i = 0; i < rtnl->wqueue_size; i++)
-                        sd_netlink_message_unref(rtnl->wqueue[i]);
-                free(rtnl->wqueue);
-
                 free(rtnl->rbuffer);
 
                 hashmap_free_free(rtnl->reply_callbacks);
@@ -215,7 +206,6 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
 
                 sd_event_source_unref(rtnl->io_event_source);
                 sd_event_source_unref(rtnl->time_event_source);
-                sd_event_source_unref(rtnl->exit_event_source);
                 sd_event_unref(rtnl->event);
 
                 while ((f = rtnl->match_callbacks)) {
@@ -257,29 +247,9 @@ int sd_netlink_send(sd_netlink *nl,
 
         rtnl_seal_message(nl, message);
 
-        if (nl->wqueue_size <= 0) {
-                /* send directly */
-                r = socket_write_message(nl, message);
-                if (r < 0)
-                        return r;
-                else if (r == 0) {
-                        /* nothing was sent, so let's put it on
-                         * the queue */
-                        nl->wqueue[0] = sd_netlink_message_ref(message);
-                        nl->wqueue_size = 1;
-                }
-        } else {
-                /* append to queue */
-                if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
-                        log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
-                        return -ENOBUFS;
-                }
-
-                if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
-                        return -ENOMEM;
-
-                nl->wqueue[nl->wqueue_size ++] = sd_netlink_message_ref(message);
-        }
+        r = socket_write_message(nl, message);
+        if (r < 0)
+                return r;
 
         if (serial)
                 *serial = rtnl_message_get_serial(message);
@@ -337,31 +307,6 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
         return 1;
 }
 
-static int dispatch_wqueue(sd_netlink *rtnl) {
-        int r, ret = 0;
-
-        assert(rtnl);
-
-        while (rtnl->wqueue_size > 0) {
-                r = socket_write_message(rtnl, rtnl->wqueue[0]);
-                if (r < 0)
-                        return r;
-                else if (r == 0)
-                        /* Didn't do anything this time */
-                        return ret;
-                else {
-                        /* see equivalent in sd-bus.c */
-                        sd_netlink_message_unref(rtnl->wqueue[0]);
-                        rtnl->wqueue_size --;
-                        memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_netlink_message*) * rtnl->wqueue_size);
-
-                        ret = 1;
-                }
-        }
-
-        return ret;
-}
-
 static int process_timeout(sd_netlink *rtnl) {
         _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
         struct reply_callback *c;
@@ -462,10 +407,6 @@ static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) {
         if (r != 0)
                 goto null_message;
 
-        r = dispatch_wqueue(rtnl);
-        if (r != 0)
-                goto null_message;
-
         r = dispatch_rqueue(rtnl, &m);
         if (r < 0)
                 return r;
@@ -759,48 +700,17 @@ int sd_netlink_call(sd_netlink *rtnl,
                         return r;
                 else if (r == 0)
                         return -ETIMEDOUT;
-
-                r = dispatch_wqueue(rtnl);
-                if (r < 0)
-                        return r;
-        }
-}
-
-int sd_netlink_flush(sd_netlink *rtnl) {
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        if (rtnl->wqueue_size <= 0)
-                return 0;
-
-        for (;;) {
-                r = dispatch_wqueue(rtnl);
-                if (r < 0)
-                        return r;
-
-                if (rtnl->wqueue_size <= 0)
-                        return 0;
-
-                r = rtnl_poll(rtnl, false, (uint64_t) -1);
-                if (r < 0)
-                        return r;
         }
 }
 
 int sd_netlink_get_events(sd_netlink *rtnl) {
-        int flags = 0;
-
         assert_return(rtnl, -EINVAL);
         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
 
-        if (rtnl->rqueue_size <= 0)
-                flags |= POLLIN;
-        if (rtnl->wqueue_size > 0)
-                flags |= POLLOUT;
-
-        return flags;
+        if (rtnl->rqueue_size == 0)
+                return POLLIN;
+        else
+                return 0;
 }
 
 int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) {
@@ -886,16 +796,6 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
         return 1;
 }
 
-static int exit_callback(sd_event_source *event, void *userdata) {
-        sd_netlink *rtnl = userdata;
-
-        assert(event);
-
-        sd_netlink_flush(rtnl);
-
-        return 1;
-}
-
 int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) {
         int r;
 
@@ -941,14 +841,6 @@ int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) {
         if (r < 0)
                 goto fail;
 
-        r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
-        if (r < 0)
-                goto fail;
-
         return 0;
 
 fail:
@@ -960,17 +852,11 @@ int sd_netlink_detach_event(sd_netlink *rtnl) {
         assert_return(rtnl, -EINVAL);
         assert_return(rtnl->event, -ENXIO);
 
-        if (rtnl->io_event_source)
-                rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
-
-        if (rtnl->time_event_source)
-                rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
+        rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
 
-        if (rtnl->exit_event_source)
-                rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
+        rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
 
-        if (rtnl->event)
-                rtnl->event = sd_event_unref(rtnl->event);
+        rtnl->event = sd_event_unref(rtnl->event);
 
         return 0;
 }
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 60a4601..c9cb415 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -115,7 +115,6 @@ static void test_link_get(sd_netlink *rtnl, int ifindex) {
 
         assert_se(sd_netlink_message_read_ether_addr(r, IFLA_ADDRESS, &eth_data) == 0);
 
-        assert_se(sd_netlink_flush(rtnl) >= 0);
         assert_se((m = sd_netlink_message_unref(m)) == NULL);
         assert_se((r = sd_netlink_message_unref(r)) == NULL);
 }
@@ -138,7 +137,6 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
         assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0);
         assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
 
-        assert_se(sd_netlink_flush(rtnl) >= 0);
         assert_se((m = sd_netlink_message_unref(m)) == NULL);
         assert_se((r = sd_netlink_message_unref(r)) == NULL);
 
@@ -434,7 +432,6 @@ int main(void) {
         test_link_get(rtnl, if_loopback);
         test_address_get(rtnl, if_loopback);
 
-        assert_se(sd_netlink_flush(rtnl) >= 0);
         assert_se((m = sd_netlink_message_unref(m)) == NULL);
         assert_se((r = sd_netlink_message_unref(r)) == NULL);
         assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index 3733673..7f6af54 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -61,7 +61,6 @@ int sd_netlink_get_events(sd_netlink *nl);
 int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout);
 int sd_netlink_process(sd_netlink *nl, sd_netlink_message **ret);
 int sd_netlink_wait(sd_netlink *nl, uint64_t timeout);
-int sd_netlink_flush(sd_netlink *nl);
 
 int sd_netlink_add_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
 int sd_netlink_remove_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);

commit 1c4baffc1895809bae9ac36b670af90a4cb9cd7d
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri Jun 12 16:31:33 2015 +0200

    sd-netlink: rename from sd-rtnl

diff --git a/.gitignore b/.gitignore
index ea9aacf..9d93347 100644
--- a/.gitignore
+++ b/.gitignore
@@ -244,8 +244,8 @@
 /test-replace-var
 /test-resolve
 /test-ring
-/test-rtnl
-/test-rtnl-manual
+/test-netlink
+/test-netlink-manual
 /test-sched-prio
 /test-set
 /test-sigbus
diff --git a/Makefile.am b/Makefile.am
index eaa9a85..0f779d1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -233,7 +233,7 @@ AM_CPPFLAGS = \
 	-I $(top_srcdir)/src/libsystemd/sd-bus \
 	-I $(top_srcdir)/src/libsystemd/sd-event \
 	-I $(top_srcdir)/src/libsystemd/sd-login \
-	-I $(top_srcdir)/src/libsystemd/sd-rtnl \
+	-I $(top_srcdir)/src/libsystemd/sd-netlink \
 	-I $(top_srcdir)/src/libsystemd/sd-network \
 	-I $(top_srcdir)/src/libsystemd/sd-hwdb \
 	-I $(top_srcdir)/src/libsystemd/sd-device \
@@ -1368,7 +1368,7 @@ endif
 
 if HAVE_KMOD
 manual_tests += \
-	test-rtnl-manual
+	test-netlink-manual
 endif
 
 tests += \
@@ -1873,14 +1873,14 @@ test_fw_util_LDADD = \
 	$(LIBIPTC_LIBS)
 endif
 
-test_rtnl_manual_SOURCES = \
-	src/test/test-rtnl-manual.c
+test_netlink_manual_SOURCES = \
+	src/test/test-netlink-manual.c
 
-test_rtnl_manual_CFLAGS = \
+test_netlink_manual_CFLAGS = \
 	$(AM_CFLAGS) \
 	$(KMOD_CFLAGS)
 
-test_rtnl_manual_LDADD = \
+test_netlink_manual_LDADD = \
 	libshared.la \
 	$(KMOD_LIBS)
 
@@ -2856,7 +2856,7 @@ libsystemd_internal_la_SOURCES = \
 	src/systemd/sd-bus-vtable.h \
 	src/systemd/sd-utf8.h \
 	src/systemd/sd-event.h \
-	src/systemd/sd-rtnl.h \
+	src/systemd/sd-netlink.h \
 	src/systemd/sd-resolve.h \
 	src/systemd/sd-login.h \
 	src/systemd/sd-id128.h \
@@ -2910,15 +2910,15 @@ libsystemd_internal_la_SOURCES = \
 	src/libsystemd/sd-utf8/sd-utf8.c \
 	src/libsystemd/sd-event/sd-event.c \
 	src/libsystemd/sd-event/event-util.h \
-	src/libsystemd/sd-rtnl/sd-rtnl.c \
-	src/libsystemd/sd-rtnl/rtnl-internal.h \
-	src/libsystemd/sd-rtnl/rtnl-message.c \
-	src/libsystemd/sd-rtnl/rtnl-types.h \
-	src/libsystemd/sd-rtnl/rtnl-types.c \
-	src/libsystemd/sd-rtnl/rtnl-util.h \
-	src/libsystemd/sd-rtnl/rtnl-util.c \
-	src/libsystemd/sd-rtnl/local-addresses.h \
-	src/libsystemd/sd-rtnl/local-addresses.c \
+	src/libsystemd/sd-netlink/sd-netlink.c \
+	src/libsystemd/sd-netlink/netlink-internal.h \
+	src/libsystemd/sd-netlink/netlink-message.c \
+	src/libsystemd/sd-netlink/netlink-types.h \
+	src/libsystemd/sd-netlink/netlink-types.c \
+	src/libsystemd/sd-netlink/netlink-util.h \
+	src/libsystemd/sd-netlink/netlink-util.c \
+	src/libsystemd/sd-netlink/local-addresses.h \
+	src/libsystemd/sd-netlink/local-addresses.c \
 	src/libsystemd/sd-id128/sd-id128.c \
 	src/libsystemd/sd-daemon/sd-daemon.c \
 	src/libsystemd/sd-login/sd-login.c \
@@ -3019,7 +3019,7 @@ pkginclude_HEADERS += \
 if ENABLE_KDBUS
 pkginclude_HEADERS += \
 	src/systemd/sd-utf8.h \
-	src/systemd/sd-rtnl.h \
+	src/systemd/sd-netlink.h \
 	src/systemd/sd-resolve.h \
 	src/systemd/sd-path.h
 endif
@@ -3044,7 +3044,7 @@ tests += \
 	test-bus-creds \
 	test-bus-gvariant \
 	test-event \
-	test-rtnl \
+	test-netlink \
 	test-local-addresses \
 	test-resolve
 
@@ -3175,14 +3175,14 @@ test_event_SOURCES = \
 test_event_LDADD = \
 	libshared.la
 
-test_rtnl_SOURCES = \
-	src/libsystemd/sd-rtnl/test-rtnl.c
+test_netlink_SOURCES = \
+	src/libsystemd/sd-netlink/test-netlink.c
 
-test_rtnl_LDADD = \
+test_netlink_LDADD = \
 	libshared.la
 
 test_local_addresses_SOURCES = \
-	src/libsystemd/sd-rtnl/test-local-addresses.c
+	src/libsystemd/sd-netlink/test-local-addresses.c
 
 test_local_addresses_LDADD = \
 	libshared.la
diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c
index 938f3ab..4503fc9 100644
--- a/src/core/loopback-setup.c
+++ b/src/core/loopback-setup.c
@@ -22,13 +22,13 @@
 #include <net/if.h>
 #include <stdlib.h>
 
-#include "sd-rtnl.h"
-#include "rtnl-util.h"
+#include "sd-netlink.h"
+#include "netlink-util.h"
 #include "missing.h"
 #include "loopback-setup.h"
 
-static int start_loopback(sd_rtnl *rtnl) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+static int start_loopback(sd_netlink *rtnl) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, LOOPBACK_IFINDEX);
@@ -39,15 +39,15 @@ static int start_loopback(sd_rtnl *rtnl) {
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call(rtnl, req, 0, NULL);
+        r = sd_netlink_call(rtnl, req, 0, NULL);
         if (r < 0)
                 return r;
 
         return 0;
 }
 
-static bool check_loopback(sd_rtnl *rtnl) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+static bool check_loopback(sd_netlink *rtnl) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
         unsigned flags;
         int r;
 
@@ -55,7 +55,7 @@ static bool check_loopback(sd_rtnl *rtnl) {
         if (r < 0)
                 return false;
 
-        r = sd_rtnl_call(rtnl, req, 0, &reply);
+        r = sd_netlink_call(rtnl, req, 0, &reply);
         if (r < 0)
                 return false;
 
@@ -67,10 +67,10 @@ static bool check_loopback(sd_rtnl *rtnl) {
 }
 
 int loopback_setup(void) {
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         int r;
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return r;
 
diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c
index cc51197..72878f4 100644
--- a/src/libsystemd-network/test-pppoe.c
+++ b/src/libsystemd-network/test-pppoe.c
@@ -29,7 +29,7 @@
 #include "util.h"
 #include "sd-event.h"
 #include "event-util.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "sd-pppoe.h"
 #include "process-util.h"
 
@@ -83,8 +83,8 @@ static int client_run(const char *client_name, sd_event *e) {
 }
 
 static int test_pppoe_server(sd_event *e) {
-        sd_rtnl *rtnl;
-        sd_rtnl_message *m;
+        sd_netlink *rtnl;
+        sd_netlink_message *m;
         pid_t pid;
         int r, client_ifindex, server_ifindex;
 
@@ -94,34 +94,34 @@ static int test_pppoe_server(sd_event *e) {
 
         assert_se(r >= 0);
 
-        assert_se(sd_rtnl_open(&rtnl) >= 0);
-        assert_se(sd_rtnl_attach_event(rtnl, e, 0) >= 0);
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+        assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
 
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
-        assert_se(sd_rtnl_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0);
-        assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
-        assert_se(sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0);
-        assert_se(sd_rtnl_message_open_container(m, VETH_INFO_PEER) >= 0);
-        assert_se(sd_rtnl_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0);
-        assert_se(sd_rtnl_message_close_container(m) >= 0);
-        assert_se(sd_rtnl_message_close_container(m) >= 0);
-        assert_se(sd_rtnl_message_close_container(m) >= 0);
-        assert_se(sd_rtnl_call(rtnl, m, 0, NULL) >= 0);
+        assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0);
+        assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
+        assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0);
+        assert_se(sd_netlink_message_open_container(m, VETH_INFO_PEER) >= 0);
+        assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0);
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+        assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
 
         client_ifindex = (int) if_nametoindex("pppoe-client");
         assert_se(client_ifindex > 0);
         server_ifindex = (int) if_nametoindex("pppoe-server");
         assert_se(server_ifindex > 0);
 
-        m = sd_rtnl_message_unref(m);
+        m = sd_netlink_message_unref(m);
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, client_ifindex) >= 0);
         assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
-        assert_se(sd_rtnl_call(rtnl, m, 0, NULL) >= 0);
+        assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
 
-        m = sd_rtnl_message_unref(m);
+        m = sd_netlink_message_unref(m);
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, server_ifindex) >= 0);
         assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
-        assert_se(sd_rtnl_call(rtnl, m, 0, NULL) >= 0);
+        assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
 
         pid = fork();
         assert_se(pid >= 0);
@@ -145,8 +145,8 @@ static int test_pppoe_server(sd_event *e) {
         assert_se(kill(pid, SIGTERM) >= 0);
         assert_se(wait_for_terminate(pid, NULL) >= 0);
 
-        assert_se(!sd_rtnl_message_unref(m));
-        assert_se(!sd_rtnl_unref(rtnl));
+        assert_se(!sd_netlink_message_unref(m));
+        assert_se(!sd_netlink_unref(rtnl));
 
         return EXIT_SUCCESS;
 }
diff --git a/src/libsystemd/sd-netlink/Makefile b/src/libsystemd/sd-netlink/Makefile
new file mode 120000
index 0000000..94aaae2
--- /dev/null
+++ b/src/libsystemd/sd-netlink/Makefile
@@ -0,0 +1 @@
+../../Makefile
\ No newline at end of file
diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c
new file mode 100644
index 0000000..e2f637f
--- /dev/null
+++ b/src/libsystemd/sd-netlink/local-addresses.c
@@ -0,0 +1,276 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2008-2011 Lennart Poettering
+  Copyright 2014 Tom Gundersen
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-netlink.h"
+#include "netlink-util.h"
+#include "macro.h"
+#include "local-addresses.h"
+
+static int address_compare(const void *_a, const void *_b) {
+        const struct local_address *a = _a, *b = _b;
+
+        /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
+
+        if (a->family == AF_INET && b->family == AF_INET6)
+                return -1;
+        if (a->family == AF_INET6 && b->family == AF_INET)
+                return 1;
+
+        if (a->scope < b->scope)
+                return -1;
+        if (a->scope > b->scope)
+                return 1;
+
+        if (a->metric < b->metric)
+                return -1;
+        if (a->metric > b->metric)
+                return 1;
+
+        if (a->ifindex < b->ifindex)
+                return -1;
+        if (a->ifindex > b->ifindex)
+                return 1;
+
+        return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
+}
+
+int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        _cleanup_free_ struct local_address *list = NULL;
+        size_t n_list = 0, n_allocated = 0;
+        sd_netlink_message *m;
+        int r;
+
+        assert(ret);
+
+        if (context)
+                rtnl = sd_netlink_ref(context);
+        else {
+                r = sd_netlink_open(&rtnl);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_call(rtnl, req, 0, &reply);
+        if (r < 0)
+                return r;
+
+        for (m = reply; m; m = sd_netlink_message_next(m)) {
+                struct local_address *a;
+                unsigned char flags;
+                uint16_t type;
+                int ifi, family;
+
+                r = sd_netlink_message_get_errno(m);
+                if (r < 0)
+                        return r;
+
+                r = sd_netlink_message_get_type(m, &type);
+                if (r < 0)
+                        return r;
+                if (type != RTM_NEWADDR)
+                        continue;
+
+                r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
+                if (r < 0)
+                        return r;
+                if (ifindex > 0 && ifi != ifindex)
+                        continue;
+
+                r = sd_rtnl_message_addr_get_family(m, &family);
+                if (r < 0)
+                        return r;
+                if (af != AF_UNSPEC && af != family)
+                        continue;
+
+                r = sd_rtnl_message_addr_get_flags(m, &flags);
+                if (r < 0)
+                        return r;
+                if (flags & IFA_F_DEPRECATED)
+                        continue;
+
+                if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
+                        return -ENOMEM;
+
+                a = list + n_list;
+
+                r = sd_rtnl_message_addr_get_scope(m, &a->scope);
+                if (r < 0)
+                        return r;
+
+                if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
+                        continue;
+
+                switch (family) {
+
+                case AF_INET:
+                        r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
+                        if (r < 0) {
+                                r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
+                                if (r < 0)
+                                        continue;
+                        }
+                        break;
+
+                case AF_INET6:
+                        r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
+                        if (r < 0) {
+                                r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
+                                if (r < 0)
+                                        continue;
+                        }
+                        break;
+
+                default:
+                        continue;
+                }
+
+                a->ifindex = ifi;
+                a->family = family;
+
+                n_list++;
+        };
+
+        if (n_list > 0)
+                qsort(list, n_list, sizeof(struct local_address), address_compare);
+
+        *ret = list;
+        list = NULL;
+
+        return (int) n_list;
+}
+
+int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        _cleanup_free_ struct local_address *list = NULL;
+        sd_netlink_message *m = NULL;
+        size_t n_list = 0, n_allocated = 0;
+        int r;
+
+        assert(ret);
+
+        if (context)
+                rtnl = sd_netlink_ref(context);
+        else {
+                r = sd_netlink_open(&rtnl);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_request_dump(req, true);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_call(rtnl, req, 0, &reply);
+        if (r < 0)
+                return r;
+
+        for (m = reply; m; m = sd_netlink_message_next(m)) {
+                struct local_address *a;
+                uint16_t type;
+                unsigned char dst_len, src_len;
+                uint32_t ifi;
+                int family;
+
+                r = sd_netlink_message_get_errno(m);
+                if (r < 0)
+                        return r;
+
+                r = sd_netlink_message_get_type(m, &type);
+                if (r < 0)
+                        return r;
+                if (type != RTM_NEWROUTE)
+                        continue;
+
+                /* We only care for default routes */
+                r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
+                if (r < 0)
+                        return r;
+                if (dst_len != 0)
+                        continue;
+
+                r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
+                if (r < 0)
+                        return r;
+                if (src_len != 0)
+                        continue;
+
+                r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
+                if (r < 0)
+                        return r;
+                if (ifindex > 0 && (int) ifi != ifindex)
+                        continue;
+
+                r = sd_rtnl_message_route_get_family(m, &family);
+                if (r < 0)
+                        return r;
+                if (af != AF_UNSPEC && af != family)
+                        continue;
+
+                if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
+                        return -ENOMEM;
+
+                a = list + n_list;
+
+                switch (family) {
+                case AF_INET:
+                        r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
+                        if (r < 0)
+                                continue;
+
+                        break;
+                case AF_INET6:
+                        r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
+                        if (r < 0)
+                                continue;
+
+                        break;
+                default:
+                        continue;
+                }
+
+                sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric);
+
+                a->ifindex = ifi;
+                a->family = family;
+
+                n_list++;
+        }
+
+        if (n_list > 0)
+                qsort(list, n_list, sizeof(struct local_address), address_compare);
+
+        *ret = list;
+        list = NULL;
+
+        return (int) n_list;
+}
diff --git a/src/libsystemd/sd-netlink/local-addresses.h b/src/libsystemd/sd-netlink/local-addresses.h
new file mode 100644
index 0000000..5d0f11a
--- /dev/null
+++ b/src/libsystemd/sd-netlink/local-addresses.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2008-2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+
+#include "sd-netlink.h"
+#include "in-addr-util.h"
+
+struct local_address {
+        int family, ifindex;
+        unsigned char scope;
+        uint32_t metric;
+        union in_addr_union address;
+};
+
+int local_addresses(sd_netlink *rtnl, int ifindex, int af, struct local_address **ret);
+
+int local_gateways(sd_netlink *rtnl, int ifindex, int af, struct local_address **ret);
diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
new file mode 100644
index 0000000..ff663f9
--- /dev/null
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -0,0 +1,135 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <linux/netlink.h>
+
+#include "refcnt.h"
+#include "prioq.h"
+#include "list.h"
+
+#include "sd-netlink.h"
+
+#include "netlink-types.h"
+
+#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
+
+#define RTNL_WQUEUE_MAX 1024
+#define RTNL_RQUEUE_MAX 64*1024
+
+#define RTNL_CONTAINER_DEPTH 32
+
+struct reply_callback {
+        sd_netlink_message_handler_t callback;
+        void *userdata;
+        usec_t timeout;
+        uint64_t serial;
+        unsigned prioq_idx;
+};
+
+struct match_callback {
+        sd_netlink_message_handler_t callback;
+        uint16_t type;
+        void *userdata;
+
+        LIST_FIELDS(struct match_callback, match_callbacks);
+};
+
+struct sd_netlink {
+        RefCount n_ref;
+
+        int fd;
+
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sockaddr;
+
+        sd_netlink_message **rqueue;
+        unsigned rqueue_size;
+        size_t rqueue_allocated;
+
+        sd_netlink_message **rqueue_partial;
+        unsigned rqueue_partial_size;
+        size_t rqueue_partial_allocated;
+
+        sd_netlink_message **wqueue;
+        unsigned wqueue_size;
+        size_t wqueue_allocated;
+
+        struct nlmsghdr *rbuffer;
+        size_t rbuffer_allocated;
+
+        bool processing:1;
+
+        uint32_t serial;
+
+        struct Prioq *reply_callbacks_prioq;
+        Hashmap *reply_callbacks;
+
+        LIST_HEAD(struct match_callback, match_callbacks);
+
+        pid_t original_pid;
+
+        sd_event_source *io_event_source;
+        sd_event_source *time_event_source;
+        sd_event_source *exit_event_source;
+        sd_event *event;
+};
+
+struct sd_netlink_message {
+        RefCount n_ref;
+
+        sd_netlink *rtnl;
+
+        struct nlmsghdr *hdr;
+        const struct NLTypeSystem *(container_type_system[RTNL_CONTAINER_DEPTH]); /* the type of the container and all its parents */
+        size_t container_offsets[RTNL_CONTAINER_DEPTH]; /* offset from hdr to each container's start */
+        unsigned n_containers; /* number of containers */
+        size_t next_rta_offset; /* offset from hdr to next rta */
+        size_t *rta_offset_tb[RTNL_CONTAINER_DEPTH];
+        unsigned short rta_tb_size[RTNL_CONTAINER_DEPTH];
+        bool sealed:1;
+        bool broadcast:1;
+
+        sd_netlink_message *next; /* next in a chain of multi-part messages */
+};
+
+int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type);
+
+int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
+int socket_read_message(sd_netlink *nl);
+
+int rtnl_rqueue_make_room(sd_netlink *rtnl);
+int rtnl_rqueue_partial_make_room(sd_netlink *rtnl);
+
+int rtnl_message_read_internal(sd_netlink_message *m, unsigned short type, void **data);
+int rtnl_message_parse(sd_netlink_message *m,
+                       size_t **rta_offset_tb,
+                       unsigned short *rta_tb_size,
+                       int max,
+                       struct rtattr *rta,
+                       unsigned int rt_len);
+
+/* Make sure callbacks don't destroy the rtnl connection */
+#define RTNL_DONT_DESTROY(rtnl) \
+        _cleanup_netlink_unref_ _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl)
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
new file mode 100644
index 0000000..9c280b1
--- /dev/null
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -0,0 +1,1699 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "socket-util.h"
+#include "formats-util.h"
+#include "refcnt.h"
+#include "missing.h"
+
+#include "sd-netlink.h"
+#include "netlink-util.h"
+#include "netlink-internal.h"
+#include "netlink-types.h"
+
+#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
+#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
+
+#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
+
+static int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
+        sd_netlink_message *m;
+
+        assert_return(ret, -EINVAL);
+
+        /* Note that 'rtnl' is currently unused, if we start using it internally
+           we must take care to avoid problems due to mutual references between
+           buses and their queued messages. See sd-bus.
+         */
+
+        m = new0(sd_netlink_message, 1);
+        if (!m)
+                return -ENOMEM;
+
+        m->n_ref = REFCNT_INIT;
+
+        m->sealed = false;
+
+        *ret = m;
+
+        return 0;
+}
+
+int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+        const NLType *nl_type;
+        size_t size;
+        int r;
+
+        r = type_system_get_type(NULL, &nl_type, type);
+        if (r < 0)
+                return r;
+
+        r = message_new_empty(rtnl, &m);
+        if (r < 0)
+                return r;
+
+        size = NLMSG_SPACE(nl_type->size);
+
+        assert(size >= sizeof(struct nlmsghdr));
+        m->hdr = malloc0(size);
+        if (!m->hdr)
+                return -ENOMEM;
+
+        m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+        m->container_type_system[0] = nl_type->type_system;
+        m->hdr->nlmsg_len = size;
+        m->hdr->nlmsg_type = type;
+
+        *ret = m;
+        m = NULL;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
+            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
+                return -ERANGE;
+
+        rtm->rtm_dst_len = prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
+            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
+                return -ERANGE;
+
+        rtm->rtm_src_len = prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        rtm->rtm_scope = scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(family, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *family = rtm->rtm_family;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(dst_len, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *dst_len = rtm->rtm_dst_len;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(src_len, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *src_len = rtm->rtm_src_len;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
+                              uint16_t nlmsg_type, int rtm_family,
+                              unsigned char rtm_protocol) {
+        struct rtmsg *rtm;
+        int r;
+
+        assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
+        assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
+                      rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_NEWROUTE)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
+
+        rtm = NLMSG_DATA((*ret)->hdr);
+
+        rtm->rtm_family = rtm_family;
+        rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+        rtm->rtm_type = RTN_UNICAST;
+        rtm->rtm_table = RT_TABLE_MAIN;
+        rtm->rtm_protocol = rtm_protocol;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        ndm->ndm_flags |= flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        ndm->ndm_state |= state;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        *flags = ndm->ndm_flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+        *state = ndm->ndm_state;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(family, -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+
+        *family = ndm->ndm_family;
+
+        return 0;
+}
+
+int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index) {
+        struct ndmsg *ndm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(index, -EINVAL);
+
+        ndm = NLMSG_DATA(m->hdr);
+
+        *index = ndm->ndm_ifindex;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_neigh(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
+        struct ndmsg *ndm;
+        int r;
+
+        assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
+        assert_return(ndm_family == AF_INET  ||
+                      ndm_family == AF_INET6 ||
+                      ndm_family == PF_BRIDGE, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_NEWNEIGH)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
+
+        ndm = NLMSG_DATA((*ret)->hdr);
+
+        ndm->ndm_family = ndm_family;
+        ndm->ndm_ifindex = index;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(change, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_flags = flags;
+        ifi->ifi_change = change;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_type = type;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_family = family;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
+                             uint16_t nlmsg_type, int index) {
+        struct ifinfomsg *ifi;
+        int r;
+
+        assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
+        assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_NEWLINK)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+
+        ifi = NLMSG_DATA((*ret)->hdr);
+
+        ifi->ifi_family = AF_UNSPEC;
+        ifi->ifi_index = index;
+
+        return 0;
+}
+
+int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(m->hdr->nlmsg_type == RTM_GETLINK  ||
+                      m->hdr->nlmsg_type == RTM_GETADDR  ||
+                      m->hdr->nlmsg_type == RTM_GETROUTE ||
+                      m->hdr->nlmsg_type == RTM_GETNEIGH,
+                      -EINVAL);
+
+        if (dump)
+                m->hdr->nlmsg_flags |= NLM_F_DUMP;
+        else
+                m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
+            (ifa->ifa_family == AF_INET6 && prefixlen > 128))
+                return -ERANGE;
+
+        ifa->ifa_prefixlen = prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        ifa->ifa_flags = flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        ifa->ifa_scope = scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(family, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *family = ifa->ifa_family;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(prefixlen, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *prefixlen = ifa->ifa_prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(scope, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *scope = ifa->ifa_scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(flags, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *flags = ifa->ifa_flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex) {
+        struct ifaddrmsg *ifa;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(ifindex, -EINVAL);
+
+        ifa = NLMSG_DATA(m->hdr);
+
+        *ifindex = ifa->ifa_index;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_addr(sd_netlink *rtnl, sd_netlink_message **ret,
+                             uint16_t nlmsg_type, int index,
+                             int family) {
+        struct ifaddrmsg *ifa;
+        int r;
+
+        assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
+        assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
+                      index > 0, -EINVAL);
+        assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
+                      family == AF_INET || family == AF_INET6, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(rtnl, ret, nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (nlmsg_type == RTM_GETADDR)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
+
+        ifa = NLMSG_DATA((*ret)->hdr);
+
+        ifa->ifa_index = index;
+        ifa->ifa_family = family;
+        if (family == AF_INET)
+                ifa->ifa_prefixlen = 32;
+        else if (family == AF_INET6)
+                ifa->ifa_prefixlen = 128;
+
+        return 0;
+}
+
+int sd_rtnl_message_new_addr_update(sd_netlink *rtnl, sd_netlink_message **ret,
+                             int index, int family) {
+        int r;
+
+        r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
+
+        return 0;
+}
+
+sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
+        if (m)
+                assert_se(REFCNT_INC(m->n_ref) >= 2);
+
+        return m;
+}
+
+sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
+        if (m && REFCNT_DEC(m->n_ref) == 0) {
+                unsigned i;
+
+                free(m->hdr);
+
+                for (i = 0; i <= m->n_containers; i++)
+                        free(m->rta_offset_tb[i]);
+
+                sd_netlink_message_unref(m->next);
+
+                free(m);
+        }
+
+        return NULL;
+}
+
+int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
+        assert_return(m, -EINVAL);
+        assert_return(type, -EINVAL);
+
+        *type = m->hdr->nlmsg_type;
+
+        return 0;
+}
+
+int sd_netlink_message_get_family(sd_netlink_message *m, int *family) {
+        assert_return(m, -EINVAL);
+        assert_return(family, -EINVAL);
+
+        assert(m->hdr);
+
+        if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
+                struct ifinfomsg *ifi;
+
+                ifi = NLMSG_DATA(m->hdr);
+
+                *family = ifi->ifi_family;
+
+                return 0;
+        } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
+                struct rtmsg *rtm;
+
+                rtm = NLMSG_DATA(m->hdr);
+
+                *family = rtm->rtm_family;
+
+                return 0;
+        } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
+                struct ndmsg *ndm;
+
+                ndm = NLMSG_DATA(m->hdr);
+
+                *family = ndm->ndm_family;
+
+                return 0;
+        } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
+                struct ifaddrmsg *ifa;
+
+                ifa = NLMSG_DATA(m->hdr);
+
+                *family = ifa->ifa_family;
+
+                return 0;
+        }
+
+        return -EOPNOTSUPP;
+}
+
+int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
+        assert_return(m, -EINVAL);
+
+        return m->broadcast;
+}
+
+int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(ifindex, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *ifindex = ifi->ifi_index;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(flags, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *flags = ifi->ifi_flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(type, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *type = ifi->ifi_type;
+
+        return 0;
+}
+
+/* If successful the updated message will be correctly aligned, if
+   unsuccessful the old message is untouched. */
+static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
+        uint32_t rta_length;
+        size_t message_length, padding_length;
+        struct nlmsghdr *new_hdr;
+        struct rtattr *rta;
+        char *padding;
+        unsigned i;
+        int offset;
+
+        assert(m);
+        assert(m->hdr);
+        assert(!m->sealed);
+        assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
+        assert(!data || data_length);
+
+        /* get offset of the new attribute */
+        offset = m->hdr->nlmsg_len;
+
+        /* get the size of the new rta attribute (with padding at the end) */
+        rta_length = RTA_LENGTH(data_length);
+
+        /* get the new message size (with padding at the end) */
+        message_length = offset + RTA_ALIGN(rta_length);
+
+        /* realloc to fit the new attribute */
+        new_hdr = realloc(m->hdr, message_length);
+        if (!new_hdr)
+                return -ENOMEM;
+        m->hdr = new_hdr;
+
+        /* get pointer to the attribute we are about to add */
+        rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
+
+        /* if we are inside containers, extend them */
+        for (i = 0; i < m->n_containers; i++)
+                GET_CONTAINER(m, i)->rta_len += message_length - offset;
+
+        /* fill in the attribute */
+        rta->rta_type = type;
+        rta->rta_len = rta_length;
+        if (data)
+                /* we don't deal with the case where the user lies about the type
+                 * and gives us too little data (so don't do that)
+                 */
+                padding = mempcpy(RTA_DATA(rta), data, data_length);
+        else {
+                /* if no data was passed, make sure we still initialize the padding
+                   note that we can have data_length > 0 (used by some containers) */
+                padding = RTA_DATA(rta);
+        }
+
+        /* make sure also the padding at the end of the message is initialized */
+        padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
+        memzero(padding, padding_length);
+
+        /* update message size */
+        m->hdr->nlmsg_len = message_length;
+
+        return offset;
+}
+
+static int message_attribute_has_type(sd_netlink_message *m, uint16_t attribute_type, uint16_t data_type) {
+        const NLType *type;
+        int r;
+
+        r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
+        if (r < 0)
+                return r;
+
+        if (type->type != data_type)
+                return -EINVAL;
+
+        return type->size;
+}
+
+int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
+        size_t length, size;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(data, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_STRING);
+        if (r < 0)
+                return r;
+        else
+                size = (size_t)r;
+
+        if (size) {
+                length = strnlen(data, size+1);
+                if (length > size)
+                        return -EINVAL;
+        } else
+                length = strlen(data);
+
+        r = add_rtattr(m, type, data, length + 1);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+
+        r = message_attribute_has_type(m, type, NLA_U8);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, &data, sizeof(uint8_t));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+
+int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+
+        r = message_attribute_has_type(m, type, NLA_U16);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, &data, sizeof(uint16_t));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+
+        r = message_attribute_has_type(m, type, NLA_U32);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, &data, sizeof(uint32_t));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(data, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, data, sizeof(struct in_addr));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(data, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, data, sizeof(struct in6_addr));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(data, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, data, ETH_ALEN);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(info, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
+        if (r < 0)
+                return r;
+
+        r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
+        size_t size;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
+
+        r = message_attribute_has_type(m, type, NLA_NESTED);
+        if (r < 0) {
+                const NLTypeSystemUnion *type_system_union;
+                int family;
+
+                r = message_attribute_has_type(m, type, NLA_UNION);
+                if (r < 0)
+                        return r;
+                size = (size_t) r;
+
+                r = sd_netlink_message_get_family(m, &family);
+                if (r < 0)
+                        return r;
+
+                r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
+                if (r < 0)
+                        return r;
+
+                r = type_system_union_protocol_get_type_system(type_system_union,
+                                                               &m->container_type_system[m->n_containers + 1],
+                                                               family);
+                if (r < 0)
+                        return r;
+        } else {
+                size = (size_t)r;
+
+                r = type_system_get_type_system(m->container_type_system[m->n_containers],
+                                                &m->container_type_system[m->n_containers + 1],
+                                                type);
+                if (r < 0)
+                        return r;
+        }
+
+        r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
+        if (r < 0)
+                return r;
+
+        m->container_offsets[m->n_containers ++] = r;
+
+        return 0;
+}
+
+int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
+        const NLTypeSystemUnion *type_system_union;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+
+        r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
+        if (r < 0)
+                return r;
+
+        r = type_system_union_get_type_system(type_system_union,
+                                              &m->container_type_system[m->n_containers + 1],
+                                              key);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_append_string(m, type_system_union->match, key);
+        if (r < 0)
+                return r;
+
+        /* do we evere need non-null size */
+        r = add_rtattr(m, type, NULL, 0);
+        if (r < 0)
+                return r;
+
+        m->container_offsets[m->n_containers ++] = r;
+
+        return 0;
+}
+
+
+int sd_netlink_message_close_container(sd_netlink_message *m) {
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(m->n_containers > 0, -EINVAL);
+
+        m->container_type_system[m->n_containers] = NULL;
+        m->n_containers --;
+
+        return 0;
+}
+
+int rtnl_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) {
+        struct rtattr *rta;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(data, -EINVAL);
+        assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
+        assert(m->rta_offset_tb[m->n_containers]);
+        assert(type < m->rta_tb_size[m->n_containers]);
+
+        if(!m->rta_offset_tb[m->n_containers][type])
+                return -ENODATA;
+
+        rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
+
+        *data = RTA_DATA(rta);
+
+        return RTA_PAYLOAD(rta);
+}
+
+int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_STRING);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if (strnlen(attr_data, r) >= (size_t) r)
+                return -EIO;
+
+        if (data)
+                *data = (const char *) attr_data;
+
+        return 0;
+}
+
+int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_U8);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t) r < sizeof(uint8_t))
+                return -EIO;
+
+        if (data)
+                *data = *(uint8_t *) attr_data;
+
+        return 0;
+}
+
+int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_U16);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t) r < sizeof(uint16_t))
+                return -EIO;
+
+        if (data)
+                *data = *(uint16_t *) attr_data;
+
+        return 0;
+}
+
+int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_U32);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t)r < sizeof(uint32_t))
+                return -EIO;
+
+        if (data)
+                *data = *(uint32_t *) attr_data;
+
+        return 0;
+}
+
+int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t)r < sizeof(struct ether_addr))
+                return -EIO;
+
+        if (data)
+                memcpy(data, attr_data, sizeof(struct ether_addr));
+
+        return 0;
+}
+
+int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t)r < sizeof(struct ifa_cacheinfo))
+                return -EIO;
+
+        if (info)
+                memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
+
+        return 0;
+}
+
+int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t)r < sizeof(struct in_addr))
+                return -EIO;
+
+        if (data)
+                memcpy(data, attr_data, sizeof(struct in_addr));
+
+        return 0;
+}
+
+int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
+        int r;
+        void *attr_data;
+
+        assert_return(m, -EINVAL);
+
+        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
+        if (r < 0)
+                return r;
+
+        r = rtnl_message_read_internal(m, type, &attr_data);
+        if (r < 0)
+                return r;
+        else if ((size_t)r < sizeof(struct in6_addr))
+                return -EIO;
+
+        if (data)
+                memcpy(data, attr_data, sizeof(struct in6_addr));
+
+        return 0;
+}
+
+int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type) {
+        const NLType *nl_type;
+        const NLTypeSystem *type_system;
+        void *container;
+        size_t size;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
+
+        r = type_system_get_type(m->container_type_system[m->n_containers],
+                                 &nl_type,
+                                 type);
+        if (r < 0)
+                return r;
+
+        if (nl_type->type == NLA_NESTED) {
+                r = type_system_get_type_system(m->container_type_system[m->n_containers],
+                                                &type_system,
+                                                type);
+                if (r < 0)
+                        return r;
+        } else if (nl_type->type == NLA_UNION) {
+                const NLTypeSystemUnion *type_system_union;
+
+                r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
+                                                      &type_system_union,
+                                                      type);
+                if (r < 0)
+                        return r;
+
+                switch (type_system_union->match_type) {
+                case NL_MATCH_SIBLING:
+                {
+                        const char *key;
+
+                        r = sd_netlink_message_read_string(m, type_system_union->match, &key);
+                        if (r < 0)
+                                return r;
+
+                        r = type_system_union_get_type_system(type_system_union,
+                                                              &type_system,
+                                                              key);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                }
+                case NL_MATCH_PROTOCOL:
+                {
+                        int family;
+
+                        r = sd_netlink_message_get_family(m, &family);
+                        if (r < 0)
+                                return r;
+
+                        r = type_system_union_protocol_get_type_system(type_system_union,
+                                                                       &type_system,
+                                                                       family);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                }
+                default:
+                        assert_not_reached("sd-netlink: invalid type system union type");
+                }
+        } else
+                return -EINVAL;
+
+        r = rtnl_message_read_internal(m, type, &container);
+        if (r < 0)
+                return r;
+        else
+                size = (size_t)r;
+
+        m->n_containers ++;
+
+        r = rtnl_message_parse(m,
+                               &m->rta_offset_tb[m->n_containers],
+                               &m->rta_tb_size[m->n_containers],
+                               type_system->max,
+                               container,
+                               size);
+        if (r < 0) {
+                m->n_containers --;
+                return r;
+        }
+
+        m->container_type_system[m->n_containers] = type_system;
+
+        return 0;
+}
+
+int sd_netlink_message_exit_container(sd_netlink_message *m) {
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EINVAL);
+        assert_return(m->n_containers > 0, -EINVAL);
+
+        free(m->rta_offset_tb[m->n_containers]);
+        m->rta_offset_tb[m->n_containers] = NULL;
+        m->container_type_system[m->n_containers] = NULL;
+
+        m->n_containers --;
+
+        return 0;
+}
+
+uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
+        assert(m);
+        assert(m->hdr);
+
+        return m->hdr->nlmsg_seq;
+}
+
+int sd_netlink_message_is_error(sd_netlink_message *m) {
+        assert_return(m, 0);
+        assert_return(m->hdr, 0);
+
+        return m->hdr->nlmsg_type == NLMSG_ERROR;
+}
+
+int sd_netlink_message_get_errno(sd_netlink_message *m) {
+        struct nlmsgerr *err;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+
+        if (!sd_netlink_message_is_error(m))
+                return 0;
+
+        err = NLMSG_DATA(m->hdr);
+
+        return err->error;
+}
+
+int rtnl_message_parse(sd_netlink_message *m,
+                       size_t **rta_offset_tb,
+                       unsigned short *rta_tb_size,
+                       int max,
+                       struct rtattr *rta,
+                       unsigned int rt_len) {
+        unsigned short type;
+        size_t *tb;
+
+        tb = new0(size_t, max + 1);
+        if(!tb)
+                return -ENOMEM;
+
+        *rta_tb_size = max + 1;
+
+        for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
+                type = RTA_TYPE(rta);
+
+                /* if the kernel is newer than the headers we used
+                   when building, we ignore out-of-range attributes
+                 */
+                if (type > max)
+                        continue;
+
+                if (tb[type])
+                        log_debug("rtnl: message parse - overwriting repeated attribute");
+
+                tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
+        }
+
+        *rta_offset_tb = tb;
+
+        return 0;
+}
+
+/* returns the number of bytes sent, or a negative error code */
+int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } addr = {
+                .nl.nl_family = AF_NETLINK,
+        };
+        ssize_t k;
+
+        assert(nl);
+        assert(m);
+        assert(m->hdr);
+
+        k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
+                        0, &addr.sa, sizeof(addr));
+        if (k < 0)
+                return (errno == EAGAIN) ? 0 : -errno;
+
+        return k;
+}
+
+static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
+        union sockaddr_union sender;
+        uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
+        struct msghdr msg = {
+                .msg_iov = iov,
+                .msg_iovlen = 1,
+                .msg_name = &sender,
+                .msg_namelen = sizeof(sender),
+                .msg_control = cmsg_buffer,
+                .msg_controllen = sizeof(cmsg_buffer),
+        };
+        struct cmsghdr *cmsg;
+        uint32_t group = 0;
+        int r;
+
+        assert(fd >= 0);
+        assert(iov);
+
+        r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
+        if (r < 0) {
+                /* no data */
+                if (errno == ENOBUFS)
+                        log_debug("rtnl: kernel receive buffer overrun");
+                else if (errno == EAGAIN)
+                        log_debug("rtnl: no data in socket");
+
+                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
+        }
+
+        if (sender.nl.nl_pid != 0) {
+                /* not from the kernel, ignore */
+                log_debug("rtnl: ignoring message from portid %"PRIu32, sender.nl.nl_pid);
+
+                if (peek) {
+                        /* drop the message */
+                        r = recvmsg(fd, &msg, 0);
+                        if (r < 0)
+                                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
+                }
+
+                return 0;
+        }
+
+        CMSG_FOREACH(cmsg, &msg) {
+                if (cmsg->cmsg_level == SOL_NETLINK &&
+                    cmsg->cmsg_type == NETLINK_PKTINFO &&
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
+                        struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
+
+                        /* multi-cast group */
+                        group = pktinfo->group;
+                }
+        }
+
+        if (_group)
+                *_group = group;
+
+        return r;
+}
+
+/* On success, the number of bytes received is returned and *ret points to the received message
+ * which has a valid header and the correct size.
+ * If nothing useful was received 0 is returned.
+ * On failure, a negative error code is returned.
+ */
+int socket_read_message(sd_netlink *rtnl) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *first = NULL;
+        struct iovec iov = {};
+        uint32_t group = 0;
+        bool multi_part = false, done = false;
+        struct nlmsghdr *new_msg;
+        size_t len;
+        int r;
+        unsigned i = 0;
+
+        assert(rtnl);
+        assert(rtnl->rbuffer);
+        assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
+
+        /* read nothing, just get the pending message size */
+        r = socket_recv_message(rtnl->fd, &iov, NULL, true);
+        if (r <= 0)
+                return r;
+        else
+                len = (size_t)r;
+
+        /* make room for the pending message */
+        if (!greedy_realloc((void **)&rtnl->rbuffer,
+                            &rtnl->rbuffer_allocated,
+                            len, sizeof(uint8_t)))
+                return -ENOMEM;
+
+        iov.iov_base = rtnl->rbuffer;
+        iov.iov_len = rtnl->rbuffer_allocated;
+
+        /* read the pending message */
+        r = socket_recv_message(rtnl->fd, &iov, &group, false);
+        if (r <= 0)
+                return r;
+        else
+                len = (size_t)r;
+
+        if (len > rtnl->rbuffer_allocated)
+                /* message did not fit in read buffer */
+                return -EIO;
+
+        if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
+                multi_part = true;
+
+                for (i = 0; i < rtnl->rqueue_partial_size; i++) {
+                        if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
+                            rtnl->rbuffer->nlmsg_seq) {
+                                first = rtnl->rqueue_partial[i];
+                                break;
+                        }
+                }
+        }
+
+        for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
+                _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+                const NLType *nl_type;
+
+                if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
+                        /* not broadcast and not for us */
+                        continue;
+
+                if (new_msg->nlmsg_type == NLMSG_NOOP)
+                        /* silently drop noop messages */
+                        continue;
+
+                if (new_msg->nlmsg_type == NLMSG_DONE) {
+                        /* finished reading multi-part message */
+                        done = true;
+
+                        /* if first is not defined, put NLMSG_DONE into the receive queue. */
+                        if (first)
+                                continue;
+                }
+
+                /* check that we support this message type */
+                r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
+                if (r < 0) {
+                        if (r == -EOPNOTSUPP)
+                                log_debug("sd-netlink: ignored message with unknown type: %i",
+                                          new_msg->nlmsg_type);
+
+                        continue;
+                }
+
+                /* check that the size matches the message type */
+                if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
+                        log_debug("sd-netlink: message larger than expected, dropping");
+                        continue;
+                }
+
+                r = message_new_empty(rtnl, &m);
+                if (r < 0)
+                        return r;
+
+                m->broadcast = !!group;
+
+                m->hdr = memdup(new_msg, new_msg->nlmsg_len);
+                if (!m->hdr)
+                        return -ENOMEM;
+
+                /* seal and parse the top-level message */
+                r = sd_netlink_message_rewind(m);
+                if (r < 0)
+                        return r;
+
+                /* push the message onto the multi-part message stack */
+                if (first)
+                        m->next = first;
+                first = m;
+                m = NULL;
+        }
+
+        if (len)
+                log_debug("sd-netlink: discarding %zu bytes of incoming message", len);
+
+        if (!first)
+                return 0;
+
+        if (!multi_part || done) {
+                /* we got a complete message, push it on the read queue */
+                r = rtnl_rqueue_make_room(rtnl);
+                if (r < 0)
+                        return r;
+
+                rtnl->rqueue[rtnl->rqueue_size ++] = first;
+                first = NULL;
+
+                if (multi_part && (i < rtnl->rqueue_partial_size)) {
+                        /* remove the message form the partial read queue */
+                        memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
+                                sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1));
+                        rtnl->rqueue_partial_size --;
+                }
+
+                return 1;
+        } else {
+                /* we only got a partial multi-part message, push it on the
+                   partial read queue */
+                if (i < rtnl->rqueue_partial_size) {
+                        rtnl->rqueue_partial[i] = first;
+                } else {
+                        r = rtnl_rqueue_partial_make_room(rtnl);
+                        if (r < 0)
+                                return r;
+
+                        rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
+                }
+                first = NULL;
+
+                return 0;
+        }
+}
+
+int sd_netlink_message_rewind(sd_netlink_message *m) {
+        const NLType *type;
+        unsigned i;
+        int r;
+
+        assert_return(m, -EINVAL);
+
+        /* don't allow appending to message once parsed */
+        if (!m->sealed)
+                rtnl_message_seal(m);
+
+        for (i = 1; i <= m->n_containers; i++) {
+                free(m->rta_offset_tb[i]);
+                m->rta_offset_tb[i] = NULL;
+                m->rta_tb_size[i] = 0;
+                m->container_type_system[i] = NULL;
+        }
+
+        m->n_containers = 0;
+
+        if (m->rta_offset_tb[0]) {
+                /* top-level attributes have already been parsed */
+                return 0;
+        }
+
+        assert(m->hdr);
+
+        r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
+        if (r < 0)
+                return r;
+
+        if (type->type == NLA_NESTED) {
+                const NLTypeSystem *type_system = type->type_system;
+
+                assert(type_system);
+
+                m->container_type_system[0] = type_system;
+
+                r = rtnl_message_parse(m,
+                                       &m->rta_offset_tb[m->n_containers],
+                                       &m->rta_tb_size[m->n_containers],
+                                       type_system->max,
+                                       (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
+                                                        NLMSG_ALIGN(type->size)),
+                                       NLMSG_PAYLOAD(m->hdr, type->size));
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+void rtnl_message_seal(sd_netlink_message *m) {
+        assert(m);
+        assert(!m->sealed);
+
+        m->sealed = true;
+}
+
+sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
+        assert_return(m, NULL);
+
+        return m->next;
+}
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
new file mode 100644
index 0000000..2730337
--- /dev/null
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -0,0 +1,561 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdint.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/in6.h>
+#include <linux/veth.h>
+#include <linux/if_bridge.h>
+#include <linux/if_addr.h>
+#include <linux/if.h>
+
+#include <linux/ip.h>
+#include <linux/if_link.h>
+#include <linux/if_tunnel.h>
+
+#include "macro.h"
+#include "util.h"
+
+#include "netlink-types.h"
+#include "missing.h"
+
+static const NLTypeSystem rtnl_link_type_system;
+
+static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
+        [VETH_INFO_PEER]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
+};
+
+static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
+        [IFLA_IPVLAN_MODE]  = { .type = NLA_U16 },
+};
+
+static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
+        [IFLA_MACVLAN_MODE]  = { .type = NLA_U32 },
+        [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
+};
+
+static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
+        [IFLA_BRIDGE_FLAGS]     = { .type = NLA_U16 },
+        [IFLA_BRIDGE_MODE]      = { .type = NLA_U16 },
+/*
+        [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
+                                    .len = sizeof(struct bridge_vlan_info), },
+*/
+};
+
+static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
+        [IFLA_VLAN_ID]          = { .type = NLA_U16 },
+/*
+        [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
+        [IFLA_VLAN_EGRESS_QOS]  = { .type = NLA_NESTED },
+        [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
+*/
+        [IFLA_VLAN_PROTOCOL]    = { .type = NLA_U16 },
+};
+
+static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
+        [IFLA_VXLAN_ID] = { .type = NLA_U32 },
+        [IFLA_VXLAN_GROUP] = {.type = NLA_IN_ADDR },
+        [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
+        [IFLA_VXLAN_LOCAL] = { .type = NLA_U32},
+        [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
+        [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
+        [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
+        [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
+        [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
+        [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_U32},
+        [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
+        [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
+        [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
+        [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
+};
+
+static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
+        [BOND_ARP_TARGETS_0]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_1]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_2]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_3]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_4]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_5]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_6]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_7]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_8]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_9]        = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_10]       = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_11]       = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_12]       = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_13]       = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_14]       = { .type = NLA_U32 },
+        [BOND_ARP_TARGETS_MAX]      = { .type = NLA_U32 },
+};
+
+static const NLTypeSystem rtnl_bond_arp_type_system = {
+        .max = ELEMENTSOF(rtnl_bond_arp_target_types) - 1,
+        .types = rtnl_bond_arp_target_types,
+};
+
+static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
+        [IFLA_BOND_MODE]                = { .type = NLA_U8 },
+        [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NLA_U32 },
+        [IFLA_BOND_MIIMON]              = { .type = NLA_U32 },
+        [IFLA_BOND_UPDELAY]             = { .type = NLA_U32 },
+        [IFLA_BOND_DOWNDELAY]           = { .type = NLA_U32 },
+        [IFLA_BOND_USE_CARRIER]         = { .type = NLA_U8 },
+        [IFLA_BOND_ARP_INTERVAL]        = { .type = NLA_U32 },
+        [IFLA_BOND_ARP_IP_TARGET]       = { .type = NLA_NESTED, .type_system = &rtnl_bond_arp_type_system },
+        [IFLA_BOND_ARP_VALIDATE]        = { .type = NLA_U32 },
+        [IFLA_BOND_ARP_ALL_TARGETS]     = { .type = NLA_U32 },
+        [IFLA_BOND_PRIMARY]             = { .type = NLA_U32 },
+        [IFLA_BOND_PRIMARY_RESELECT]    = { .type = NLA_U8 },
+        [IFLA_BOND_FAIL_OVER_MAC]       = { .type = NLA_U8 },
+        [IFLA_BOND_XMIT_HASH_POLICY]    = { .type = NLA_U8 },
+        [IFLA_BOND_RESEND_IGMP]         = { .type = NLA_U32 },
+        [IFLA_BOND_NUM_PEER_NOTIF]      = { .type = NLA_U8 },
+        [IFLA_BOND_ALL_SLAVES_ACTIVE]   = { .type = NLA_U8 },
+        [IFLA_BOND_MIN_LINKS]           = { .type = NLA_U32 },
+        [IFLA_BOND_LP_INTERVAL]         = { .type = NLA_U32 },
+        [IFLA_BOND_PACKETS_PER_SLAVE]   = { .type = NLA_U32 },
+        [IFLA_BOND_AD_LACP_RATE]        = { .type = NLA_U8 },
+        [IFLA_BOND_AD_SELECT]           = { .type = NLA_U8 },
+        [IFLA_BOND_AD_INFO]             = { .type = NLA_NESTED },
+};
+
+static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
+        [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
+        [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
+        [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
+        [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
+        [IFLA_IPTUN_TOS]                 = { .type = NLA_U8 },
+        [IFLA_IPTUN_PMTUDISC]            = { .type = NLA_U8 },
+        [IFLA_IPTUN_FLAGS]               = { .type = NLA_U16 },
+        [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
+        [IFLA_IPTUN_6RD_PREFIX]          = { .type = NLA_IN_ADDR },
+        [IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NLA_U32 },
+        [IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NLA_U16 },
+        [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
+};
+
+static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
+        [IFLA_GRE_LINK]     = { .type = NLA_U32 },
+        [IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
+        [IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
+        [IFLA_GRE_IKEY]     = { .type = NLA_U32 },
+        [IFLA_GRE_OKEY]     = { .type = NLA_U32 },
+        [IFLA_GRE_LOCAL]    = { .type = NLA_IN_ADDR },
+        [IFLA_GRE_REMOTE]   = { .type = NLA_IN_ADDR },
+        [IFLA_GRE_TTL]      = { .type = NLA_U8 },
+        [IFLA_GRE_TOS]      = { .type = NLA_U8 },
+        [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
+};
+
+static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
+        [IFLA_VTI_LINK]         = { .type = NLA_U32 },
+        [IFLA_VTI_IKEY]         = { .type = NLA_U32 },
+        [IFLA_VTI_OKEY]         = { .type = NLA_U32 },
+        [IFLA_VTI_LOCAL]        = { .type = NLA_IN_ADDR  },
+        [IFLA_VTI_REMOTE]       = { .type = NLA_IN_ADDR  },
+};
+
+static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
+        [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
+        [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
+        [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
+        [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
+        [IFLA_IPTUN_FLAGS]               = { .type = NLA_U32 },
+        [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
+        [IFLA_IPTUN_ENCAP_LIMIT]         = { .type = NLA_U8 },
+        [IFLA_IPTUN_FLOWINFO]            = { .type = NLA_U32},
+};
+
+/* these strings must match the .kind entries in the kernel */
+static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
+        [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
+        [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
+        [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
+        [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
+        [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
+        [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
+        [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
+        [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
+        [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
+        [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
+        [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
+        [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = "ip6gre",
+        [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap",
+        [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
+        [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
+        [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
+        [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
+
+static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
+        [NL_UNION_LINK_INFO_DATA_BOND] =        { .max = ELEMENTSOF(rtnl_link_info_data_bond_types) - 1,
+                                                  .types = rtnl_link_info_data_bond_types },
+        [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .max = ELEMENTSOF(rtnl_link_info_data_bridge_types) - 1,
+                                                  .types = rtnl_link_info_data_bridge_types },
+        [NL_UNION_LINK_INFO_DATA_VLAN] =        { .max = ELEMENTSOF(rtnl_link_info_data_vlan_types) - 1,
+                                                  .types = rtnl_link_info_data_vlan_types },
+        [NL_UNION_LINK_INFO_DATA_VETH] =        { .max = ELEMENTSOF(rtnl_link_info_data_veth_types) - 1,
+                                                  .types = rtnl_link_info_data_veth_types },
+        [NL_UNION_LINK_INFO_DATA_MACVLAN] =     { .max = ELEMENTSOF(rtnl_link_info_data_macvlan_types) - 1,
+                                                  .types = rtnl_link_info_data_macvlan_types },
+        [NL_UNION_LINK_INFO_DATA_IPVLAN] =      { .max = ELEMENTSOF(rtnl_link_info_data_ipvlan_types) - 1,
+                                                  .types = rtnl_link_info_data_ipvlan_types },
+        [NL_UNION_LINK_INFO_DATA_VXLAN] =       { .max = ELEMENTSOF(rtnl_link_info_data_vxlan_types) - 1,
+                                                  .types = rtnl_link_info_data_vxlan_types },
+        [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
+                                                  .types = rtnl_link_info_data_iptun_types },
+        [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
+                                                    .types = rtnl_link_info_data_ipgre_types },
+        [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
+                                                    .types = rtnl_link_info_data_ipgre_types },
+        [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
+                                                    .types = rtnl_link_info_data_ipgre_types },
+        [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
+                                                    .types = rtnl_link_info_data_ipgre_types },
+        [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
+                                                  .types = rtnl_link_info_data_iptun_types },
+        [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
+                                                  .types = rtnl_link_info_data_ipvti_types },
+        [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
+                                                  .types = rtnl_link_info_data_ipvti_types },
+        [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types) - 1,
+                                                     .types = rtnl_link_info_data_ip6tnl_types },
+
+};
+
+static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
+        .num = _NL_UNION_LINK_INFO_DATA_MAX,
+        .lookup = nl_union_link_info_data_from_string,
+        .type_systems = rtnl_link_info_data_type_systems,
+        .match_type = NL_MATCH_SIBLING,
+        .match = IFLA_INFO_KIND,
+};
+
+static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
+        [IFLA_INFO_KIND]        = { .type = NLA_STRING },
+        [IFLA_INFO_DATA]        = { .type = NLA_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
+/*
+        [IFLA_INFO_XSTATS],
+        [IFLA_INFO_SLAVE_KIND]  = { .type = NLA_STRING },
+        [IFLA_INFO_SLAVE_DATA]  = { .type = NLA_NESTED },
+*/
+};
+
+static const NLTypeSystem rtnl_link_info_type_system = {
+        .max = ELEMENTSOF(rtnl_link_info_types) - 1,
+        .types = rtnl_link_info_types,
+};
+
+static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
+        [IFLA_BRPORT_STATE]     = { .type = NLA_U8 },
+        [IFLA_BRPORT_COST]      = { .type = NLA_U32 },
+        [IFLA_BRPORT_PRIORITY]  = { .type = NLA_U16 },
+        [IFLA_BRPORT_MODE]      = { .type = NLA_U8 },
+        [IFLA_BRPORT_GUARD]     = { .type = NLA_U8 },
+        [IFLA_BRPORT_PROTECT]   = { .type = NLA_U8 },
+        [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
+        [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
+};
+
+static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
+        [AF_BRIDGE] =   { .max = ELEMENTSOF(rtnl_prot_info_bridge_port_types) - 1,
+                          .types = rtnl_prot_info_bridge_port_types },
+};
+
+static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
+        .num = AF_MAX,
+        .type_systems = rtnl_prot_info_type_systems,
+        .match_type = NL_MATCH_PROTOCOL,
+};
+
+static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
+        [IFLA_INET6_FLAGS]              = { .type = NLA_U32 },
+/*
+        IFLA_INET6_CONF,
+        IFLA_INET6_STATS,
+        IFLA_INET6_MCAST,
+        IFLA_INET6_CACHEINFO,
+        IFLA_INET6_ICMP6STATS,
+*/
+        [IFLA_INET6_TOKEN]              = { .type = NLA_IN_ADDR },
+        [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NLA_U8 },
+};
+
+static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
+        .max = ELEMENTSOF(rtnl_af_spec_inet6_types) - 1,
+        .types = rtnl_af_spec_inet6_types,
+};
+
+static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
+        [AF_INET6] =    { .type = NLA_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
+};
+
+static const NLTypeSystem rtnl_af_spec_type_system = {
+        .max = ELEMENTSOF(rtnl_af_spec_types) - 1,
+        .types = rtnl_af_spec_types,
+};
+
+static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
+        [IFLA_ADDRESS]          = { .type = NLA_ETHER_ADDR, },
+        [IFLA_BROADCAST]        = { .type = NLA_ETHER_ADDR, },
+        [IFLA_IFNAME]           = { .type = NLA_STRING, .size = IFNAMSIZ - 1, },
+        [IFLA_MTU]              = { .type = NLA_U32 },
+        [IFLA_LINK]             = { .type = NLA_U32 },
+/*
+        [IFLA_QDISC],
+        [IFLA_STATS],
+        [IFLA_COST],
+        [IFLA_PRIORITY],
+*/
+        [IFLA_MASTER]           = { .type = NLA_U32 },
+/*
+        [IFLA_WIRELESS],
+*/
+        [IFLA_PROTINFO]         = { .type = NLA_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
+        [IFLA_TXQLEN]           = { .type = NLA_U32 },
+/*
+        [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
+*/
+        [IFLA_WEIGHT]           = { .type = NLA_U32 },
+        [IFLA_OPERSTATE]        = { .type = NLA_U8 },
+        [IFLA_LINKMODE]         = { .type = NLA_U8 },
+        [IFLA_LINKINFO]         = { .type = NLA_NESTED, .type_system = &rtnl_link_info_type_system },
+        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
+        [IFLA_IFALIAS]          = { .type = NLA_STRING, .size = IFALIASZ - 1 },
+/*
+        [IFLA_NUM_VF],
+        [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED, },
+        [IFLA_STATS64],
+        [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
+        [IFLA_PORT_SELF]        = { .type = NLA_NESTED },
+*/
+        [IFLA_AF_SPEC]          = { .type = NLA_NESTED, .type_system = &rtnl_af_spec_type_system },
+/*
+        [IFLA_VF_PORTS],
+        [IFLA_PORT_SELF],
+        [IFLA_AF_SPEC],
+*/
+        [IFLA_GROUP]            = { .type = NLA_U32 },
+        [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
+        [IFLA_EXT_MASK]         = { .type = NLA_U32 },
+        [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
+        [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
+        [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
+        [IFLA_CARRIER]          = { .type = NLA_U8 },
+/*
+        [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
+*/
+};
+
+static const NLTypeSystem rtnl_link_type_system = {
+        .max = ELEMENTSOF(rtnl_link_types) - 1,
+        .types = rtnl_link_types,
+};
+
+/* IFA_FLAGS was defined in kernel 3.14, but we still support older
+ * kernels where IFA_MAX is lower. */
+static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
+        [IFA_ADDRESS]           = { .type = NLA_IN_ADDR },
+        [IFA_LOCAL]             = { .type = NLA_IN_ADDR },
+        [IFA_LABEL]             = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
+        [IFA_BROADCAST]         = { .type = NLA_IN_ADDR }, /* 6? */
+        [IFA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
+/*
+        [IFA_ANYCAST],
+        [IFA_MULTICAST],
+*/
+        [IFA_FLAGS]             = { .type = NLA_U32 },
+};
+
+static const NLTypeSystem rtnl_address_type_system = {
+        .max = ELEMENTSOF(rtnl_address_types) - 1,
+        .types = rtnl_address_types,
+};
+
+static const NLType rtnl_route_types[RTA_MAX + 1] = {
+        [RTA_DST]               = { .type = NLA_IN_ADDR }, /* 6? */
+        [RTA_SRC]               = { .type = NLA_IN_ADDR }, /* 6? */
+        [RTA_IIF]               = { .type = NLA_U32 },
+        [RTA_OIF]               = { .type = NLA_U32 },
+        [RTA_GATEWAY]           = { .type = NLA_IN_ADDR },
+        [RTA_PRIORITY]          = { .type = NLA_U32 },
+        [RTA_PREFSRC]           = { .type = NLA_IN_ADDR }, /* 6? */
+/*
+        [RTA_METRICS]           = { .type = NLA_NESTED },
+        [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
+*/
+        [RTA_FLOW]              = { .type = NLA_U32 }, /* 6? */
+/*
+        RTA_CACHEINFO,
+        RTA_TABLE,
+        RTA_MARK,
+        RTA_MFC_STATS,
+*/
+};
+
+static const NLTypeSystem rtnl_route_type_system = {
+        .max = ELEMENTSOF(rtnl_route_types) - 1,
+        .types = rtnl_route_types,
+};
+
+static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
+        [NDA_DST]               = { .type = NLA_IN_ADDR },
+        [NDA_LLADDR]            = { .type = NLA_ETHER_ADDR },
+        [NDA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
+        [NDA_PROBES]            = { .type = NLA_U32 },
+        [NDA_VLAN]              = { .type = NLA_U16 },
+        [NDA_PORT]              = { .type = NLA_U16 },
+        [NDA_VNI]               = { .type = NLA_U32 },
+        [NDA_IFINDEX]           = { .type = NLA_U32 },
+};
+
+static const NLTypeSystem rtnl_neigh_type_system = {
+        .max = ELEMENTSOF(rtnl_neigh_types) - 1,
+        .types = rtnl_neigh_types,
+};
+
+static const NLType rtnl_types[RTM_MAX + 1] = {
+        [NLMSG_DONE]   = { .type = NLA_META, .size = 0 },
+        [NLMSG_ERROR]  = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
+        [RTM_NEWLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
+        [RTM_DELLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
+        [RTM_GETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
+        [RTM_SETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
+        [RTM_NEWADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
+        [RTM_DELADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
+        [RTM_GETADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
+        [RTM_NEWROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
+        [RTM_DELROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
+        [RTM_GETROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
+        [RTM_NEWNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
+        [RTM_DELNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
+        [RTM_GETNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
+};
+
+const NLTypeSystem rtnl_type_system = {
+        .max = ELEMENTSOF(rtnl_types) - 1,
+        .types = rtnl_types,
+};
+
+int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
+        const NLType *nl_type;
+
+        assert(ret);
+
+        if (!type_system)
+                type_system = &rtnl_type_system;
+
+        assert(type_system->types);
+
+        if (type > type_system->max)
+                return -EOPNOTSUPP;
+
+        nl_type = &type_system->types[type];
+
+        if (nl_type->type == NLA_UNSPEC)
+                return -EOPNOTSUPP;
+
+        *ret = nl_type;
+
+        return 0;
+}
+
+int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
+        const NLType *nl_type;
+        int r;
+
+        assert(ret);
+
+        r = type_system_get_type(type_system, &nl_type, type);
+        if (r < 0)
+                return r;
+
+        assert(nl_type->type == NLA_NESTED);
+        assert(nl_type->type_system);
+
+        *ret = nl_type->type_system;
+
+        return 0;
+}
+
+int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
+        const NLType *nl_type;
+        int r;
+
+        assert(ret);
+
+        r = type_system_get_type(type_system, &nl_type, type);
+        if (r < 0)
+                return r;
+
+        assert(nl_type->type == NLA_UNION);
+        assert(nl_type->type_system_union);
+
+        *ret = nl_type->type_system_union;
+
+        return 0;
+}
+
+int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
+        int type;
+
+        assert(type_system_union);
+        assert(type_system_union->match_type == NL_MATCH_SIBLING);
+        assert(type_system_union->lookup);
+        assert(type_system_union->type_systems);
+        assert(ret);
+        assert(key);
+
+        type = type_system_union->lookup(key);
+        if (type < 0)
+                return -EOPNOTSUPP;
+
+        assert(type < type_system_union->num);
+
+        *ret = &type_system_union->type_systems[type];
+
+        return 0;
+}
+
+int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
+        const NLTypeSystem *type_system;
+
+        assert(type_system_union);
+        assert(type_system_union->type_systems);
+        assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
+        assert(ret);
+
+        if (protocol >= type_system_union->num)
+                return -EOPNOTSUPP;
+
+        type_system = &type_system_union->type_systems[protocol];
+        if (type_system->max == 0)
+                return -EOPNOTSUPP;
+
+        *ret = type_system;
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h
new file mode 100644
index 0000000..de1544b
--- /dev/null
+++ b/src/libsystemd/sd-netlink/netlink-types.h
@@ -0,0 +1,119 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+enum {
+        NLA_UNSPEC,
+        NLA_META,
+        NLA_U8,
+        NLA_U16,
+        NLA_U32,
+        NLA_U64,
+        NLA_STRING,
+        NLA_IN_ADDR,
+        NLA_ETHER_ADDR,
+        NLA_CACHE_INFO,
+        NLA_NESTED,
+        NLA_UNION,
+};
+
+typedef enum NLMatchType {
+        NL_MATCH_SIBLING,
+        NL_MATCH_PROTOCOL,
+} NLMatchType;
+
+typedef struct NLTypeSystemUnion NLTypeSystemUnion;
+typedef struct NLTypeSystem NLTypeSystem;
+typedef struct NLType NLType;
+
+struct NLTypeSystemUnion {
+        int num;
+        NLMatchType match_type;
+        uint16_t match;
+        int (*lookup)(const char *);
+        const NLTypeSystem *type_systems;
+};
+
+struct NLTypeSystem {
+        uint16_t max;
+        const NLType *types;
+};
+
+struct NLType {
+        uint16_t type;
+        size_t size;
+        const NLTypeSystem *type_system;
+        const NLTypeSystemUnion *type_system_union;
+};
+
+int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
+int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
+int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
+int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key);
+int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol);
+
+typedef enum NLUnionLinkInfoData {
+        NL_UNION_LINK_INFO_DATA_BOND,
+        NL_UNION_LINK_INFO_DATA_BRIDGE,
+        NL_UNION_LINK_INFO_DATA_VLAN,
+        NL_UNION_LINK_INFO_DATA_VETH,
+        NL_UNION_LINK_INFO_DATA_DUMMY,
+        NL_UNION_LINK_INFO_DATA_MACVLAN,
+        NL_UNION_LINK_INFO_DATA_IPVLAN,
+        NL_UNION_LINK_INFO_DATA_VXLAN,
+        NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_SIT_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_VTI_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
+        _NL_UNION_LINK_INFO_DATA_MAX,
+        _NL_UNION_LINK_INFO_DATA_INVALID = -1
+} NLUnionLinkInfoData;
+
+const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_;
+NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
+
+/* Maximum ARP IP target defined in kernel */
+#define BOND_MAX_ARP_TARGETS    16
+
+typedef enum BondArpTargets {
+        BOND_ARP_TARGETS_0,
+        BOND_ARP_TARGETS_1,
+        BOND_ARP_TARGETS_2,
+        BOND_ARP_TARGETS_3,
+        BOND_ARP_TARGETS_4,
+        BOND_ARP_TARGETS_5,
+        BOND_ARP_TARGETS_6,
+        BOND_ARP_TARGETS_7,
+        BOND_ARP_TARGETS_8,
+        BOND_ARP_TARGETS_9,
+        BOND_ARP_TARGETS_10,
+        BOND_ARP_TARGETS_11,
+        BOND_ARP_TARGETS_12,
+        BOND_ARP_TARGETS_13,
+        BOND_ARP_TARGETS_14,
+        BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS,
+} BondArpTargets;
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
new file mode 100644
index 0000000..482ff6b
--- /dev/null
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -0,0 +1,173 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+
+#include "sd-netlink.h"
+
+#include "netlink-util.h"
+#include "netlink-internal.h"
+
+int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+        int r;
+
+        assert(rtnl);
+        assert(ifindex > 0);
+        assert(name);
+
+        if (!*rtnl) {
+                r = sd_netlink_open(rtnl);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_call(*rtnl, message, 0, NULL);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
+                             const struct ether_addr *mac, unsigned mtu) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+        int r;
+
+        assert(rtnl);
+        assert(ifindex > 0);
+
+        if (!alias && !mac && mtu == 0)
+                return 0;
+
+        if (!*rtnl) {
+                r = sd_netlink_open(rtnl);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
+        if (r < 0)
+                return r;
+
+        if (alias) {
+                r = sd_netlink_message_append_string(message, IFLA_IFALIAS, alias);
+                if (r < 0)
+                        return r;
+        }
+
+        if (mac) {
+                r = sd_netlink_message_append_ether_addr(message, IFLA_ADDRESS, mac);
+                if (r < 0)
+                        return r;
+        }
+
+        if (mtu > 0) {
+                r = sd_netlink_message_append_u32(message, IFLA_MTU, mtu);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_netlink_call(*rtnl, message, 0, NULL);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret) {
+        struct nlmsgerr *err;
+        int r;
+
+        assert(error <= 0);
+
+        r = message_new(NULL, ret, NLMSG_ERROR);
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_seq = serial;
+
+        err = NLMSG_DATA((*ret)->hdr);
+
+        err->error = error;
+
+        return 0;
+}
+
+bool rtnl_message_type_is_neigh(uint16_t type) {
+        switch (type) {
+                case RTM_NEWNEIGH:
+                case RTM_GETNEIGH:
+                case RTM_DELNEIGH:
+                        return true;
+                default:
+                        return false;
+        }
+}
+
+bool rtnl_message_type_is_route(uint16_t type) {
+        switch (type) {
+                case RTM_NEWROUTE:
+                case RTM_GETROUTE:
+                case RTM_DELROUTE:
+                        return true;
+                default:
+                        return false;
+        }
+}
+
+bool rtnl_message_type_is_link(uint16_t type) {
+        switch (type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_GETLINK:
+                case RTM_DELLINK:
+                        return true;
+                default:
+                        return false;
+        }
+}
+
+bool rtnl_message_type_is_addr(uint16_t type) {
+        switch (type) {
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        return true;
+                default:
+                        return false;
+        }
+}
+
+int rtnl_log_parse_error(int r) {
+        return log_error_errno(r, "Failed to parse netlink message: %m");
+}
+
+int rtnl_log_create_error(int r) {
+        return log_error_errno(r, "Failed to create netlink message: %m");
+}
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
new file mode 100644
index 0000000..9df0aa2
--- /dev/null
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -0,0 +1,47 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+
+#include "util.h"
+#include "sd-netlink.h"
+
+int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret);
+uint32_t rtnl_message_get_serial(sd_netlink_message *m);
+void rtnl_message_seal(sd_netlink_message *m);
+
+bool rtnl_message_type_is_link(uint16_t type);
+bool rtnl_message_type_is_addr(uint16_t type);
+bool rtnl_message_type_is_route(uint16_t type);
+bool rtnl_message_type_is_neigh(uint16_t type);
+
+int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
+int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
+
+int rtnl_log_parse_error(int r);
+int rtnl_log_create_error(int r);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_netlink*, sd_netlink_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_netlink_message*, sd_netlink_message_unref);
+
+#define _cleanup_netlink_unref_ _cleanup_(sd_netlink_unrefp)
+#define _cleanup_netlink_message_unref_ _cleanup_(sd_netlink_message_unrefp)
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
new file mode 100644
index 0000000..14cc759
--- /dev/null
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -0,0 +1,1056 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/socket.h>
+#include <poll.h>
+
+#include "missing.h"
+#include "macro.h"
+#include "util.h"
+#include "hashmap.h"
+
+#include "sd-netlink.h"
+#include "netlink-internal.h"
+#include "netlink-util.h"
+
+static int sd_netlink_new(sd_netlink **ret) {
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+
+        assert_return(ret, -EINVAL);
+
+        rtnl = new0(sd_netlink, 1);
+        if (!rtnl)
+                return -ENOMEM;
+
+        rtnl->n_ref = REFCNT_INIT;
+
+        rtnl->fd = -1;
+
+        rtnl->sockaddr.nl.nl_family = AF_NETLINK;
+
+        rtnl->original_pid = getpid();
+
+        LIST_HEAD_INIT(rtnl->match_callbacks);
+
+        /* We guarantee that wqueue always has space for at least
+         * one entry */
+        if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
+                return -ENOMEM;
+
+        /* We guarantee that the read buffer has at least space for
+         * a message header */
+        if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
+                            sizeof(struct nlmsghdr), sizeof(uint8_t)))
+                return -ENOMEM;
+
+        /* Change notification responses have sequence 0, so we must
+         * start our request sequence numbers at 1, or we may confuse our
+         * responses with notifications from the kernel */
+        rtnl->serial = 1;
+
+        *ret = rtnl;
+        rtnl = NULL;
+
+        return 0;
+}
+
+int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        socklen_t addrlen;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        r = sd_netlink_new(&rtnl);
+        if (r < 0)
+                return r;
+
+        addrlen = sizeof(rtnl->sockaddr);
+
+        r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
+        if (r < 0)
+                return -errno;
+
+        rtnl->fd = fd;
+
+        *ret = rtnl;
+        rtnl = NULL;
+
+        return 0;
+}
+
+static bool rtnl_pid_changed(sd_netlink *rtnl) {
+        assert(rtnl);
+
+        /* We don't support people creating an rtnl connection and
+         * keeping it around over a fork(). Let's complain. */
+
+        return rtnl->original_pid != getpid();
+}
+
+int sd_netlink_open_fd(sd_netlink **ret, int fd) {
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        socklen_t addrlen;
+        int r, one = 1;
+
+        assert_return(ret, -EINVAL);
+        assert_return(fd >= 0, -EINVAL);
+
+        r = sd_netlink_new(&rtnl);
+        if (r < 0)
+                return r;
+
+        r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
+        if (r < 0)
+                return -errno;
+
+        addrlen = sizeof(rtnl->sockaddr);
+
+        r = bind(fd, &rtnl->sockaddr.sa, addrlen);
+        /* ignore EINVAL to allow opening an already bound socket */
+        if (r < 0 && errno != EINVAL)
+                return -errno;
+
+        r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
+        if (r < 0)
+                return -errno;
+
+        rtnl->fd = fd;
+
+        *ret = rtnl;
+        rtnl = NULL;
+
+        return 0;
+}
+
+int sd_netlink_open(sd_netlink **ret) {
+        _cleanup_close_ int fd = -1;
+        int r;
+
+        fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
+        if (fd < 0)
+                return -errno;
+
+        r = sd_netlink_open_fd(ret, fd);
+        if (r < 0)
+                return r;
+
+        fd = -1;
+
+        return 0;
+}
+
+static int rtnl_join_broadcast_group(sd_netlink *rtnl, unsigned group) {
+        int r;
+
+        assert(rtnl);
+        assert(rtnl->fd >= 0);
+        assert(group > 0);
+
+        r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size) {
+        return fd_inc_rcvbuf(rtnl->fd, size);
+}
+
+sd_netlink *sd_netlink_ref(sd_netlink *rtnl) {
+        assert_return(rtnl, NULL);
+        assert_return(!rtnl_pid_changed(rtnl), NULL);
+
+        if (rtnl)
+                assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
+
+        return rtnl;
+}
+
+sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
+        if (!rtnl)
+                return NULL;
+
+        assert_return(!rtnl_pid_changed(rtnl), NULL);
+
+        if (REFCNT_DEC(rtnl->n_ref) == 0) {
+                struct match_callback *f;
+                unsigned i;
+
+                for (i = 0; i < rtnl->rqueue_size; i++)
+                        sd_netlink_message_unref(rtnl->rqueue[i]);
+                free(rtnl->rqueue);
+
+                for (i = 0; i < rtnl->rqueue_partial_size; i++)
+                        sd_netlink_message_unref(rtnl->rqueue_partial[i]);
+                free(rtnl->rqueue_partial);
+
+                for (i = 0; i < rtnl->wqueue_size; i++)
+                        sd_netlink_message_unref(rtnl->wqueue[i]);
+                free(rtnl->wqueue);
+
+                free(rtnl->rbuffer);
+
+                hashmap_free_free(rtnl->reply_callbacks);
+                prioq_free(rtnl->reply_callbacks_prioq);
+
+                sd_event_source_unref(rtnl->io_event_source);
+                sd_event_source_unref(rtnl->time_event_source);
+                sd_event_source_unref(rtnl->exit_event_source);
+                sd_event_unref(rtnl->event);
+
+                while ((f = rtnl->match_callbacks)) {
+                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
+                        free(f);
+                }
+
+                safe_close(rtnl->fd);
+                free(rtnl);
+        }
+
+        return NULL;
+}
+
+static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) {
+        assert(rtnl);
+        assert(!rtnl_pid_changed(rtnl));
+        assert(m);
+        assert(m->hdr);
+
+        /* don't use seq == 0, as that is used for broadcasts, so we
+           would get confused by replies to such messages */
+        m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++;
+
+        rtnl_message_seal(m);
+
+        return;
+}
+
+int sd_netlink_send(sd_netlink *nl,
+                 sd_netlink_message *message,
+                 uint32_t *serial) {
+        int r;
+
+        assert_return(nl, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+        assert_return(message, -EINVAL);
+        assert_return(!message->sealed, -EPERM);
+
+        rtnl_seal_message(nl, message);
+
+        if (nl->wqueue_size <= 0) {
+                /* send directly */
+                r = socket_write_message(nl, message);
+                if (r < 0)
+                        return r;
+                else if (r == 0) {
+                        /* nothing was sent, so let's put it on
+                         * the queue */
+                        nl->wqueue[0] = sd_netlink_message_ref(message);
+                        nl->wqueue_size = 1;
+                }
+        } else {
+                /* append to queue */
+                if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
+                        log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
+                        return -ENOBUFS;
+                }
+
+                if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
+                        return -ENOMEM;
+
+                nl->wqueue[nl->wqueue_size ++] = sd_netlink_message_ref(message);
+        }
+
+        if (serial)
+                *serial = rtnl_message_get_serial(message);
+
+        return 1;
+}
+
+int rtnl_rqueue_make_room(sd_netlink *rtnl) {
+        assert(rtnl);
+
+        if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
+                log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
+                return -ENOBUFS;
+        }
+
+        if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int rtnl_rqueue_partial_make_room(sd_netlink *rtnl) {
+        assert(rtnl);
+
+        if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
+                log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
+                return -ENOBUFS;
+        }
+
+        if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
+                            rtnl->rqueue_partial_size + 1))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
+        int r;
+
+        assert(rtnl);
+        assert(message);
+
+        if (rtnl->rqueue_size <= 0) {
+                /* Try to read a new message */
+                r = socket_read_message(rtnl);
+                if (r <= 0)
+                        return r;
+        }
+
+        /* Dispatch a queued message */
+        *message = rtnl->rqueue[0];
+        rtnl->rqueue_size --;
+        memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size);
+
+        return 1;
+}
+
+static int dispatch_wqueue(sd_netlink *rtnl) {
+        int r, ret = 0;
+
+        assert(rtnl);
+
+        while (rtnl->wqueue_size > 0) {
+                r = socket_write_message(rtnl, rtnl->wqueue[0]);
+                if (r < 0)
+                        return r;
+                else if (r == 0)
+                        /* Didn't do anything this time */
+                        return ret;
+                else {
+                        /* see equivalent in sd-bus.c */
+                        sd_netlink_message_unref(rtnl->wqueue[0]);
+                        rtnl->wqueue_size --;
+                        memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_netlink_message*) * rtnl->wqueue_size);
+
+                        ret = 1;
+                }
+        }
+
+        return ret;
+}
+
+static int process_timeout(sd_netlink *rtnl) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+        struct reply_callback *c;
+        usec_t n;
+        int r;
+
+        assert(rtnl);
+
+        c = prioq_peek(rtnl->reply_callbacks_prioq);
+        if (!c)
+                return 0;
+
+        n = now(CLOCK_MONOTONIC);
+        if (c->timeout > n)
+                return 0;
+
+        r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
+        if (r < 0)
+                return r;
+
+        assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
+        hashmap_remove(rtnl->reply_callbacks, &c->serial);
+
+        r = c->callback(rtnl, m, c->userdata);
+        if (r < 0)
+                log_debug_errno(r, "sd-netlink: timedout callback failed: %m");
+
+        free(c);
+
+        return 1;
+}
+
+static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) {
+        _cleanup_free_ struct reply_callback *c = NULL;
+        uint64_t serial;
+        uint16_t type;
+        int r;
+
+        assert(rtnl);
+        assert(m);
+
+        serial = rtnl_message_get_serial(m);
+        c = hashmap_remove(rtnl->reply_callbacks, &serial);
+        if (!c)
+                return 0;
+
+        if (c->timeout != 0)
+                prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
+
+        r = sd_netlink_message_get_type(m, &type);
+        if (r < 0)
+                return 0;
+
+        if (type == NLMSG_DONE)
+                m = NULL;
+
+        r = c->callback(rtnl, m, c->userdata);
+        if (r < 0)
+                log_debug_errno(r, "sd-netlink: callback failed: %m");
+
+        return 1;
+}
+
+static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
+        struct match_callback *c;
+        uint16_t type;
+        int r;
+
+        assert(rtnl);
+        assert(m);
+
+        r = sd_netlink_message_get_type(m, &type);
+        if (r < 0)
+                return r;
+
+        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
+                if (type == c->type) {
+                        r = c->callback(rtnl, m, c->userdata);
+                        if (r != 0) {
+                                if (r < 0)
+                                        log_debug_errno(r, "sd-netlink: match callback failed: %m");
+
+                                break;
+                        }
+                }
+        }
+
+        return 1;
+}
+
+static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+        int r;
+
+        assert(rtnl);
+
+        r = process_timeout(rtnl);
+        if (r != 0)
+                goto null_message;
+
+        r = dispatch_wqueue(rtnl);
+        if (r != 0)
+                goto null_message;
+
+        r = dispatch_rqueue(rtnl, &m);
+        if (r < 0)
+                return r;
+        if (!m)
+                goto null_message;
+
+        if (sd_netlink_message_is_broadcast(m)) {
+                r = process_match(rtnl, m);
+                if (r != 0)
+                        goto null_message;
+        } else {
+                r = process_reply(rtnl, m);
+                if (r != 0)
+                        goto null_message;
+        }
+
+        if (ret) {
+                *ret = m;
+                m = NULL;
+
+                return 1;
+        }
+
+        return 1;
+
+null_message:
+        if (r >= 0 && ret)
+                *ret = NULL;
+
+        return r;
+}
+
+int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) {
+        RTNL_DONT_DESTROY(rtnl);
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+        assert_return(!rtnl->processing, -EBUSY);
+
+        rtnl->processing = true;
+        r = process_running(rtnl, ret);
+        rtnl->processing = false;
+
+        return r;
+}
+
+static usec_t calc_elapse(uint64_t usec) {
+        if (usec == (uint64_t) -1)
+                return 0;
+
+        if (usec == 0)
+                usec = RTNL_DEFAULT_TIMEOUT;
+
+        return now(CLOCK_MONOTONIC) + usec;
+}
+
+static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
+        struct pollfd p[1] = {};
+        struct timespec ts;
+        usec_t m = USEC_INFINITY;
+        int r, e;
+
+        assert(rtnl);
+
+        e = sd_netlink_get_events(rtnl);
+        if (e < 0)
+                return e;
+
+        if (need_more)
+                /* Caller wants more data, and doesn't care about
+                 * what's been read or any other timeouts. */
+                e |= POLLIN;
+        else {
+                usec_t until;
+                /* Caller wants to process if there is something to
+                 * process, but doesn't care otherwise */
+
+                r = sd_netlink_get_timeout(rtnl, &until);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        usec_t nw;
+                        nw = now(CLOCK_MONOTONIC);
+                        m = until > nw ? until - nw : 0;
+                }
+        }
+
+        if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
+                m = timeout_usec;
+
+        p[0].fd = rtnl->fd;
+        p[0].events = e;
+
+        r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
+        if (r < 0)
+                return -errno;
+
+        return r > 0 ? 1 : 0;
+}
+
+int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
+        assert_return(nl, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+
+        if (nl->rqueue_size > 0)
+                return 0;
+
+        return rtnl_poll(nl, false, timeout_usec);
+}
+
+static int timeout_compare(const void *a, const void *b) {
+        const struct reply_callback *x = a, *y = b;
+
+        if (x->timeout != 0 && y->timeout == 0)
+                return -1;
+
+        if (x->timeout == 0 && y->timeout != 0)
+                return 1;
+
+        if (x->timeout < y->timeout)
+                return -1;
+
+        if (x->timeout > y->timeout)
+                return 1;
+
+        return 0;
+}
+
+int sd_netlink_call_async(sd_netlink *nl,
+                       sd_netlink_message *m,
+                       sd_netlink_message_handler_t callback,
+                       void *userdata,
+                       uint64_t usec,
+                       uint32_t *serial) {
+        struct reply_callback *c;
+        uint32_t s;
+        int r, k;
+
+        assert_return(nl, -EINVAL);
+        assert_return(m, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+
+        r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
+        if (r < 0)
+                return r;
+
+        if (usec != (uint64_t) -1) {
+                r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
+                if (r < 0)
+                        return r;
+        }
+
+        c = new0(struct reply_callback, 1);
+        if (!c)
+                return -ENOMEM;
+
+        c->callback = callback;
+        c->userdata = userdata;
+        c->timeout = calc_elapse(usec);
+
+        k = sd_netlink_send(nl, m, &s);
+        if (k < 0) {
+                free(c);
+                return k;
+        }
+
+        c->serial = s;
+
+        r = hashmap_put(nl->reply_callbacks, &c->serial, c);
+        if (r < 0) {
+                free(c);
+                return r;
+        }
+
+        if (c->timeout != 0) {
+                r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
+                if (r > 0) {
+                        c->timeout = 0;
+                        sd_netlink_call_async_cancel(nl, c->serial);
+                        return r;
+                }
+        }
+
+        if (serial)
+                *serial = s;
+
+        return k;
+}
+
+int sd_netlink_call_async_cancel(sd_netlink *nl, uint32_t serial) {
+        struct reply_callback *c;
+        uint64_t s = serial;
+
+        assert_return(nl, -EINVAL);
+        assert_return(serial != 0, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+
+        c = hashmap_remove(nl->reply_callbacks, &s);
+        if (!c)
+                return 0;
+
+        if (c->timeout != 0)
+                prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
+
+        free(c);
+        return 1;
+}
+
+int sd_netlink_call(sd_netlink *rtnl,
+                sd_netlink_message *message,
+                uint64_t usec,
+                sd_netlink_message **ret) {
+        usec_t timeout;
+        uint32_t serial;
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+        assert_return(message, -EINVAL);
+
+        r = sd_netlink_send(rtnl, message, &serial);
+        if (r < 0)
+                return r;
+
+        timeout = calc_elapse(usec);
+
+        for (;;) {
+                usec_t left;
+                unsigned i;
+
+                for (i = 0; i < rtnl->rqueue_size; i++) {
+                        uint32_t received_serial;
+
+                        received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
+
+                        if (received_serial == serial) {
+                                _cleanup_netlink_message_unref_ sd_netlink_message *incoming = NULL;
+                                uint16_t type;
+
+                                incoming = rtnl->rqueue[i];
+
+                                /* found a match, remove from rqueue and return it */
+                                memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
+                                        sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1));
+                                rtnl->rqueue_size--;
+
+                                r = sd_netlink_message_get_errno(incoming);
+                                if (r < 0)
+                                        return r;
+
+                                r = sd_netlink_message_get_type(incoming, &type);
+                                if (r < 0)
+                                        return r;
+
+                                if (type == NLMSG_DONE) {
+                                        *ret = NULL;
+                                        return 0;
+                                }
+
+                                if (ret) {
+                                        *ret = incoming;
+                                        incoming = NULL;
+                                }
+
+                                return 1;
+                        }
+                }
+
+                r = socket_read_message(rtnl);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        /* received message, so try to process straight away */
+                        continue;
+
+                if (timeout > 0) {
+                        usec_t n;
+
+                        n = now(CLOCK_MONOTONIC);
+                        if (n >= timeout)
+                                return -ETIMEDOUT;
+
+                        left = timeout - n;
+                } else
+                        left = (uint64_t) -1;
+
+                r = rtnl_poll(rtnl, true, left);
+                if (r < 0)
+                        return r;
+                else if (r == 0)
+                        return -ETIMEDOUT;
+
+                r = dispatch_wqueue(rtnl);
+                if (r < 0)
+                        return r;
+        }
+}
+
+int sd_netlink_flush(sd_netlink *rtnl) {
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        if (rtnl->wqueue_size <= 0)
+                return 0;
+
+        for (;;) {
+                r = dispatch_wqueue(rtnl);
+                if (r < 0)
+                        return r;
+
+                if (rtnl->wqueue_size <= 0)
+                        return 0;
+
+                r = rtnl_poll(rtnl, false, (uint64_t) -1);
+                if (r < 0)
+                        return r;
+        }
+}
+
+int sd_netlink_get_events(sd_netlink *rtnl) {
+        int flags = 0;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        if (rtnl->rqueue_size <= 0)
+                flags |= POLLIN;
+        if (rtnl->wqueue_size > 0)
+                flags |= POLLOUT;
+
+        return flags;
+}
+
+int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) {
+        struct reply_callback *c;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(timeout_usec, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        if (rtnl->rqueue_size > 0) {
+                *timeout_usec = 0;
+                return 1;
+        }
+
+        c = prioq_peek(rtnl->reply_callbacks_prioq);
+        if (!c) {
+                *timeout_usec = (uint64_t) -1;
+                return 0;
+        }
+
+        *timeout_usec = c->timeout;
+
+        return 1;
+}
+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        sd_netlink *rtnl = userdata;
+        int r;
+
+        assert(rtnl);
+
+        r = sd_netlink_process(rtnl, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
+        sd_netlink *rtnl = userdata;
+        int r;
+
+        assert(rtnl);
+
+        r = sd_netlink_process(rtnl, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int prepare_callback(sd_event_source *s, void *userdata) {
+        sd_netlink *rtnl = userdata;
+        int r, e;
+        usec_t until;
+
+        assert(s);
+        assert(rtnl);
+
+        e = sd_netlink_get_events(rtnl);
+        if (e < 0)
+                return e;
+
+        r = sd_event_source_set_io_events(rtnl->io_event_source, e);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_get_timeout(rtnl, &until);
+        if (r < 0)
+                return r;
+        if (r > 0) {
+                int j;
+
+                j = sd_event_source_set_time(rtnl->time_event_source, until);
+                if (j < 0)
+                        return j;
+        }
+
+        r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int exit_callback(sd_event_source *event, void *userdata) {
+        sd_netlink *rtnl = userdata;
+
+        assert(event);
+
+        sd_netlink_flush(rtnl);
+
+        return 1;
+}
+
+int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) {
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl->event, -EBUSY);
+
+        assert(!rtnl->io_event_source);
+        assert(!rtnl->time_event_source);
+
+        if (event)
+                rtnl->event = sd_event_ref(event);
+        else {
+                r = sd_event_default(&rtnl->event);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_priority(rtnl->io_event_source, priority);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_priority(rtnl->time_event_source, priority);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
+        if (r < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        sd_netlink_detach_event(rtnl);
+        return r;
+}
+
+int sd_netlink_detach_event(sd_netlink *rtnl) {
+        assert_return(rtnl, -EINVAL);
+        assert_return(rtnl->event, -ENXIO);
+
+        if (rtnl->io_event_source)
+                rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
+
+        if (rtnl->time_event_source)
+                rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
+
+        if (rtnl->exit_event_source)
+                rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
+
+        if (rtnl->event)
+                rtnl->event = sd_event_unref(rtnl->event);
+
+        return 0;
+}
+
+int sd_netlink_add_match(sd_netlink *rtnl,
+                      uint16_t type,
+                      sd_netlink_message_handler_t callback,
+                      void *userdata) {
+        _cleanup_free_ struct match_callback *c = NULL;
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        c = new0(struct match_callback, 1);
+        if (!c)
+                return -ENOMEM;
+
+        c->callback = callback;
+        c->type = type;
+        c->userdata = userdata;
+
+        switch (type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_GETLINK:
+                case RTM_DELLINK:
+                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_LINK);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
+                        if (r < 0)
+                                return r;
+
+                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                default:
+                        return -EOPNOTSUPP;
+        }
+
+        LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
+
+        c = NULL;
+
+        return 0;
+}
+
+int sd_netlink_remove_match(sd_netlink *rtnl,
+                         uint16_t type,
+                         sd_netlink_message_handler_t callback,
+                         void *userdata) {
+        struct match_callback *c;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        /* we should unsubscribe from the broadcast groups at this point, but it is not so
+           trivial for a few reasons: the refcounting is a bit of a mess and not obvious
+           how it will look like after we add genetlink support, and it is also not possible
+           to query what broadcast groups were subscribed to when we inherit the socket to get
+           the initial refcount. The latter could indeed be done for the first 32 broadcast
+           groups (which incidentally is all we currently support in .socket units anyway),
+           but we better not rely on only ever using 32 groups. */
+        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
+                if (c->callback == callback && c->type == type && c->userdata == userdata) {
+                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
+                        free(c);
+
+                        return 1;
+                }
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c
new file mode 100644
index 0000000..38cbcfb
--- /dev/null
+++ b/src/libsystemd/sd-netlink/test-local-addresses.c
@@ -0,0 +1,58 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "in-addr-util.h"
+#include "local-addresses.h"
+#include "af-list.h"
+
+static void print_local_addresses(struct local_address *a, unsigned n) {
+        unsigned i;
+
+        for (i = 0; i < n; i++) {
+                _cleanup_free_ char *b = NULL;
+
+                assert_se(in_addr_to_string(a[i].family, &a[i].address, &b) >= 0);
+                printf("%s if%i scope=%i metric=%u address=%s\n", af_to_name(a[i].family), a[i].ifindex, a[i].scope, a[i].metric, b);
+        }
+}
+
+int main(int argc, char *argv[]) {
+        struct local_address *a;
+        int n;
+
+        a = NULL;
+        n = local_addresses(NULL, 0, AF_UNSPEC, &a);
+        assert_se(n >= 0);
+
+        printf("Local Addresses:\n");
+        print_local_addresses(a, (unsigned) n);
+        free(a);
+
+        a = NULL;
+        n = local_gateways(NULL, 0, AF_UNSPEC, &a);
+        assert_se(n >= 0);
+
+        printf("Local Gateways:\n");
+        print_local_addresses(a, (unsigned) n);
+        free(a);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
new file mode 100644
index 0000000..60a4601
--- /dev/null
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -0,0 +1,443 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/ether.h>
+#include <net/if.h>
+
+#include "util.h"
+#include "macro.h"
+#include "sd-netlink.h"
+#include "socket-util.h"
+#include "netlink-util.h"
+#include "event-util.h"
+#include "missing.h"
+
+static void test_message_link_bridge(sd_netlink *rtnl) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+        uint32_t cost;
+
+        assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0);
+        assert_se(sd_rtnl_message_link_set_family(message, PF_BRIDGE) >= 0);
+        assert_se(sd_netlink_message_open_container(message, IFLA_PROTINFO) >= 0);
+        assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
+        assert_se(sd_netlink_message_close_container(message) >= 0);
+
+        assert_se(sd_netlink_message_rewind(message) >= 0);
+
+        assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0);
+        assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
+        assert_se(cost == 10);
+        assert_se(sd_netlink_message_exit_container(message) >= 0);
+}
+
+static void test_link_configure(sd_netlink *rtnl, int ifindex) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
+        const char *mac = "98:fe:94:3f:c6:18", *name = "test";
+        char buffer[ETHER_ADDR_TO_STRING_MAX];
+        unsigned int mtu = 1450, mtu_out;
+        const char *name_out;
+        struct ether_addr mac_out;
+
+        /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
+        assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
+        assert_se(sd_netlink_message_append_string(message, IFLA_IFNAME, name) >= 0);
+        assert_se(sd_netlink_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
+        assert_se(sd_netlink_message_append_u32(message, IFLA_MTU, mtu) >= 0);
+
+        assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1);
+        assert_se(sd_netlink_message_rewind(message) >= 0);
+
+        assert_se(sd_netlink_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
+        assert_se(streq(name, name_out));
+
+        assert_se(sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &mac_out) >= 0);
+        assert_se(streq(mac, ether_addr_to_string(&mac_out, buffer)));
+
+        assert_se(sd_netlink_message_read_u32(message, IFLA_MTU, &mtu_out) >= 0);
+        assert_se(mtu == mtu_out);
+}
+
+static void test_link_get(sd_netlink *rtnl, int ifindex) {
+        sd_netlink_message *m;
+        sd_netlink_message *r;
+        unsigned int mtu = 1500;
+        const char *str_data;
+        uint8_t u8_data;
+        uint32_t u32_data;
+        struct ether_addr eth_data;
+
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+        assert_se(m);
+
+        /* u8 test cases  */
+        assert_se(sd_netlink_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
+        assert_se(sd_netlink_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
+        assert_se(sd_netlink_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
+
+        /* u32 test cases */
+        assert_se(sd_netlink_message_append_u32(m, IFLA_MTU, mtu) >= 0);
+        assert_se(sd_netlink_message_append_u32(m, IFLA_GROUP, 0) >= 0);
+        assert_se(sd_netlink_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
+        assert_se(sd_netlink_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
+        assert_se(sd_netlink_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
+
+        assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1);
+
+        assert_se(sd_netlink_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
+
+        assert_se(sd_netlink_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
+        assert_se(sd_netlink_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
+        assert_se(sd_netlink_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
+
+        assert_se(sd_netlink_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
+        assert_se(sd_netlink_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
+        assert_se(sd_netlink_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
+        assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
+        assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
+
+        assert_se(sd_netlink_message_read_ether_addr(r, IFLA_ADDRESS, &eth_data) == 0);
+
+        assert_se(sd_netlink_flush(rtnl) >= 0);
+        assert_se((m = sd_netlink_message_unref(m)) == NULL);
+        assert_se((r = sd_netlink_message_unref(r)) == NULL);
+}
+
+
+static void test_address_get(sd_netlink *rtnl, int ifindex) {
+        sd_netlink_message *m;
+        sd_netlink_message *r;
+        struct in_addr in_data;
+        struct ifa_cacheinfo cache;
+        const char *label;
+
+        assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
+        assert_se(m);
+
+        assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1);
+
+        assert_se(sd_netlink_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
+        assert_se(sd_netlink_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
+        assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0);
+        assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
+
+        assert_se(sd_netlink_flush(rtnl) >= 0);
+        assert_se((m = sd_netlink_message_unref(m)) == NULL);
+        assert_se((r = sd_netlink_message_unref(r)) == NULL);
+
+}
+
+static void test_route(void) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req;
+        struct in_addr addr, addr_data;
+        uint32_t index = 2, u32_data;
+        int r;
+
+        r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
+        if (r < 0) {
+                log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
+                return;
+        }
+
+        addr.s_addr = htonl(INADDR_LOOPBACK);
+
+        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &addr);
+        if (r < 0) {
+                log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
+                return;
+        }
+
+        r = sd_netlink_message_append_u32(req, RTA_OIF, index);
+        if (r < 0) {
+                log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+                return;
+        }
+
+        assert_se(sd_netlink_message_rewind(req) >= 0);
+
+        assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
+        assert_se(addr_data.s_addr == addr.s_addr);
+
+        assert_se(sd_netlink_message_read_u32(req, RTA_OIF, &u32_data) >= 0);
+        assert_se(u32_data == index);
+
+        assert_se((req = sd_netlink_message_unref(req)) == NULL);
+}
+
+static void test_multiple(void) {
+        sd_netlink *rtnl1, *rtnl2;
+
+        assert_se(sd_netlink_open(&rtnl1) >= 0);
+        assert_se(sd_netlink_open(&rtnl2) >= 0);
+
+        rtnl1 = sd_netlink_unref(rtnl1);
+        rtnl2 = sd_netlink_unref(rtnl2);
+}
+
+static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        char *ifname = userdata;
+        const char *data;
+
+        assert_se(rtnl);
+        assert_se(m);
+
+        log_info("got link info about %s", ifname);
+        free(ifname);
+
+        assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0);
+        assert_se(streq(data, "lo"));
+
+        return 1;
+}
+
+static void test_event_loop(int ifindex) {
+        _cleanup_event_unref_ sd_event *event = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+        char *ifname;
+
+        ifname = strdup("lo2");
+        assert_se(ifname);
+
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+
+        assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
+
+        assert_se(sd_event_default(&event) >= 0);
+
+        assert_se(sd_netlink_attach_event(rtnl, event, 0) >= 0);
+
+        assert_se(sd_event_run(event, 0) >= 0);
+
+        assert_se(sd_netlink_detach_event(rtnl) >= 0);
+
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+}
+
+static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        int *counter = userdata;
+        int r;
+
+        (*counter) --;
+
+        r = sd_netlink_message_get_errno(m);
+
+        log_info_errno(r, "%d left in pipe. got reply: %m", *counter);
+
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static void test_async(int ifindex) {
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *r = NULL;
+        uint32_t serial;
+        char *ifname;
+
+        ifname = strdup("lo");
+        assert_se(ifname);
+
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+
+        assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
+
+        assert_se(sd_netlink_wait(rtnl, 0) >= 0);
+        assert_se(sd_netlink_process(rtnl, &r) >= 0);
+
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+}
+
+static void test_pipe(int ifindex) {
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *m1 = NULL, *m2 = NULL;
+        int counter = 0;
+
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+
+        assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
+        assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
+
+        counter ++;
+        assert_se(sd_netlink_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
+
+        counter ++;
+        assert_se(sd_netlink_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
+
+        while (counter > 0) {
+                assert_se(sd_netlink_wait(rtnl, 0) >= 0);
+                assert_se(sd_netlink_process(rtnl, NULL) >= 0);
+        }
+
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+}
+
+static void test_container(void) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+        uint16_t u16_data;
+        uint32_t u32_data;
+        const char *string_data;
+
+        assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
+
+        assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
+        assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
+        assert_se(sd_netlink_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+        assert_se(sd_netlink_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+        assert_se(sd_netlink_message_close_container(m) == -EINVAL);
+
+        assert_se(sd_netlink_message_rewind(m) >= 0);
+
+        assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0);
+        assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
+        assert_se(streq("vlan", string_data));
+
+        assert_se(sd_netlink_message_enter_container(m, IFLA_INFO_DATA) >= 0);
+        assert_se(sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0);
+        assert_se(sd_netlink_message_exit_container(m) >= 0);
+
+        assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
+        assert_se(streq("vlan", string_data));
+        assert_se(sd_netlink_message_exit_container(m) >= 0);
+
+        assert_se(sd_netlink_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0);
+
+        assert_se(sd_netlink_message_exit_container(m) == -EINVAL);
+}
+
+static void test_match(void) {
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+
+        assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
+        assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
+
+        assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
+        assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
+        assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
+
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+}
+
+static void test_get_addresses(sd_netlink *rtnl) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *m;
+
+        assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
+
+        assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0);
+
+        for (m = reply; m; m = sd_netlink_message_next(m)) {
+                uint16_t type;
+                unsigned char scope, flags;
+                int family, ifindex;
+
+                assert_se(sd_netlink_message_get_type(m, &type) >= 0);
+                assert_se(type == RTM_NEWADDR);
+
+                assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0);
+                assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0);
+                assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0);
+                assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0);
+
+                assert_se(ifindex > 0);
+                assert_se(family == AF_INET || family == AF_INET6);
+
+                log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex);
+        }
+}
+
+static void test_message(void) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+
+        assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
+        assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
+}
+
+int main(void) {
+        sd_netlink *rtnl;
+        sd_netlink_message *m;
+        sd_netlink_message *r;
+        const char *string_data;
+        int if_loopback;
+        uint16_t type;
+
+        test_message();
+
+        test_match();
+
+        test_multiple();
+
+        test_route();
+
+        test_container();
+
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+        assert_se(rtnl);
+
+        if_loopback = (int) if_nametoindex("lo");
+        assert_se(if_loopback > 0);
+
+        test_async(if_loopback);
+
+        test_pipe(if_loopback);
+
+        test_event_loop(if_loopback);
+
+        test_link_configure(rtnl, if_loopback);
+
+        test_get_addresses(rtnl);
+
+        test_message_link_bridge(rtnl);
+
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
+        assert_se(m);
+
+        assert_se(sd_netlink_message_get_type(m, &type) >= 0);
+        assert_se(type == RTM_GETLINK);
+
+        assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
+
+        assert_se(sd_netlink_call(rtnl, m, 0, &r) == 1);
+        assert_se(sd_netlink_message_get_type(r, &type) >= 0);
+        assert_se(type == RTM_NEWLINK);
+
+        assert_se((r = sd_netlink_message_unref(r)) == NULL);
+
+        assert_se(sd_netlink_call(rtnl, m, -1, &r) == -EPERM);
+        assert_se((m = sd_netlink_message_unref(m)) == NULL);
+        assert_se((r = sd_netlink_message_unref(r)) == NULL);
+
+        test_link_get(rtnl, if_loopback);
+        test_address_get(rtnl, if_loopback);
+
+        assert_se(sd_netlink_flush(rtnl) >= 0);
+        assert_se((m = sd_netlink_message_unref(m)) == NULL);
+        assert_se((r = sd_netlink_message_unref(r)) == NULL);
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+
+        return EXIT_SUCCESS;
+}
diff --git a/src/libsystemd/sd-rtnl/Makefile b/src/libsystemd/sd-rtnl/Makefile
deleted file mode 120000
index 94aaae2..0000000
--- a/src/libsystemd/sd-rtnl/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile
\ No newline at end of file
diff --git a/src/libsystemd/sd-rtnl/local-addresses.c b/src/libsystemd/sd-rtnl/local-addresses.c
deleted file mode 100644
index f05cbf1..0000000
--- a/src/libsystemd/sd-rtnl/local-addresses.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2008-2011 Lennart Poettering
-  Copyright 2014 Tom Gundersen
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-rtnl.h"
-#include "rtnl-util.h"
-#include "macro.h"
-#include "local-addresses.h"
-
-static int address_compare(const void *_a, const void *_b) {
-        const struct local_address *a = _a, *b = _b;
-
-        /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
-
-        if (a->family == AF_INET && b->family == AF_INET6)
-                return -1;
-        if (a->family == AF_INET6 && b->family == AF_INET)
-                return 1;
-
-        if (a->scope < b->scope)
-                return -1;
-        if (a->scope > b->scope)
-                return 1;
-
-        if (a->metric < b->metric)
-                return -1;
-        if (a->metric > b->metric)
-                return 1;
-
-        if (a->ifindex < b->ifindex)
-                return -1;
-        if (a->ifindex > b->ifindex)
-                return 1;
-
-        return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
-}
-
-int local_addresses(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_free_ struct local_address *list = NULL;
-        size_t n_list = 0, n_allocated = 0;
-        sd_rtnl_message *m;
-        int r;
-
-        assert(ret);
-
-        if (context)
-                rtnl = sd_rtnl_ref(context);
-        else {
-                r = sd_rtnl_open(&rtnl);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_call(rtnl, req, 0, &reply);
-        if (r < 0)
-                return r;
-
-        for (m = reply; m; m = sd_rtnl_message_next(m)) {
-                struct local_address *a;
-                unsigned char flags;
-                uint16_t type;
-                int ifi, family;
-
-                r = sd_rtnl_message_get_errno(m);
-                if (r < 0)
-                        return r;
-
-                r = sd_rtnl_message_get_type(m, &type);
-                if (r < 0)
-                        return r;
-                if (type != RTM_NEWADDR)
-                        continue;
-
-                r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
-                if (r < 0)
-                        return r;
-                if (ifindex > 0 && ifi != ifindex)
-                        continue;
-
-                r = sd_rtnl_message_addr_get_family(m, &family);
-                if (r < 0)
-                        return r;
-                if (af != AF_UNSPEC && af != family)
-                        continue;
-
-                r = sd_rtnl_message_addr_get_flags(m, &flags);
-                if (r < 0)
-                        return r;
-                if (flags & IFA_F_DEPRECATED)
-                        continue;
-
-                if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
-                        return -ENOMEM;
-
-                a = list + n_list;
-
-                r = sd_rtnl_message_addr_get_scope(m, &a->scope);
-                if (r < 0)
-                        return r;
-
-                if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
-                        continue;
-
-                switch (family) {
-
-                case AF_INET:
-                        r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
-                        if (r < 0) {
-                                r = sd_rtnl_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
-                                if (r < 0)
-                                        continue;
-                        }
-                        break;
-
-                case AF_INET6:
-                        r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
-                        if (r < 0) {
-                                r = sd_rtnl_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
-                                if (r < 0)
-                                        continue;
-                        }
-                        break;
-
-                default:
-                        continue;
-                }
-
-                a->ifindex = ifi;
-                a->family = family;
-
-                n_list++;
-        };
-
-        if (n_list > 0)
-                qsort(list, n_list, sizeof(struct local_address), address_compare);
-
-        *ret = list;
-        list = NULL;
-
-        return (int) n_list;
-}
-
-int local_gateways(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_free_ struct local_address *list = NULL;
-        sd_rtnl_message *m = NULL;
-        size_t n_list = 0, n_allocated = 0;
-        int r;
-
-        assert(ret);
-
-        if (context)
-                rtnl = sd_rtnl_ref(context);
-        else {
-                r = sd_rtnl_open(&rtnl);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_message_request_dump(req, true);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_call(rtnl, req, 0, &reply);
-        if (r < 0)
-                return r;
-
-        for (m = reply; m; m = sd_rtnl_message_next(m)) {
-                struct local_address *a;
-                uint16_t type;
-                unsigned char dst_len, src_len;
-                uint32_t ifi;
-                int family;
-
-                r = sd_rtnl_message_get_errno(m);
-                if (r < 0)
-                        return r;
-
-                r = sd_rtnl_message_get_type(m, &type);
-                if (r < 0)
-                        return r;
-                if (type != RTM_NEWROUTE)
-                        continue;
-
-                /* We only care for default routes */
-                r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
-                if (r < 0)
-                        return r;
-                if (dst_len != 0)
-                        continue;
-
-                r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
-                if (r < 0)
-                        return r;
-                if (src_len != 0)
-                        continue;
-
-                r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
-                if (r < 0)
-                        return r;
-                if (ifindex > 0 && (int) ifi != ifindex)
-                        continue;
-
-                r = sd_rtnl_message_route_get_family(m, &family);
-                if (r < 0)
-                        return r;
-                if (af != AF_UNSPEC && af != family)
-                        continue;
-
-                if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
-                        return -ENOMEM;
-
-                a = list + n_list;
-
-                switch (family) {
-                case AF_INET:
-                        r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
-                        if (r < 0)
-                                continue;
-
-                        break;
-                case AF_INET6:
-                        r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
-                        if (r < 0)
-                                continue;
-
-                        break;
-                default:
-                        continue;
-                }
-
-                sd_rtnl_message_read_u32(m, RTA_PRIORITY, &a->metric);
-
-                a->ifindex = ifi;
-                a->family = family;
-
-                n_list++;
-        }
-
-        if (n_list > 0)
-                qsort(list, n_list, sizeof(struct local_address), address_compare);
-
-        *ret = list;
-        list = NULL;
-
-        return (int) n_list;
-}
diff --git a/src/libsystemd/sd-rtnl/local-addresses.h b/src/libsystemd/sd-rtnl/local-addresses.h
deleted file mode 100644
index bdc28d3..0000000
--- a/src/libsystemd/sd-rtnl/local-addresses.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
-  This file is part of systemd.
-
-  Copyright 2008-2011 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-#include "sd-rtnl.h"
-#include "in-addr-util.h"
-
-struct local_address {
-        int family, ifindex;
-        unsigned char scope;
-        uint32_t metric;
-        union in_addr_union address;
-};
-
-int local_addresses(sd_rtnl *rtnl, int ifindex, int af, struct local_address **ret);
-
-int local_gateways(sd_rtnl *rtnl, int ifindex, int af, struct local_address **ret);
diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h
deleted file mode 100644
index 05b88b1..0000000
--- a/src/libsystemd/sd-rtnl/rtnl-internal.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <linux/netlink.h>
-
-#include "refcnt.h"
-#include "prioq.h"
-#include "list.h"
-
-#include "sd-rtnl.h"
-
-#include "rtnl-types.h"
-
-#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
-
-#define RTNL_WQUEUE_MAX 1024
-#define RTNL_RQUEUE_MAX 64*1024
-
-#define RTNL_CONTAINER_DEPTH 32
-
-struct reply_callback {
-        sd_rtnl_message_handler_t callback;
-        void *userdata;
-        usec_t timeout;
-        uint64_t serial;
-        unsigned prioq_idx;
-};
-
-struct match_callback {
-        sd_rtnl_message_handler_t callback;
-        uint16_t type;
-        void *userdata;
-
-        LIST_FIELDS(struct match_callback, match_callbacks);
-};
-
-struct sd_rtnl {
-        RefCount n_ref;
-
-        int fd;
-
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sockaddr;
-
-        sd_rtnl_message **rqueue;
-        unsigned rqueue_size;
-        size_t rqueue_allocated;
-
-        sd_rtnl_message **rqueue_partial;
-        unsigned rqueue_partial_size;
-        size_t rqueue_partial_allocated;
-
-        sd_rtnl_message **wqueue;
-        unsigned wqueue_size;
-        size_t wqueue_allocated;
-
-        struct nlmsghdr *rbuffer;
-        size_t rbuffer_allocated;
-
-        bool processing:1;
-
-        uint32_t serial;
-
-        struct Prioq *reply_callbacks_prioq;
-        Hashmap *reply_callbacks;
-
-        LIST_HEAD(struct match_callback, match_callbacks);
-
-        pid_t original_pid;
-
-        sd_event_source *io_event_source;
-        sd_event_source *time_event_source;
-        sd_event_source *exit_event_source;
-        sd_event *event;
-};
-
-struct sd_rtnl_message {
-        RefCount n_ref;
-
-        sd_rtnl *rtnl;
-
-        struct nlmsghdr *hdr;
-        const struct NLTypeSystem *(container_type_system[RTNL_CONTAINER_DEPTH]); /* the type of the container and all its parents */
-        size_t container_offsets[RTNL_CONTAINER_DEPTH]; /* offset from hdr to each container's start */
-        unsigned n_containers; /* number of containers */
-        size_t next_rta_offset; /* offset from hdr to next rta */
-        size_t *rta_offset_tb[RTNL_CONTAINER_DEPTH];
-        unsigned short rta_tb_size[RTNL_CONTAINER_DEPTH];
-        bool sealed:1;
-        bool broadcast:1;
-
-        sd_rtnl_message *next; /* next in a chain of multi-part messages */
-};
-
-int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type);
-
-int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m);
-int socket_read_message(sd_rtnl *nl);
-
-int rtnl_rqueue_make_room(sd_rtnl *rtnl);
-int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl);
-
-int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data);
-int rtnl_message_parse(sd_rtnl_message *m,
-                       size_t **rta_offset_tb,
-                       unsigned short *rta_tb_size,
-                       int max,
-                       struct rtattr *rta,
-                       unsigned int rt_len);
-
-/* Make sure callbacks don't destroy the rtnl connection */
-#define RTNL_DONT_DESTROY(rtnl) \
-        _cleanup_rtnl_unref_ _unused_ sd_rtnl *_dont_destroy_##rtnl = sd_rtnl_ref(rtnl)
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
deleted file mode 100644
index 79e67f6..0000000
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ /dev/null
@@ -1,1699 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <unistd.h>
-
-#include "util.h"
-#include "socket-util.h"
-#include "formats-util.h"
-#include "refcnt.h"
-#include "missing.h"
-
-#include "sd-rtnl.h"
-#include "rtnl-util.h"
-#include "rtnl-internal.h"
-#include "rtnl-types.h"
-
-#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
-#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
-
-#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
-
-static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
-        sd_rtnl_message *m;
-
-        assert_return(ret, -EINVAL);
-
-        /* Note that 'rtnl' is currently unused, if we start using it internally
-           we must take care to avoid problems due to mutual references between
-           buses and their queued messages. See sd-bus.
-         */
-
-        m = new0(sd_rtnl_message, 1);
-        if (!m)
-                return -ENOMEM;
-
-        m->n_ref = REFCNT_INIT;
-
-        m->sealed = false;
-
-        *ret = m;
-
-        return 0;
-}
-
-int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        const NLType *nl_type;
-        size_t size;
-        int r;
-
-        r = type_system_get_type(NULL, &nl_type, type);
-        if (r < 0)
-                return r;
-
-        r = message_new_empty(rtnl, &m);
-        if (r < 0)
-                return r;
-
-        size = NLMSG_SPACE(nl_type->size);
-
-        assert(size >= sizeof(struct nlmsghdr));
-        m->hdr = malloc0(size);
-        if (!m->hdr)
-                return -ENOMEM;
-
-        m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-
-        m->container_type_system[0] = nl_type->type_system;
-        m->hdr->nlmsg_len = size;
-        m->hdr->nlmsg_type = type;
-
-        *ret = m;
-        m = NULL;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
-            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
-                return -ERANGE;
-
-        rtm->rtm_dst_len = prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
-            (rtm->rtm_family == AF_INET6 && prefixlen > 128))
-                return -ERANGE;
-
-        rtm->rtm_src_len = prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        rtm->rtm_scope = scope;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(family, -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        *family = rtm->rtm_family;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(dst_len, -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        *dst_len = rtm->rtm_dst_len;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len) {
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(src_len, -EINVAL);
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        *src_len = rtm->rtm_src_len;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
-                              uint16_t nlmsg_type, int rtm_family,
-                              unsigned char rtm_protocol) {
-        struct rtmsg *rtm;
-        int r;
-
-        assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
-        assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
-                      rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_NEWROUTE)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
-
-        rtm = NLMSG_DATA((*ret)->hdr);
-
-        rtm->rtm_family = rtm_family;
-        rtm->rtm_scope = RT_SCOPE_UNIVERSE;
-        rtm->rtm_type = RTN_UNICAST;
-        rtm->rtm_table = RT_TABLE_MAIN;
-        rtm->rtm_protocol = rtm_protocol;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_set_flags(sd_rtnl_message *m, uint8_t flags) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        ndm->ndm_flags |= flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_set_state(sd_rtnl_message *m, uint16_t state) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        ndm->ndm_state |= state;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_flags(sd_rtnl_message *m, uint8_t *flags) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        *flags = ndm->ndm_flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_state(sd_rtnl_message *m, uint16_t *state) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-        *state = ndm->ndm_state;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(family, -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-
-        *family = ndm->ndm_family;
-
-        return 0;
-}
-
-int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *index) {
-        struct ndmsg *ndm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(index, -EINVAL);
-
-        ndm = NLMSG_DATA(m->hdr);
-
-        *index = ndm->ndm_ifindex;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
-        struct ndmsg *ndm;
-        int r;
-
-        assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
-        assert_return(ndm_family == AF_INET  ||
-                      ndm_family == AF_INET6 ||
-                      ndm_family == PF_BRIDGE, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_NEWNEIGH)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
-
-        ndm = NLMSG_DATA((*ret)->hdr);
-
-        ndm->ndm_family = ndm_family;
-        ndm->ndm_ifindex = index;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(change, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_flags = flags;
-        ifi->ifi_change = change;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_type = type;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_family = family;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
-                             uint16_t nlmsg_type, int index) {
-        struct ifinfomsg *ifi;
-        int r;
-
-        assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
-        assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_NEWLINK)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
-
-        ifi = NLMSG_DATA((*ret)->hdr);
-
-        ifi->ifi_family = AF_UNSPEC;
-        ifi->ifi_index = index;
-
-        return 0;
-}
-
-int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(m->hdr->nlmsg_type == RTM_GETLINK  ||
-                      m->hdr->nlmsg_type == RTM_GETADDR  ||
-                      m->hdr->nlmsg_type == RTM_GETROUTE ||
-                      m->hdr->nlmsg_type == RTM_GETNEIGH,
-                      -EINVAL);
-
-        if (dump)
-                m->hdr->nlmsg_flags |= NLM_F_DUMP;
-        else
-                m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
-            (ifa->ifa_family == AF_INET6 && prefixlen > 128))
-                return -ERANGE;
-
-        ifa->ifa_prefixlen = prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        ifa->ifa_flags = flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        ifa->ifa_scope = scope;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, int *family) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(family, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *family = ifa->ifa_family;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(prefixlen, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *prefixlen = ifa->ifa_prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(scope, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *scope = ifa->ifa_scope;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(flags, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *flags = ifa->ifa_flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
-        struct ifaddrmsg *ifa;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(ifindex, -EINVAL);
-
-        ifa = NLMSG_DATA(m->hdr);
-
-        *ifindex = ifa->ifa_index;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
-                             uint16_t nlmsg_type, int index,
-                             int family) {
-        struct ifaddrmsg *ifa;
-        int r;
-
-        assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
-        assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
-                      index > 0, -EINVAL);
-        assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
-                      family == AF_INET || family == AF_INET6, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(rtnl, ret, nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (nlmsg_type == RTM_GETADDR)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
-
-        ifa = NLMSG_DATA((*ret)->hdr);
-
-        ifa->ifa_index = index;
-        ifa->ifa_family = family;
-        if (family == AF_INET)
-                ifa->ifa_prefixlen = 32;
-        else if (family == AF_INET6)
-                ifa->ifa_prefixlen = 128;
-
-        return 0;
-}
-
-int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
-                             int index, int family) {
-        int r;
-
-        r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
-        if (r < 0)
-                return r;
-
-        (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
-
-        return 0;
-}
-
-sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
-        if (m)
-                assert_se(REFCNT_INC(m->n_ref) >= 2);
-
-        return m;
-}
-
-sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
-        if (m && REFCNT_DEC(m->n_ref) == 0) {
-                unsigned i;
-
-                free(m->hdr);
-
-                for (i = 0; i <= m->n_containers; i++)
-                        free(m->rta_offset_tb[i]);
-
-                sd_rtnl_message_unref(m->next);
-
-                free(m);
-        }
-
-        return NULL;
-}
-
-int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
-        assert_return(m, -EINVAL);
-        assert_return(type, -EINVAL);
-
-        *type = m->hdr->nlmsg_type;
-
-        return 0;
-}
-
-int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family) {
-        assert_return(m, -EINVAL);
-        assert_return(family, -EINVAL);
-
-        assert(m->hdr);
-
-        if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
-                struct ifinfomsg *ifi;
-
-                ifi = NLMSG_DATA(m->hdr);
-
-                *family = ifi->ifi_family;
-
-                return 0;
-        } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
-                struct rtmsg *rtm;
-
-                rtm = NLMSG_DATA(m->hdr);
-
-                *family = rtm->rtm_family;
-
-                return 0;
-        } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
-                struct ndmsg *ndm;
-
-                ndm = NLMSG_DATA(m->hdr);
-
-                *family = ndm->ndm_family;
-
-                return 0;
-        } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
-                struct ifaddrmsg *ifa;
-
-                ifa = NLMSG_DATA(m->hdr);
-
-                *family = ifa->ifa_family;
-
-                return 0;
-        }
-
-        return -EOPNOTSUPP;
-}
-
-int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
-        assert_return(m, -EINVAL);
-
-        return m->broadcast;
-}
-
-int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(ifindex, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *ifindex = ifi->ifi_index;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(flags, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *flags = ifi->ifi_flags;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(type, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *type = ifi->ifi_type;
-
-        return 0;
-}
-
-/* If successful the updated message will be correctly aligned, if
-   unsuccessful the old message is untouched. */
-static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
-        uint32_t rta_length;
-        size_t message_length, padding_length;
-        struct nlmsghdr *new_hdr;
-        struct rtattr *rta;
-        char *padding;
-        unsigned i;
-        int offset;
-
-        assert(m);
-        assert(m->hdr);
-        assert(!m->sealed);
-        assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
-        assert(!data || data_length);
-
-        /* get offset of the new attribute */
-        offset = m->hdr->nlmsg_len;
-
-        /* get the size of the new rta attribute (with padding at the end) */
-        rta_length = RTA_LENGTH(data_length);
-
-        /* get the new message size (with padding at the end) */
-        message_length = offset + RTA_ALIGN(rta_length);
-
-        /* realloc to fit the new attribute */
-        new_hdr = realloc(m->hdr, message_length);
-        if (!new_hdr)
-                return -ENOMEM;
-        m->hdr = new_hdr;
-
-        /* get pointer to the attribute we are about to add */
-        rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
-
-        /* if we are inside containers, extend them */
-        for (i = 0; i < m->n_containers; i++)
-                GET_CONTAINER(m, i)->rta_len += message_length - offset;
-
-        /* fill in the attribute */
-        rta->rta_type = type;
-        rta->rta_len = rta_length;
-        if (data)
-                /* we don't deal with the case where the user lies about the type
-                 * and gives us too little data (so don't do that)
-                 */
-                padding = mempcpy(RTA_DATA(rta), data, data_length);
-        else {
-                /* if no data was passed, make sure we still initialize the padding
-                   note that we can have data_length > 0 (used by some containers) */
-                padding = RTA_DATA(rta);
-        }
-
-        /* make sure also the padding at the end of the message is initialized */
-        padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
-        memzero(padding, padding_length);
-
-        /* update message size */
-        m->hdr->nlmsg_len = message_length;
-
-        return offset;
-}
-
-static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
-        const NLType *type;
-        int r;
-
-        r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
-        if (r < 0)
-                return r;
-
-        if (type->type != data_type)
-                return -EINVAL;
-
-        return type->size;
-}
-
-int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
-        size_t length, size;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(data, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_STRING);
-        if (r < 0)
-                return r;
-        else
-                size = (size_t)r;
-
-        if (size) {
-                length = strnlen(data, size+1);
-                if (length > size)
-                        return -EINVAL;
-        } else
-                length = strlen(data);
-
-        r = add_rtattr(m, type, data, length + 1);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-
-        r = message_attribute_has_type(m, type, NLA_U8);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, &data, sizeof(uint8_t));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-
-int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-
-        r = message_attribute_has_type(m, type, NLA_U16);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, &data, sizeof(uint16_t));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-
-        r = message_attribute_has_type(m, type, NLA_U32);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, &data, sizeof(uint32_t));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(data, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, data, sizeof(struct in_addr));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(data, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, data, sizeof(struct in6_addr));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(data, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, data, ETH_ALEN);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(info, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
-        size_t size;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
-
-        r = message_attribute_has_type(m, type, NLA_NESTED);
-        if (r < 0) {
-                const NLTypeSystemUnion *type_system_union;
-                int family;
-
-                r = message_attribute_has_type(m, type, NLA_UNION);
-                if (r < 0)
-                        return r;
-                size = (size_t) r;
-
-                r = sd_rtnl_message_get_family(m, &family);
-                if (r < 0)
-                        return r;
-
-                r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
-                if (r < 0)
-                        return r;
-
-                r = type_system_union_protocol_get_type_system(type_system_union,
-                                                               &m->container_type_system[m->n_containers + 1],
-                                                               family);
-                if (r < 0)
-                        return r;
-        } else {
-                size = (size_t)r;
-
-                r = type_system_get_type_system(m->container_type_system[m->n_containers],
-                                                &m->container_type_system[m->n_containers + 1],
-                                                type);
-                if (r < 0)
-                        return r;
-        }
-
-        r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
-        if (r < 0)
-                return r;
-
-        m->container_offsets[m->n_containers ++] = r;
-
-        return 0;
-}
-
-int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
-        const NLTypeSystemUnion *type_system_union;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-
-        r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
-        if (r < 0)
-                return r;
-
-        r = type_system_union_get_type_system(type_system_union,
-                                              &m->container_type_system[m->n_containers + 1],
-                                              key);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_message_append_string(m, type_system_union->match, key);
-        if (r < 0)
-                return r;
-
-        /* do we evere need non-null size */
-        r = add_rtattr(m, type, NULL, 0);
-        if (r < 0)
-                return r;
-
-        m->container_offsets[m->n_containers ++] = r;
-
-        return 0;
-}
-
-
-int sd_rtnl_message_close_container(sd_rtnl_message *m) {
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(m->n_containers > 0, -EINVAL);
-
-        m->container_type_system[m->n_containers] = NULL;
-        m->n_containers --;
-
-        return 0;
-}
-
-int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
-        struct rtattr *rta;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(data, -EINVAL);
-        assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
-        assert(m->rta_offset_tb[m->n_containers]);
-        assert(type < m->rta_tb_size[m->n_containers]);
-
-        if(!m->rta_offset_tb[m->n_containers][type])
-                return -ENODATA;
-
-        rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
-
-        *data = RTA_DATA(rta);
-
-        return RTA_PAYLOAD(rta);
-}
-
-int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_STRING);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if (strnlen(attr_data, r) >= (size_t) r)
-                return -EIO;
-
-        if (data)
-                *data = (const char *) attr_data;
-
-        return 0;
-}
-
-int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_U8);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if ((size_t) r < sizeof(uint8_t))
-                return -EIO;
-
-        if (data)
-                *data = *(uint8_t *) attr_data;
-
-        return 0;
-}
-
-int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_U16);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if ((size_t) r < sizeof(uint16_t))
-                return -EIO;
-
-        if (data)
-                *data = *(uint16_t *) attr_data;
-
-        return 0;
-}
-
-int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_U32);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if ((size_t)r < sizeof(uint32_t))
-                return -EIO;
-
-        if (data)
-                *data = *(uint32_t *) attr_data;
-
-        return 0;
-}
-
-int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if ((size_t)r < sizeof(struct ether_addr))
-                return -EIO;
-
-        if (data)
-                memcpy(data, attr_data, sizeof(struct ether_addr));
-
-        return 0;
-}
-
-int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if ((size_t)r < sizeof(struct ifa_cacheinfo))
-                return -EIO;
-
-        if (info)
-                memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
-
-        return 0;
-}
-
-int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if ((size_t)r < sizeof(struct in_addr))
-                return -EIO;
-
-        if (data)
-                memcpy(data, attr_data, sizeof(struct in_addr));
-
-        return 0;
-}
-
-int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
-        int r;
-        void *attr_data;
-
-        assert_return(m, -EINVAL);
-
-        r = message_attribute_has_type(m, type, NLA_IN_ADDR);
-        if (r < 0)
-                return r;
-
-        r = rtnl_message_read_internal(m, type, &attr_data);
-        if (r < 0)
-                return r;
-        else if ((size_t)r < sizeof(struct in6_addr))
-                return -EIO;
-
-        if (data)
-                memcpy(data, attr_data, sizeof(struct in6_addr));
-
-        return 0;
-}
-
-int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
-        const NLType *nl_type;
-        const NLTypeSystem *type_system;
-        void *container;
-        size_t size;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
-
-        r = type_system_get_type(m->container_type_system[m->n_containers],
-                                 &nl_type,
-                                 type);
-        if (r < 0)
-                return r;
-
-        if (nl_type->type == NLA_NESTED) {
-                r = type_system_get_type_system(m->container_type_system[m->n_containers],
-                                                &type_system,
-                                                type);
-                if (r < 0)
-                        return r;
-        } else if (nl_type->type == NLA_UNION) {
-                const NLTypeSystemUnion *type_system_union;
-
-                r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
-                                                      &type_system_union,
-                                                      type);
-                if (r < 0)
-                        return r;
-
-                switch (type_system_union->match_type) {
-                case NL_MATCH_SIBLING:
-                {
-                        const char *key;
-
-                        r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
-                        if (r < 0)
-                                return r;
-
-                        r = type_system_union_get_type_system(type_system_union,
-                                                              &type_system,
-                                                              key);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                }
-                case NL_MATCH_PROTOCOL:
-                {
-                        int family;
-
-                        r = sd_rtnl_message_get_family(m, &family);
-                        if (r < 0)
-                                return r;
-
-                        r = type_system_union_protocol_get_type_system(type_system_union,
-                                                                       &type_system,
-                                                                       family);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                }
-                default:
-                        assert_not_reached("sd-rtnl: invalid type system union type");
-                }
-        } else
-                return -EINVAL;
-
-        r = rtnl_message_read_internal(m, type, &container);
-        if (r < 0)
-                return r;
-        else
-                size = (size_t)r;
-
-        m->n_containers ++;
-
-        r = rtnl_message_parse(m,
-                               &m->rta_offset_tb[m->n_containers],
-                               &m->rta_tb_size[m->n_containers],
-                               type_system->max,
-                               container,
-                               size);
-        if (r < 0) {
-                m->n_containers --;
-                return r;
-        }
-
-        m->container_type_system[m->n_containers] = type_system;
-
-        return 0;
-}
-
-int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EINVAL);
-        assert_return(m->n_containers > 0, -EINVAL);
-
-        free(m->rta_offset_tb[m->n_containers]);
-        m->rta_offset_tb[m->n_containers] = NULL;
-        m->container_type_system[m->n_containers] = NULL;
-
-        m->n_containers --;
-
-        return 0;
-}
-
-uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
-        assert(m);
-        assert(m->hdr);
-
-        return m->hdr->nlmsg_seq;
-}
-
-int sd_rtnl_message_is_error(sd_rtnl_message *m) {
-        assert_return(m, 0);
-        assert_return(m->hdr, 0);
-
-        return m->hdr->nlmsg_type == NLMSG_ERROR;
-}
-
-int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
-        struct nlmsgerr *err;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-
-        if (!sd_rtnl_message_is_error(m))
-                return 0;
-
-        err = NLMSG_DATA(m->hdr);
-
-        return err->error;
-}
-
-int rtnl_message_parse(sd_rtnl_message *m,
-                       size_t **rta_offset_tb,
-                       unsigned short *rta_tb_size,
-                       int max,
-                       struct rtattr *rta,
-                       unsigned int rt_len) {
-        unsigned short type;
-        size_t *tb;
-
-        tb = new0(size_t, max + 1);
-        if(!tb)
-                return -ENOMEM;
-
-        *rta_tb_size = max + 1;
-
-        for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
-                type = RTA_TYPE(rta);
-
-                /* if the kernel is newer than the headers we used
-                   when building, we ignore out-of-range attributes
-                 */
-                if (type > max)
-                        continue;
-
-                if (tb[type])
-                        log_debug("rtnl: message parse - overwriting repeated attribute");
-
-                tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
-        }
-
-        *rta_offset_tb = tb;
-
-        return 0;
-}
-
-/* returns the number of bytes sent, or a negative error code */
-int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } addr = {
-                .nl.nl_family = AF_NETLINK,
-        };
-        ssize_t k;
-
-        assert(nl);
-        assert(m);
-        assert(m->hdr);
-
-        k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
-                        0, &addr.sa, sizeof(addr));
-        if (k < 0)
-                return (errno == EAGAIN) ? 0 : -errno;
-
-        return k;
-}
-
-static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
-        union sockaddr_union sender;
-        uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
-        struct msghdr msg = {
-                .msg_iov = iov,
-                .msg_iovlen = 1,
-                .msg_name = &sender,
-                .msg_namelen = sizeof(sender),
-                .msg_control = cmsg_buffer,
-                .msg_controllen = sizeof(cmsg_buffer),
-        };
-        struct cmsghdr *cmsg;
-        uint32_t group = 0;
-        int r;
-
-        assert(fd >= 0);
-        assert(iov);
-
-        r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
-        if (r < 0) {
-                /* no data */
-                if (errno == ENOBUFS)
-                        log_debug("rtnl: kernel receive buffer overrun");
-                else if (errno == EAGAIN)
-                        log_debug("rtnl: no data in socket");
-
-                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
-        }
-
-        if (sender.nl.nl_pid != 0) {
-                /* not from the kernel, ignore */
-                log_debug("rtnl: ignoring message from portid %"PRIu32, sender.nl.nl_pid);
-
-                if (peek) {
-                        /* drop the message */
-                        r = recvmsg(fd, &msg, 0);
-                        if (r < 0)
-                                return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
-                }
-
-                return 0;
-        }
-
-        CMSG_FOREACH(cmsg, &msg) {
-                if (cmsg->cmsg_level == SOL_NETLINK &&
-                    cmsg->cmsg_type == NETLINK_PKTINFO &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
-                        struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
-
-                        /* multi-cast group */
-                        group = pktinfo->group;
-                }
-        }
-
-        if (_group)
-                *_group = group;
-
-        return r;
-}
-
-/* On success, the number of bytes received is returned and *ret points to the received message
- * which has a valid header and the correct size.
- * If nothing useful was received 0 is returned.
- * On failure, a negative error code is returned.
- */
-int socket_read_message(sd_rtnl *rtnl) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
-        struct iovec iov = {};
-        uint32_t group = 0;
-        bool multi_part = false, done = false;
-        struct nlmsghdr *new_msg;
-        size_t len;
-        int r;
-        unsigned i = 0;
-
-        assert(rtnl);
-        assert(rtnl->rbuffer);
-        assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
-
-        /* read nothing, just get the pending message size */
-        r = socket_recv_message(rtnl->fd, &iov, NULL, true);
-        if (r <= 0)
-                return r;
-        else
-                len = (size_t)r;
-
-        /* make room for the pending message */
-        if (!greedy_realloc((void **)&rtnl->rbuffer,
-                            &rtnl->rbuffer_allocated,
-                            len, sizeof(uint8_t)))
-                return -ENOMEM;
-
-        iov.iov_base = rtnl->rbuffer;
-        iov.iov_len = rtnl->rbuffer_allocated;
-
-        /* read the pending message */
-        r = socket_recv_message(rtnl->fd, &iov, &group, false);
-        if (r <= 0)
-                return r;
-        else
-                len = (size_t)r;
-
-        if (len > rtnl->rbuffer_allocated)
-                /* message did not fit in read buffer */
-                return -EIO;
-
-        if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
-                multi_part = true;
-
-                for (i = 0; i < rtnl->rqueue_partial_size; i++) {
-                        if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
-                            rtnl->rbuffer->nlmsg_seq) {
-                                first = rtnl->rqueue_partial[i];
-                                break;
-                        }
-                }
-        }
-
-        for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-                const NLType *nl_type;
-
-                if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
-                        /* not broadcast and not for us */
-                        continue;
-
-                if (new_msg->nlmsg_type == NLMSG_NOOP)
-                        /* silently drop noop messages */
-                        continue;
-
-                if (new_msg->nlmsg_type == NLMSG_DONE) {
-                        /* finished reading multi-part message */
-                        done = true;
-
-                        /* if first is not defined, put NLMSG_DONE into the receive queue. */
-                        if (first)
-                                continue;
-                }
-
-                /* check that we support this message type */
-                r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
-                if (r < 0) {
-                        if (r == -EOPNOTSUPP)
-                                log_debug("sd-rtnl: ignored message with unknown type: %i",
-                                          new_msg->nlmsg_type);
-
-                        continue;
-                }
-
-                /* check that the size matches the message type */
-                if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
-                        log_debug("sd-rtnl: message larger than expected, dropping");
-                        continue;
-                }
-
-                r = message_new_empty(rtnl, &m);
-                if (r < 0)
-                        return r;
-
-                m->broadcast = !!group;
-
-                m->hdr = memdup(new_msg, new_msg->nlmsg_len);
-                if (!m->hdr)
-                        return -ENOMEM;
-
-                /* seal and parse the top-level message */
-                r = sd_rtnl_message_rewind(m);
-                if (r < 0)
-                        return r;
-
-                /* push the message onto the multi-part message stack */
-                if (first)
-                        m->next = first;
-                first = m;
-                m = NULL;
-        }
-
-        if (len)
-                log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
-
-        if (!first)
-                return 0;
-
-        if (!multi_part || done) {
-                /* we got a complete message, push it on the read queue */
-                r = rtnl_rqueue_make_room(rtnl);
-                if (r < 0)
-                        return r;
-
-                rtnl->rqueue[rtnl->rqueue_size ++] = first;
-                first = NULL;
-
-                if (multi_part && (i < rtnl->rqueue_partial_size)) {
-                        /* remove the message form the partial read queue */
-                        memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
-                                sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
-                        rtnl->rqueue_partial_size --;
-                }
-
-                return 1;
-        } else {
-                /* we only got a partial multi-part message, push it on the
-                   partial read queue */
-                if (i < rtnl->rqueue_partial_size) {
-                        rtnl->rqueue_partial[i] = first;
-                } else {
-                        r = rtnl_rqueue_partial_make_room(rtnl);
-                        if (r < 0)
-                                return r;
-
-                        rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
-                }
-                first = NULL;
-
-                return 0;
-        }
-}
-
-int sd_rtnl_message_rewind(sd_rtnl_message *m) {
-        const NLType *type;
-        unsigned i;
-        int r;
-
-        assert_return(m, -EINVAL);
-
-        /* don't allow appending to message once parsed */
-        if (!m->sealed)
-                rtnl_message_seal(m);
-
-        for (i = 1; i <= m->n_containers; i++) {
-                free(m->rta_offset_tb[i]);
-                m->rta_offset_tb[i] = NULL;
-                m->rta_tb_size[i] = 0;
-                m->container_type_system[i] = NULL;
-        }
-
-        m->n_containers = 0;
-
-        if (m->rta_offset_tb[0]) {
-                /* top-level attributes have already been parsed */
-                return 0;
-        }
-
-        assert(m->hdr);
-
-        r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
-        if (r < 0)
-                return r;
-
-        if (type->type == NLA_NESTED) {
-                const NLTypeSystem *type_system = type->type_system;
-
-                assert(type_system);
-
-                m->container_type_system[0] = type_system;
-
-                r = rtnl_message_parse(m,
-                                       &m->rta_offset_tb[m->n_containers],
-                                       &m->rta_tb_size[m->n_containers],
-                                       type_system->max,
-                                       (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
-                                                        NLMSG_ALIGN(type->size)),
-                                       NLMSG_PAYLOAD(m->hdr, type->size));
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-void rtnl_message_seal(sd_rtnl_message *m) {
-        assert(m);
-        assert(!m->sealed);
-
-        m->sealed = true;
-}
-
-sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
-        assert_return(m, NULL);
-
-        return m->next;
-}
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.c b/src/libsystemd/sd-rtnl/rtnl-types.c
deleted file mode 100644
index d211684..0000000
--- a/src/libsystemd/sd-rtnl/rtnl-types.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdint.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/in6.h>
-#include <linux/veth.h>
-#include <linux/if_bridge.h>
-#include <linux/if_addr.h>
-#include <linux/if.h>
-
-#include <linux/ip.h>
-#include <linux/if_link.h>
-#include <linux/if_tunnel.h>
-
-#include "macro.h"
-#include "util.h"
-
-#include "rtnl-types.h"
-#include "missing.h"
-
-static const NLTypeSystem rtnl_link_type_system;
-
-static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
-        [VETH_INFO_PEER]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
-};
-
-static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
-        [IFLA_IPVLAN_MODE]  = { .type = NLA_U16 },
-};
-
-static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
-        [IFLA_MACVLAN_MODE]  = { .type = NLA_U32 },
-        [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
-};
-
-static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
-        [IFLA_BRIDGE_FLAGS]     = { .type = NLA_U16 },
-        [IFLA_BRIDGE_MODE]      = { .type = NLA_U16 },
-/*
-        [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
-                                    .len = sizeof(struct bridge_vlan_info), },
-*/
-};
-
-static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
-        [IFLA_VLAN_ID]          = { .type = NLA_U16 },
-/*
-        [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
-        [IFLA_VLAN_EGRESS_QOS]  = { .type = NLA_NESTED },
-        [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
-*/
-        [IFLA_VLAN_PROTOCOL]    = { .type = NLA_U16 },
-};
-
-static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
-        [IFLA_VXLAN_ID] = { .type = NLA_U32 },
-        [IFLA_VXLAN_GROUP] = {.type = NLA_IN_ADDR },
-        [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
-        [IFLA_VXLAN_LOCAL] = { .type = NLA_U32},
-        [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
-        [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
-        [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
-        [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
-        [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
-        [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_U32},
-        [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
-        [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
-        [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
-        [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
-};
-
-static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
-        [BOND_ARP_TARGETS_0]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_1]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_2]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_3]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_4]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_5]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_6]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_7]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_8]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_9]        = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_10]       = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_11]       = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_12]       = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_13]       = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_14]       = { .type = NLA_U32 },
-        [BOND_ARP_TARGETS_MAX]      = { .type = NLA_U32 },
-};
-
-static const NLTypeSystem rtnl_bond_arp_type_system = {
-        .max = ELEMENTSOF(rtnl_bond_arp_target_types) - 1,
-        .types = rtnl_bond_arp_target_types,
-};
-
-static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
-        [IFLA_BOND_MODE]                = { .type = NLA_U8 },
-        [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NLA_U32 },
-        [IFLA_BOND_MIIMON]              = { .type = NLA_U32 },
-        [IFLA_BOND_UPDELAY]             = { .type = NLA_U32 },
-        [IFLA_BOND_DOWNDELAY]           = { .type = NLA_U32 },
-        [IFLA_BOND_USE_CARRIER]         = { .type = NLA_U8 },
-        [IFLA_BOND_ARP_INTERVAL]        = { .type = NLA_U32 },
-        [IFLA_BOND_ARP_IP_TARGET]       = { .type = NLA_NESTED, .type_system = &rtnl_bond_arp_type_system },
-        [IFLA_BOND_ARP_VALIDATE]        = { .type = NLA_U32 },
-        [IFLA_BOND_ARP_ALL_TARGETS]     = { .type = NLA_U32 },
-        [IFLA_BOND_PRIMARY]             = { .type = NLA_U32 },
-        [IFLA_BOND_PRIMARY_RESELECT]    = { .type = NLA_U8 },
-        [IFLA_BOND_FAIL_OVER_MAC]       = { .type = NLA_U8 },
-        [IFLA_BOND_XMIT_HASH_POLICY]    = { .type = NLA_U8 },
-        [IFLA_BOND_RESEND_IGMP]         = { .type = NLA_U32 },
-        [IFLA_BOND_NUM_PEER_NOTIF]      = { .type = NLA_U8 },
-        [IFLA_BOND_ALL_SLAVES_ACTIVE]   = { .type = NLA_U8 },
-        [IFLA_BOND_MIN_LINKS]           = { .type = NLA_U32 },
-        [IFLA_BOND_LP_INTERVAL]         = { .type = NLA_U32 },
-        [IFLA_BOND_PACKETS_PER_SLAVE]   = { .type = NLA_U32 },
-        [IFLA_BOND_AD_LACP_RATE]        = { .type = NLA_U8 },
-        [IFLA_BOND_AD_SELECT]           = { .type = NLA_U8 },
-        [IFLA_BOND_AD_INFO]             = { .type = NLA_NESTED },
-};
-
-static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
-        [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
-        [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
-        [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
-        [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
-        [IFLA_IPTUN_TOS]                 = { .type = NLA_U8 },
-        [IFLA_IPTUN_PMTUDISC]            = { .type = NLA_U8 },
-        [IFLA_IPTUN_FLAGS]               = { .type = NLA_U16 },
-        [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
-        [IFLA_IPTUN_6RD_PREFIX]          = { .type = NLA_IN_ADDR },
-        [IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NLA_U32 },
-        [IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NLA_U16 },
-        [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
-};
-
-static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
-        [IFLA_GRE_LINK]     = { .type = NLA_U32 },
-        [IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
-        [IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
-        [IFLA_GRE_IKEY]     = { .type = NLA_U32 },
-        [IFLA_GRE_OKEY]     = { .type = NLA_U32 },
-        [IFLA_GRE_LOCAL]    = { .type = NLA_IN_ADDR },
-        [IFLA_GRE_REMOTE]   = { .type = NLA_IN_ADDR },
-        [IFLA_GRE_TTL]      = { .type = NLA_U8 },
-        [IFLA_GRE_TOS]      = { .type = NLA_U8 },
-        [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
-};
-
-static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
-        [IFLA_VTI_LINK]         = { .type = NLA_U32 },
-        [IFLA_VTI_IKEY]         = { .type = NLA_U32 },
-        [IFLA_VTI_OKEY]         = { .type = NLA_U32 },
-        [IFLA_VTI_LOCAL]        = { .type = NLA_IN_ADDR  },
-        [IFLA_VTI_REMOTE]       = { .type = NLA_IN_ADDR  },
-};
-
-static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
-        [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
-        [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
-        [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
-        [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
-        [IFLA_IPTUN_FLAGS]               = { .type = NLA_U32 },
-        [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
-        [IFLA_IPTUN_ENCAP_LIMIT]         = { .type = NLA_U8 },
-        [IFLA_IPTUN_FLOWINFO]            = { .type = NLA_U32},
-};
-
-/* these strings must match the .kind entries in the kernel */
-static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
-        [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
-        [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
-        [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
-        [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
-        [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
-        [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
-        [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
-        [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
-        [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
-        [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
-        [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
-        [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = "ip6gre",
-        [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap",
-        [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
-        [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
-        [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
-        [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
-
-static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
-        [NL_UNION_LINK_INFO_DATA_BOND] =        { .max = ELEMENTSOF(rtnl_link_info_data_bond_types) - 1,
-                                                  .types = rtnl_link_info_data_bond_types },
-        [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .max = ELEMENTSOF(rtnl_link_info_data_bridge_types) - 1,
-                                                  .types = rtnl_link_info_data_bridge_types },
-        [NL_UNION_LINK_INFO_DATA_VLAN] =        { .max = ELEMENTSOF(rtnl_link_info_data_vlan_types) - 1,
-                                                  .types = rtnl_link_info_data_vlan_types },
-        [NL_UNION_LINK_INFO_DATA_VETH] =        { .max = ELEMENTSOF(rtnl_link_info_data_veth_types) - 1,
-                                                  .types = rtnl_link_info_data_veth_types },
-        [NL_UNION_LINK_INFO_DATA_MACVLAN] =     { .max = ELEMENTSOF(rtnl_link_info_data_macvlan_types) - 1,
-                                                  .types = rtnl_link_info_data_macvlan_types },
-        [NL_UNION_LINK_INFO_DATA_IPVLAN] =      { .max = ELEMENTSOF(rtnl_link_info_data_ipvlan_types) - 1,
-                                                  .types = rtnl_link_info_data_ipvlan_types },
-        [NL_UNION_LINK_INFO_DATA_VXLAN] =       { .max = ELEMENTSOF(rtnl_link_info_data_vxlan_types) - 1,
-                                                  .types = rtnl_link_info_data_vxlan_types },
-        [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
-                                                  .types = rtnl_link_info_data_iptun_types },
-        [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
-                                                    .types = rtnl_link_info_data_ipgre_types },
-        [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
-                                                    .types = rtnl_link_info_data_ipgre_types },
-        [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
-                                                    .types = rtnl_link_info_data_ipgre_types },
-        [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
-                                                    .types = rtnl_link_info_data_ipgre_types },
-        [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
-                                                  .types = rtnl_link_info_data_iptun_types },
-        [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
-                                                  .types = rtnl_link_info_data_ipvti_types },
-        [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
-                                                  .types = rtnl_link_info_data_ipvti_types },
-        [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types) - 1,
-                                                     .types = rtnl_link_info_data_ip6tnl_types },
-
-};
-
-static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
-        .num = _NL_UNION_LINK_INFO_DATA_MAX,
-        .lookup = nl_union_link_info_data_from_string,
-        .type_systems = rtnl_link_info_data_type_systems,
-        .match_type = NL_MATCH_SIBLING,
-        .match = IFLA_INFO_KIND,
-};
-
-static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
-        [IFLA_INFO_KIND]        = { .type = NLA_STRING },
-        [IFLA_INFO_DATA]        = { .type = NLA_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
-/*
-        [IFLA_INFO_XSTATS],
-        [IFLA_INFO_SLAVE_KIND]  = { .type = NLA_STRING },
-        [IFLA_INFO_SLAVE_DATA]  = { .type = NLA_NESTED },
-*/
-};
-
-static const NLTypeSystem rtnl_link_info_type_system = {
-        .max = ELEMENTSOF(rtnl_link_info_types) - 1,
-        .types = rtnl_link_info_types,
-};
-
-static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
-        [IFLA_BRPORT_STATE]     = { .type = NLA_U8 },
-        [IFLA_BRPORT_COST]      = { .type = NLA_U32 },
-        [IFLA_BRPORT_PRIORITY]  = { .type = NLA_U16 },
-        [IFLA_BRPORT_MODE]      = { .type = NLA_U8 },
-        [IFLA_BRPORT_GUARD]     = { .type = NLA_U8 },
-        [IFLA_BRPORT_PROTECT]   = { .type = NLA_U8 },
-        [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
-        [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
-};
-
-static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
-        [AF_BRIDGE] =   { .max = ELEMENTSOF(rtnl_prot_info_bridge_port_types) - 1,
-                          .types = rtnl_prot_info_bridge_port_types },
-};
-
-static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
-        .num = AF_MAX,
-        .type_systems = rtnl_prot_info_type_systems,
-        .match_type = NL_MATCH_PROTOCOL,
-};
-
-static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
-        [IFLA_INET6_FLAGS]              = { .type = NLA_U32 },
-/*
-        IFLA_INET6_CONF,
-        IFLA_INET6_STATS,
-        IFLA_INET6_MCAST,
-        IFLA_INET6_CACHEINFO,
-        IFLA_INET6_ICMP6STATS,
-*/
-        [IFLA_INET6_TOKEN]              = { .type = NLA_IN_ADDR },
-        [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NLA_U8 },
-};
-
-static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
-        .max = ELEMENTSOF(rtnl_af_spec_inet6_types) - 1,
-        .types = rtnl_af_spec_inet6_types,
-};
-
-static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
-        [AF_INET6] =    { .type = NLA_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
-};
-
-static const NLTypeSystem rtnl_af_spec_type_system = {
-        .max = ELEMENTSOF(rtnl_af_spec_types) - 1,
-        .types = rtnl_af_spec_types,
-};
-
-static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
-        [IFLA_ADDRESS]          = { .type = NLA_ETHER_ADDR, },
-        [IFLA_BROADCAST]        = { .type = NLA_ETHER_ADDR, },
-        [IFLA_IFNAME]           = { .type = NLA_STRING, .size = IFNAMSIZ - 1, },
-        [IFLA_MTU]              = { .type = NLA_U32 },
-        [IFLA_LINK]             = { .type = NLA_U32 },
-/*
-        [IFLA_QDISC],
-        [IFLA_STATS],
-        [IFLA_COST],
-        [IFLA_PRIORITY],
-*/
-        [IFLA_MASTER]           = { .type = NLA_U32 },
-/*
-        [IFLA_WIRELESS],
-*/
-        [IFLA_PROTINFO]         = { .type = NLA_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
-        [IFLA_TXQLEN]           = { .type = NLA_U32 },
-/*
-        [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
-*/
-        [IFLA_WEIGHT]           = { .type = NLA_U32 },
-        [IFLA_OPERSTATE]        = { .type = NLA_U8 },
-        [IFLA_LINKMODE]         = { .type = NLA_U8 },
-        [IFLA_LINKINFO]         = { .type = NLA_NESTED, .type_system = &rtnl_link_info_type_system },
-        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
-        [IFLA_IFALIAS]          = { .type = NLA_STRING, .size = IFALIASZ - 1 },
-/*
-        [IFLA_NUM_VF],
-        [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED, },
-        [IFLA_STATS64],
-        [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
-        [IFLA_PORT_SELF]        = { .type = NLA_NESTED },
-*/
-        [IFLA_AF_SPEC]          = { .type = NLA_NESTED, .type_system = &rtnl_af_spec_type_system },
-/*
-        [IFLA_VF_PORTS],
-        [IFLA_PORT_SELF],
-        [IFLA_AF_SPEC],
-*/
-        [IFLA_GROUP]            = { .type = NLA_U32 },
-        [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
-        [IFLA_EXT_MASK]         = { .type = NLA_U32 },
-        [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
-        [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
-        [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
-        [IFLA_CARRIER]          = { .type = NLA_U8 },
-/*
-        [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
-*/
-};
-
-static const NLTypeSystem rtnl_link_type_system = {
-        .max = ELEMENTSOF(rtnl_link_types) - 1,
-        .types = rtnl_link_types,
-};
-
-/* IFA_FLAGS was defined in kernel 3.14, but we still support older
- * kernels where IFA_MAX is lower. */
-static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
-        [IFA_ADDRESS]           = { .type = NLA_IN_ADDR },
-        [IFA_LOCAL]             = { .type = NLA_IN_ADDR },
-        [IFA_LABEL]             = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
-        [IFA_BROADCAST]         = { .type = NLA_IN_ADDR }, /* 6? */
-        [IFA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
-/*
-        [IFA_ANYCAST],
-        [IFA_MULTICAST],
-*/
-        [IFA_FLAGS]             = { .type = NLA_U32 },
-};
-
-static const NLTypeSystem rtnl_address_type_system = {
-        .max = ELEMENTSOF(rtnl_address_types) - 1,
-        .types = rtnl_address_types,
-};
-
-static const NLType rtnl_route_types[RTA_MAX + 1] = {
-        [RTA_DST]               = { .type = NLA_IN_ADDR }, /* 6? */
-        [RTA_SRC]               = { .type = NLA_IN_ADDR }, /* 6? */
-        [RTA_IIF]               = { .type = NLA_U32 },
-        [RTA_OIF]               = { .type = NLA_U32 },
-        [RTA_GATEWAY]           = { .type = NLA_IN_ADDR },
-        [RTA_PRIORITY]          = { .type = NLA_U32 },
-        [RTA_PREFSRC]           = { .type = NLA_IN_ADDR }, /* 6? */
-/*
-        [RTA_METRICS]           = { .type = NLA_NESTED },
-        [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
-*/
-        [RTA_FLOW]              = { .type = NLA_U32 }, /* 6? */
-/*
-        RTA_CACHEINFO,
-        RTA_TABLE,
-        RTA_MARK,
-        RTA_MFC_STATS,
-*/
-};
-
-static const NLTypeSystem rtnl_route_type_system = {
-        .max = ELEMENTSOF(rtnl_route_types) - 1,
-        .types = rtnl_route_types,
-};
-
-static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
-        [NDA_DST]               = { .type = NLA_IN_ADDR },
-        [NDA_LLADDR]            = { .type = NLA_ETHER_ADDR },
-        [NDA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
-        [NDA_PROBES]            = { .type = NLA_U32 },
-        [NDA_VLAN]              = { .type = NLA_U16 },
-        [NDA_PORT]              = { .type = NLA_U16 },
-        [NDA_VNI]               = { .type = NLA_U32 },
-        [NDA_IFINDEX]           = { .type = NLA_U32 },
-};
-
-static const NLTypeSystem rtnl_neigh_type_system = {
-        .max = ELEMENTSOF(rtnl_neigh_types) - 1,
-        .types = rtnl_neigh_types,
-};
-
-static const NLType rtnl_types[RTM_MAX + 1] = {
-        [NLMSG_DONE]   = { .type = NLA_META, .size = 0 },
-        [NLMSG_ERROR]  = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
-        [RTM_NEWLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
-        [RTM_DELLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
-        [RTM_GETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
-        [RTM_SETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
-        [RTM_NEWADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
-        [RTM_DELADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
-        [RTM_GETADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
-        [RTM_NEWROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
-        [RTM_DELROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
-        [RTM_GETROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
-        [RTM_NEWNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
-        [RTM_DELNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
-        [RTM_GETNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
-};
-
-const NLTypeSystem rtnl_type_system = {
-        .max = ELEMENTSOF(rtnl_types) - 1,
-        .types = rtnl_types,
-};
-
-int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
-        const NLType *nl_type;
-
-        assert(ret);
-
-        if (!type_system)
-                type_system = &rtnl_type_system;
-
-        assert(type_system->types);
-
-        if (type > type_system->max)
-                return -EOPNOTSUPP;
-
-        nl_type = &type_system->types[type];
-
-        if (nl_type->type == NLA_UNSPEC)
-                return -EOPNOTSUPP;
-
-        *ret = nl_type;
-
-        return 0;
-}
-
-int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
-        const NLType *nl_type;
-        int r;
-
-        assert(ret);
-
-        r = type_system_get_type(type_system, &nl_type, type);
-        if (r < 0)
-                return r;
-
-        assert(nl_type->type == NLA_NESTED);
-        assert(nl_type->type_system);
-
-        *ret = nl_type->type_system;
-
-        return 0;
-}
-
-int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
-        const NLType *nl_type;
-        int r;
-
-        assert(ret);
-
-        r = type_system_get_type(type_system, &nl_type, type);
-        if (r < 0)
-                return r;
-
-        assert(nl_type->type == NLA_UNION);
-        assert(nl_type->type_system_union);
-
-        *ret = nl_type->type_system_union;
-
-        return 0;
-}
-
-int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
-        int type;
-
-        assert(type_system_union);
-        assert(type_system_union->match_type == NL_MATCH_SIBLING);
-        assert(type_system_union->lookup);
-        assert(type_system_union->type_systems);
-        assert(ret);
-        assert(key);
-
-        type = type_system_union->lookup(key);
-        if (type < 0)
-                return -EOPNOTSUPP;
-
-        assert(type < type_system_union->num);
-
-        *ret = &type_system_union->type_systems[type];
-
-        return 0;
-}
-
-int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
-        const NLTypeSystem *type_system;
-
-        assert(type_system_union);
-        assert(type_system_union->type_systems);
-        assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
-        assert(ret);
-
-        if (protocol >= type_system_union->num)
-                return -EOPNOTSUPP;
-
-        type_system = &type_system_union->type_systems[protocol];
-        if (type_system->max == 0)
-                return -EOPNOTSUPP;
-
-        *ret = type_system;
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.h b/src/libsystemd/sd-rtnl/rtnl-types.h
deleted file mode 100644
index de1544b..0000000
--- a/src/libsystemd/sd-rtnl/rtnl-types.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-enum {
-        NLA_UNSPEC,
-        NLA_META,
-        NLA_U8,
-        NLA_U16,
-        NLA_U32,
-        NLA_U64,
-        NLA_STRING,
-        NLA_IN_ADDR,
-        NLA_ETHER_ADDR,
-        NLA_CACHE_INFO,
-        NLA_NESTED,
-        NLA_UNION,
-};
-
-typedef enum NLMatchType {
-        NL_MATCH_SIBLING,
-        NL_MATCH_PROTOCOL,
-} NLMatchType;
-
-typedef struct NLTypeSystemUnion NLTypeSystemUnion;
-typedef struct NLTypeSystem NLTypeSystem;
-typedef struct NLType NLType;
-
-struct NLTypeSystemUnion {
-        int num;
-        NLMatchType match_type;
-        uint16_t match;
-        int (*lookup)(const char *);
-        const NLTypeSystem *type_systems;
-};
-
-struct NLTypeSystem {
-        uint16_t max;
-        const NLType *types;
-};
-
-struct NLType {
-        uint16_t type;
-        size_t size;
-        const NLTypeSystem *type_system;
-        const NLTypeSystemUnion *type_system_union;
-};
-
-int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
-int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
-int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
-int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key);
-int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol);
-
-typedef enum NLUnionLinkInfoData {
-        NL_UNION_LINK_INFO_DATA_BOND,
-        NL_UNION_LINK_INFO_DATA_BRIDGE,
-        NL_UNION_LINK_INFO_DATA_VLAN,
-        NL_UNION_LINK_INFO_DATA_VETH,
-        NL_UNION_LINK_INFO_DATA_DUMMY,
-        NL_UNION_LINK_INFO_DATA_MACVLAN,
-        NL_UNION_LINK_INFO_DATA_IPVLAN,
-        NL_UNION_LINK_INFO_DATA_VXLAN,
-        NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_SIT_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_VTI_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL,
-        NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
-        _NL_UNION_LINK_INFO_DATA_MAX,
-        _NL_UNION_LINK_INFO_DATA_INVALID = -1
-} NLUnionLinkInfoData;
-
-const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_;
-NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
-
-/* Maximum ARP IP target defined in kernel */
-#define BOND_MAX_ARP_TARGETS    16
-
-typedef enum BondArpTargets {
-        BOND_ARP_TARGETS_0,
-        BOND_ARP_TARGETS_1,
-        BOND_ARP_TARGETS_2,
-        BOND_ARP_TARGETS_3,
-        BOND_ARP_TARGETS_4,
-        BOND_ARP_TARGETS_5,
-        BOND_ARP_TARGETS_6,
-        BOND_ARP_TARGETS_7,
-        BOND_ARP_TARGETS_8,
-        BOND_ARP_TARGETS_9,
-        BOND_ARP_TARGETS_10,
-        BOND_ARP_TARGETS_11,
-        BOND_ARP_TARGETS_12,
-        BOND_ARP_TARGETS_13,
-        BOND_ARP_TARGETS_14,
-        BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS,
-} BondArpTargets;
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c
deleted file mode 100644
index c2b1a5c..0000000
--- a/src/libsystemd/sd-rtnl/rtnl-util.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-#include "sd-rtnl.h"
-
-#include "rtnl-util.h"
-#include "rtnl-internal.h"
-
-int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
-        int r;
-
-        assert(rtnl);
-        assert(ifindex > 0);
-        assert(name);
-
-        if (!*rtnl) {
-                r = sd_rtnl_open(rtnl);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_message_append_string(message, IFLA_IFNAME, name);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_call(*rtnl, message, 0, NULL);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias,
-                             const struct ether_addr *mac, unsigned mtu) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
-        int r;
-
-        assert(rtnl);
-        assert(ifindex > 0);
-
-        if (!alias && !mac && mtu == 0)
-                return 0;
-
-        if (!*rtnl) {
-                r = sd_rtnl_open(rtnl);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
-        if (r < 0)
-                return r;
-
-        if (alias) {
-                r = sd_rtnl_message_append_string(message, IFLA_IFALIAS, alias);
-                if (r < 0)
-                        return r;
-        }
-
-        if (mac) {
-                r = sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, mac);
-                if (r < 0)
-                        return r;
-        }
-
-        if (mtu > 0) {
-                r = sd_rtnl_message_append_u32(message, IFLA_MTU, mtu);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_rtnl_call(*rtnl, message, 0, NULL);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
-        struct nlmsgerr *err;
-        int r;
-
-        assert(error <= 0);
-
-        r = message_new(NULL, ret, NLMSG_ERROR);
-        if (r < 0)
-                return r;
-
-        (*ret)->hdr->nlmsg_seq = serial;
-
-        err = NLMSG_DATA((*ret)->hdr);
-
-        err->error = error;
-
-        return 0;
-}
-
-bool rtnl_message_type_is_neigh(uint16_t type) {
-        switch (type) {
-                case RTM_NEWNEIGH:
-                case RTM_GETNEIGH:
-                case RTM_DELNEIGH:
-                        return true;
-                default:
-                        return false;
-        }
-}
-
-bool rtnl_message_type_is_route(uint16_t type) {
-        switch (type) {
-                case RTM_NEWROUTE:
-                case RTM_GETROUTE:
-                case RTM_DELROUTE:
-                        return true;
-                default:
-                        return false;
-        }
-}
-
-bool rtnl_message_type_is_link(uint16_t type) {
-        switch (type) {
-                case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_GETLINK:
-                case RTM_DELLINK:
-                        return true;
-                default:
-                        return false;
-        }
-}
-
-bool rtnl_message_type_is_addr(uint16_t type) {
-        switch (type) {
-                case RTM_NEWADDR:
-                case RTM_GETADDR:
-                case RTM_DELADDR:
-                        return true;
-                default:
-                        return false;
-        }
-}
-
-int rtnl_log_parse_error(int r) {
-        return log_error_errno(r, "Failed to parse netlink message: %m");
-}
-
-int rtnl_log_create_error(int r) {
-        return log_error_errno(r, "Failed to create netlink message: %m");
-}
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h
deleted file mode 100644
index 9e4bdb8..0000000
--- a/src/libsystemd/sd-rtnl/rtnl-util.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-#include "util.h"
-#include "sd-rtnl.h"
-
-int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret);
-uint32_t rtnl_message_get_serial(sd_rtnl_message *m);
-void rtnl_message_seal(sd_rtnl_message *m);
-
-bool rtnl_message_type_is_link(uint16_t type);
-bool rtnl_message_type_is_addr(uint16_t type);
-bool rtnl_message_type_is_route(uint16_t type);
-bool rtnl_message_type_is_neigh(uint16_t type);
-
-int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name);
-int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
-
-int rtnl_log_parse_error(int r);
-int rtnl_log_create_error(int r);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl*, sd_rtnl_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl_message*, sd_rtnl_message_unref);
-
-#define _cleanup_rtnl_unref_ _cleanup_(sd_rtnl_unrefp)
-#define _cleanup_rtnl_message_unref_ _cleanup_(sd_rtnl_message_unrefp)
diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c
deleted file mode 100644
index 5bafc28..0000000
--- a/src/libsystemd/sd-rtnl/sd-rtnl.c
+++ /dev/null
@@ -1,1056 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <poll.h>
-
-#include "missing.h"
-#include "macro.h"
-#include "util.h"
-#include "hashmap.h"
-
-#include "sd-rtnl.h"
-#include "rtnl-internal.h"
-#include "rtnl-util.h"
-
-static int sd_rtnl_new(sd_rtnl **ret) {
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-
-        assert_return(ret, -EINVAL);
-
-        rtnl = new0(sd_rtnl, 1);
-        if (!rtnl)
-                return -ENOMEM;
-
-        rtnl->n_ref = REFCNT_INIT;
-
-        rtnl->fd = -1;
-
-        rtnl->sockaddr.nl.nl_family = AF_NETLINK;
-
-        rtnl->original_pid = getpid();
-
-        LIST_HEAD_INIT(rtnl->match_callbacks);
-
-        /* We guarantee that wqueue always has space for at least
-         * one entry */
-        if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
-                return -ENOMEM;
-
-        /* We guarantee that the read buffer has at least space for
-         * a message header */
-        if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
-                            sizeof(struct nlmsghdr), sizeof(uint8_t)))
-                return -ENOMEM;
-
-        /* Change notification responses have sequence 0, so we must
-         * start our request sequence numbers at 1, or we may confuse our
-         * responses with notifications from the kernel */
-        rtnl->serial = 1;
-
-        *ret = rtnl;
-        rtnl = NULL;
-
-        return 0;
-}
-
-int sd_rtnl_new_from_netlink(sd_rtnl **ret, int fd) {
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        socklen_t addrlen;
-        int r;
-
-        assert_return(ret, -EINVAL);
-
-        r = sd_rtnl_new(&rtnl);
-        if (r < 0)
-                return r;
-
-        addrlen = sizeof(rtnl->sockaddr);
-
-        r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
-        if (r < 0)
-                return -errno;
-
-        rtnl->fd = fd;
-
-        *ret = rtnl;
-        rtnl = NULL;
-
-        return 0;
-}
-
-static bool rtnl_pid_changed(sd_rtnl *rtnl) {
-        assert(rtnl);
-
-        /* We don't support people creating an rtnl connection and
-         * keeping it around over a fork(). Let's complain. */
-
-        return rtnl->original_pid != getpid();
-}
-
-int sd_rtnl_open_fd(sd_rtnl **ret, int fd) {
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        socklen_t addrlen;
-        int r, one = 1;
-
-        assert_return(ret, -EINVAL);
-        assert_return(fd >= 0, -EINVAL);
-
-        r = sd_rtnl_new(&rtnl);
-        if (r < 0)
-                return r;
-
-        r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
-        if (r < 0)
-                return -errno;
-
-        addrlen = sizeof(rtnl->sockaddr);
-
-        r = bind(fd, &rtnl->sockaddr.sa, addrlen);
-        /* ignore EINVAL to allow opening an already bound socket */
-        if (r < 0 && errno != EINVAL)
-                return -errno;
-
-        r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
-        if (r < 0)
-                return -errno;
-
-        rtnl->fd = fd;
-
-        *ret = rtnl;
-        rtnl = NULL;
-
-        return 0;
-}
-
-int sd_rtnl_open(sd_rtnl **ret) {
-        _cleanup_close_ int fd = -1;
-        int r;
-
-        fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
-        if (fd < 0)
-                return -errno;
-
-        r = sd_rtnl_open_fd(ret, fd);
-        if (r < 0)
-                return r;
-
-        fd = -1;
-
-        return 0;
-}
-
-static int rtnl_join_broadcast_group(sd_rtnl *rtnl, unsigned group) {
-        int r;
-
-        assert(rtnl);
-        assert(rtnl->fd >= 0);
-        assert(group > 0);
-
-        r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
-        return fd_inc_rcvbuf(rtnl->fd, size);
-}
-
-sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
-        assert_return(rtnl, NULL);
-        assert_return(!rtnl_pid_changed(rtnl), NULL);
-
-        if (rtnl)
-                assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
-
-        return rtnl;
-}
-
-sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
-        if (!rtnl)
-                return NULL;
-
-        assert_return(!rtnl_pid_changed(rtnl), NULL);
-
-        if (REFCNT_DEC(rtnl->n_ref) == 0) {
-                struct match_callback *f;
-                unsigned i;
-
-                for (i = 0; i < rtnl->rqueue_size; i++)
-                        sd_rtnl_message_unref(rtnl->rqueue[i]);
-                free(rtnl->rqueue);
-
-                for (i = 0; i < rtnl->rqueue_partial_size; i++)
-                        sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
-                free(rtnl->rqueue_partial);
-
-                for (i = 0; i < rtnl->wqueue_size; i++)
-                        sd_rtnl_message_unref(rtnl->wqueue[i]);
-                free(rtnl->wqueue);
-
-                free(rtnl->rbuffer);
-
-                hashmap_free_free(rtnl->reply_callbacks);
-                prioq_free(rtnl->reply_callbacks_prioq);
-
-                sd_event_source_unref(rtnl->io_event_source);
-                sd_event_source_unref(rtnl->time_event_source);
-                sd_event_source_unref(rtnl->exit_event_source);
-                sd_event_unref(rtnl->event);
-
-                while ((f = rtnl->match_callbacks)) {
-                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
-                        free(f);
-                }
-
-                safe_close(rtnl->fd);
-                free(rtnl);
-        }
-
-        return NULL;
-}
-
-static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
-        assert(rtnl);
-        assert(!rtnl_pid_changed(rtnl));
-        assert(m);
-        assert(m->hdr);
-
-        /* don't use seq == 0, as that is used for broadcasts, so we
-           would get confused by replies to such messages */
-        m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++;
-
-        rtnl_message_seal(m);
-
-        return;
-}
-
-int sd_rtnl_send(sd_rtnl *nl,
-                 sd_rtnl_message *message,
-                 uint32_t *serial) {
-        int r;
-
-        assert_return(nl, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-        assert_return(message, -EINVAL);
-        assert_return(!message->sealed, -EPERM);
-
-        rtnl_seal_message(nl, message);
-
-        if (nl->wqueue_size <= 0) {
-                /* send directly */
-                r = socket_write_message(nl, message);
-                if (r < 0)
-                        return r;
-                else if (r == 0) {
-                        /* nothing was sent, so let's put it on
-                         * the queue */
-                        nl->wqueue[0] = sd_rtnl_message_ref(message);
-                        nl->wqueue_size = 1;
-                }
-        } else {
-                /* append to queue */
-                if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
-                        log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
-                        return -ENOBUFS;
-                }
-
-                if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
-                        return -ENOMEM;
-
-                nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
-        }
-
-        if (serial)
-                *serial = rtnl_message_get_serial(message);
-
-        return 1;
-}
-
-int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
-        assert(rtnl);
-
-        if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
-                log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
-                return -ENOBUFS;
-        }
-
-        if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
-        assert(rtnl);
-
-        if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
-                log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
-                return -ENOBUFS;
-        }
-
-        if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
-                            rtnl->rqueue_partial_size + 1))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
-        int r;
-
-        assert(rtnl);
-        assert(message);
-
-        if (rtnl->rqueue_size <= 0) {
-                /* Try to read a new message */
-                r = socket_read_message(rtnl);
-                if (r <= 0)
-                        return r;
-        }
-
-        /* Dispatch a queued message */
-        *message = rtnl->rqueue[0];
-        rtnl->rqueue_size --;
-        memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
-
-        return 1;
-}
-
-static int dispatch_wqueue(sd_rtnl *rtnl) {
-        int r, ret = 0;
-
-        assert(rtnl);
-
-        while (rtnl->wqueue_size > 0) {
-                r = socket_write_message(rtnl, rtnl->wqueue[0]);
-                if (r < 0)
-                        return r;
-                else if (r == 0)
-                        /* Didn't do anything this time */
-                        return ret;
-                else {
-                        /* see equivalent in sd-bus.c */
-                        sd_rtnl_message_unref(rtnl->wqueue[0]);
-                        rtnl->wqueue_size --;
-                        memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
-
-                        ret = 1;
-                }
-        }
-
-        return ret;
-}
-
-static int process_timeout(sd_rtnl *rtnl) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        struct reply_callback *c;
-        usec_t n;
-        int r;
-
-        assert(rtnl);
-
-        c = prioq_peek(rtnl->reply_callbacks_prioq);
-        if (!c)
-                return 0;
-
-        n = now(CLOCK_MONOTONIC);
-        if (c->timeout > n)
-                return 0;
-
-        r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
-        if (r < 0)
-                return r;
-
-        assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
-        hashmap_remove(rtnl->reply_callbacks, &c->serial);
-
-        r = c->callback(rtnl, m, c->userdata);
-        if (r < 0)
-                log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
-
-        free(c);
-
-        return 1;
-}
-
-static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
-        _cleanup_free_ struct reply_callback *c = NULL;
-        uint64_t serial;
-        uint16_t type;
-        int r;
-
-        assert(rtnl);
-        assert(m);
-
-        serial = rtnl_message_get_serial(m);
-        c = hashmap_remove(rtnl->reply_callbacks, &serial);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
-
-        r = sd_rtnl_message_get_type(m, &type);
-        if (r < 0)
-                return 0;
-
-        if (type == NLMSG_DONE)
-                m = NULL;
-
-        r = c->callback(rtnl, m, c->userdata);
-        if (r < 0)
-                log_debug_errno(r, "sd-rtnl: callback failed: %m");
-
-        return 1;
-}
-
-static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
-        struct match_callback *c;
-        uint16_t type;
-        int r;
-
-        assert(rtnl);
-        assert(m);
-
-        r = sd_rtnl_message_get_type(m, &type);
-        if (r < 0)
-                return r;
-
-        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
-                if (type == c->type) {
-                        r = c->callback(rtnl, m, c->userdata);
-                        if (r != 0) {
-                                if (r < 0)
-                                        log_debug_errno(r, "sd-rtnl: match callback failed: %m");
-
-                                break;
-                        }
-                }
-        }
-
-        return 1;
-}
-
-static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        int r;
-
-        assert(rtnl);
-
-        r = process_timeout(rtnl);
-        if (r != 0)
-                goto null_message;
-
-        r = dispatch_wqueue(rtnl);
-        if (r != 0)
-                goto null_message;
-
-        r = dispatch_rqueue(rtnl, &m);
-        if (r < 0)
-                return r;
-        if (!m)
-                goto null_message;
-
-        if (sd_rtnl_message_is_broadcast(m)) {
-                r = process_match(rtnl, m);
-                if (r != 0)
-                        goto null_message;
-        } else {
-                r = process_reply(rtnl, m);
-                if (r != 0)
-                        goto null_message;
-        }
-
-        if (ret) {
-                *ret = m;
-                m = NULL;
-
-                return 1;
-        }
-
-        return 1;
-
-null_message:
-        if (r >= 0 && ret)
-                *ret = NULL;
-
-        return r;
-}
-
-int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
-        RTNL_DONT_DESTROY(rtnl);
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-        assert_return(!rtnl->processing, -EBUSY);
-
-        rtnl->processing = true;
-        r = process_running(rtnl, ret);
-        rtnl->processing = false;
-
-        return r;
-}
-
-static usec_t calc_elapse(uint64_t usec) {
-        if (usec == (uint64_t) -1)
-                return 0;
-
-        if (usec == 0)
-                usec = RTNL_DEFAULT_TIMEOUT;
-
-        return now(CLOCK_MONOTONIC) + usec;
-}
-
-static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
-        struct pollfd p[1] = {};
-        struct timespec ts;
-        usec_t m = USEC_INFINITY;
-        int r, e;
-
-        assert(rtnl);
-
-        e = sd_rtnl_get_events(rtnl);
-        if (e < 0)
-                return e;
-
-        if (need_more)
-                /* Caller wants more data, and doesn't care about
-                 * what's been read or any other timeouts. */
-                e |= POLLIN;
-        else {
-                usec_t until;
-                /* Caller wants to process if there is something to
-                 * process, but doesn't care otherwise */
-
-                r = sd_rtnl_get_timeout(rtnl, &until);
-                if (r < 0)
-                        return r;
-                if (r > 0) {
-                        usec_t nw;
-                        nw = now(CLOCK_MONOTONIC);
-                        m = until > nw ? until - nw : 0;
-                }
-        }
-
-        if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
-                m = timeout_usec;
-
-        p[0].fd = rtnl->fd;
-        p[0].events = e;
-
-        r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
-        if (r < 0)
-                return -errno;
-
-        return r > 0 ? 1 : 0;
-}
-
-int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
-        assert_return(nl, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
-        if (nl->rqueue_size > 0)
-                return 0;
-
-        return rtnl_poll(nl, false, timeout_usec);
-}
-
-static int timeout_compare(const void *a, const void *b) {
-        const struct reply_callback *x = a, *y = b;
-
-        if (x->timeout != 0 && y->timeout == 0)
-                return -1;
-
-        if (x->timeout == 0 && y->timeout != 0)
-                return 1;
-
-        if (x->timeout < y->timeout)
-                return -1;
-
-        if (x->timeout > y->timeout)
-                return 1;
-
-        return 0;
-}
-
-int sd_rtnl_call_async(sd_rtnl *nl,
-                       sd_rtnl_message *m,
-                       sd_rtnl_message_handler_t callback,
-                       void *userdata,
-                       uint64_t usec,
-                       uint32_t *serial) {
-        struct reply_callback *c;
-        uint32_t s;
-        int r, k;
-
-        assert_return(nl, -EINVAL);
-        assert_return(m, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
-        r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
-        if (r < 0)
-                return r;
-
-        if (usec != (uint64_t) -1) {
-                r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
-                if (r < 0)
-                        return r;
-        }
-
-        c = new0(struct reply_callback, 1);
-        if (!c)
-                return -ENOMEM;
-
-        c->callback = callback;
-        c->userdata = userdata;
-        c->timeout = calc_elapse(usec);
-
-        k = sd_rtnl_send(nl, m, &s);
-        if (k < 0) {
-                free(c);
-                return k;
-        }
-
-        c->serial = s;
-
-        r = hashmap_put(nl->reply_callbacks, &c->serial, c);
-        if (r < 0) {
-                free(c);
-                return r;
-        }
-
-        if (c->timeout != 0) {
-                r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
-                if (r > 0) {
-                        c->timeout = 0;
-                        sd_rtnl_call_async_cancel(nl, c->serial);
-                        return r;
-                }
-        }
-
-        if (serial)
-                *serial = s;
-
-        return k;
-}
-
-int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
-        struct reply_callback *c;
-        uint64_t s = serial;
-
-        assert_return(nl, -EINVAL);
-        assert_return(serial != 0, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
-        c = hashmap_remove(nl->reply_callbacks, &s);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
-
-        free(c);
-        return 1;
-}
-
-int sd_rtnl_call(sd_rtnl *rtnl,
-                sd_rtnl_message *message,
-                uint64_t usec,
-                sd_rtnl_message **ret) {
-        usec_t timeout;
-        uint32_t serial;
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-        assert_return(message, -EINVAL);
-
-        r = sd_rtnl_send(rtnl, message, &serial);
-        if (r < 0)
-                return r;
-
-        timeout = calc_elapse(usec);
-
-        for (;;) {
-                usec_t left;
-                unsigned i;
-
-                for (i = 0; i < rtnl->rqueue_size; i++) {
-                        uint32_t received_serial;
-
-                        received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
-
-                        if (received_serial == serial) {
-                                _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
-                                uint16_t type;
-
-                                incoming = rtnl->rqueue[i];
-
-                                /* found a match, remove from rqueue and return it */
-                                memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
-                                        sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
-                                rtnl->rqueue_size--;
-
-                                r = sd_rtnl_message_get_errno(incoming);
-                                if (r < 0)
-                                        return r;
-
-                                r = sd_rtnl_message_get_type(incoming, &type);
-                                if (r < 0)
-                                        return r;
-
-                                if (type == NLMSG_DONE) {
-                                        *ret = NULL;
-                                        return 0;
-                                }
-
-                                if (ret) {
-                                        *ret = incoming;
-                                        incoming = NULL;
-                                }
-
-                                return 1;
-                        }
-                }
-
-                r = socket_read_message(rtnl);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        /* received message, so try to process straight away */
-                        continue;
-
-                if (timeout > 0) {
-                        usec_t n;
-
-                        n = now(CLOCK_MONOTONIC);
-                        if (n >= timeout)
-                                return -ETIMEDOUT;
-
-                        left = timeout - n;
-                } else
-                        left = (uint64_t) -1;
-
-                r = rtnl_poll(rtnl, true, left);
-                if (r < 0)
-                        return r;
-                else if (r == 0)
-                        return -ETIMEDOUT;
-
-                r = dispatch_wqueue(rtnl);
-                if (r < 0)
-                        return r;
-        }
-}
-
-int sd_rtnl_flush(sd_rtnl *rtnl) {
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        if (rtnl->wqueue_size <= 0)
-                return 0;
-
-        for (;;) {
-                r = dispatch_wqueue(rtnl);
-                if (r < 0)
-                        return r;
-
-                if (rtnl->wqueue_size <= 0)
-                        return 0;
-
-                r = rtnl_poll(rtnl, false, (uint64_t) -1);
-                if (r < 0)
-                        return r;
-        }
-}
-
-int sd_rtnl_get_events(sd_rtnl *rtnl) {
-        int flags = 0;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        if (rtnl->rqueue_size <= 0)
-                flags |= POLLIN;
-        if (rtnl->wqueue_size > 0)
-                flags |= POLLOUT;
-
-        return flags;
-}
-
-int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
-        struct reply_callback *c;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(timeout_usec, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        if (rtnl->rqueue_size > 0) {
-                *timeout_usec = 0;
-                return 1;
-        }
-
-        c = prioq_peek(rtnl->reply_callbacks_prioq);
-        if (!c) {
-                *timeout_usec = (uint64_t) -1;
-                return 0;
-        }
-
-        *timeout_usec = c->timeout;
-
-        return 1;
-}
-
-static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-        int r;
-
-        assert(rtnl);
-
-        r = sd_rtnl_process(rtnl, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-        int r;
-
-        assert(rtnl);
-
-        r = sd_rtnl_process(rtnl, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int prepare_callback(sd_event_source *s, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-        int r, e;
-        usec_t until;
-
-        assert(s);
-        assert(rtnl);
-
-        e = sd_rtnl_get_events(rtnl);
-        if (e < 0)
-                return e;
-
-        r = sd_event_source_set_io_events(rtnl->io_event_source, e);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_get_timeout(rtnl, &until);
-        if (r < 0)
-                return r;
-        if (r > 0) {
-                int j;
-
-                j = sd_event_source_set_time(rtnl->time_event_source, until);
-                if (j < 0)
-                        return j;
-        }
-
-        r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int exit_callback(sd_event_source *event, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-
-        assert(event);
-
-        sd_rtnl_flush(rtnl);
-
-        return 1;
-}
-
-int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl->event, -EBUSY);
-
-        assert(!rtnl->io_event_source);
-        assert(!rtnl->time_event_source);
-
-        if (event)
-                rtnl->event = sd_event_ref(event);
-        else {
-                r = sd_event_default(&rtnl->event);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_priority(rtnl->io_event_source, priority);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_priority(rtnl->time_event_source, priority);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
-        if (r < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        sd_rtnl_detach_event(rtnl);
-        return r;
-}
-
-int sd_rtnl_detach_event(sd_rtnl *rtnl) {
-        assert_return(rtnl, -EINVAL);
-        assert_return(rtnl->event, -ENXIO);
-
-        if (rtnl->io_event_source)
-                rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
-
-        if (rtnl->time_event_source)
-                rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
-
-        if (rtnl->exit_event_source)
-                rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
-
-        if (rtnl->event)
-                rtnl->event = sd_event_unref(rtnl->event);
-
-        return 0;
-}
-
-int sd_rtnl_add_match(sd_rtnl *rtnl,
-                      uint16_t type,
-                      sd_rtnl_message_handler_t callback,
-                      void *userdata) {
-        _cleanup_free_ struct match_callback *c = NULL;
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        c = new0(struct match_callback, 1);
-        if (!c)
-                return -ENOMEM;
-
-        c->callback = callback;
-        c->type = type;
-        c->userdata = userdata;
-
-        switch (type) {
-                case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_GETLINK:
-                case RTM_DELLINK:
-                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_LINK);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                case RTM_NEWADDR:
-                case RTM_GETADDR:
-                case RTM_DELADDR:
-                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
-                        if (r < 0)
-                                return r;
-
-                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                default:
-                        return -EOPNOTSUPP;
-        }
-
-        LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
-
-        c = NULL;
-
-        return 0;
-}
-
-int sd_rtnl_remove_match(sd_rtnl *rtnl,
-                         uint16_t type,
-                         sd_rtnl_message_handler_t callback,
-                         void *userdata) {
-        struct match_callback *c;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        /* we should unsubscribe from the broadcast groups at this point, but it is not so
-           trivial for a few reasons: the refcounting is a bit of a mess and not obvious
-           how it will look like after we add genetlink support, and it is also not possible
-           to query what broadcast groups were subscribed to when we inherit the socket to get
-           the initial refcount. The latter could indeed be done for the first 32 broadcast
-           groups (which incidentally is all we currently support in .socket units anyway),
-           but we better not rely on only ever using 32 groups. */
-        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
-                if (c->callback == callback && c->type == type && c->userdata == userdata) {
-                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
-                        free(c);
-
-                        return 1;
-                }
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-rtnl/test-local-addresses.c b/src/libsystemd/sd-rtnl/test-local-addresses.c
deleted file mode 100644
index 38cbcfb..0000000
--- a/src/libsystemd/sd-rtnl/test-local-addresses.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "in-addr-util.h"
-#include "local-addresses.h"
-#include "af-list.h"
-
-static void print_local_addresses(struct local_address *a, unsigned n) {
-        unsigned i;
-
-        for (i = 0; i < n; i++) {
-                _cleanup_free_ char *b = NULL;
-
-                assert_se(in_addr_to_string(a[i].family, &a[i].address, &b) >= 0);
-                printf("%s if%i scope=%i metric=%u address=%s\n", af_to_name(a[i].family), a[i].ifindex, a[i].scope, a[i].metric, b);
-        }
-}
-
-int main(int argc, char *argv[]) {
-        struct local_address *a;
-        int n;
-
-        a = NULL;
-        n = local_addresses(NULL, 0, AF_UNSPEC, &a);
-        assert_se(n >= 0);
-
-        printf("Local Addresses:\n");
-        print_local_addresses(a, (unsigned) n);
-        free(a);
-
-        a = NULL;
-        n = local_gateways(NULL, 0, AF_UNSPEC, &a);
-        assert_se(n >= 0);
-
-        printf("Local Gateways:\n");
-        print_local_addresses(a, (unsigned) n);
-        free(a);
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c
deleted file mode 100644
index 94b1cb7..0000000
--- a/src/libsystemd/sd-rtnl/test-rtnl.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <netinet/ether.h>
-#include <net/if.h>
-
-#include "util.h"
-#include "macro.h"
-#include "sd-rtnl.h"
-#include "socket-util.h"
-#include "rtnl-util.h"
-#include "event-util.h"
-#include "missing.h"
-
-static void test_message_link_bridge(sd_rtnl *rtnl) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
-        uint32_t cost;
-
-        assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0);
-        assert_se(sd_rtnl_message_link_set_family(message, PF_BRIDGE) >= 0);
-        assert_se(sd_rtnl_message_open_container(message, IFLA_PROTINFO) >= 0);
-        assert_se(sd_rtnl_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
-        assert_se(sd_rtnl_message_close_container(message) >= 0);
-
-        assert_se(sd_rtnl_message_rewind(message) >= 0);
-
-        assert_se(sd_rtnl_message_enter_container(message, IFLA_PROTINFO) >= 0);
-        assert_se(sd_rtnl_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
-        assert_se(cost == 10);
-        assert_se(sd_rtnl_message_exit_container(message) >= 0);
-}
-
-static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
-        const char *mac = "98:fe:94:3f:c6:18", *name = "test";
-        char buffer[ETHER_ADDR_TO_STRING_MAX];
-        unsigned int mtu = 1450, mtu_out;
-        const char *name_out;
-        struct ether_addr mac_out;
-
-        /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
-        assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
-        assert_se(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
-        assert_se(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
-        assert_se(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
-
-        assert_se(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
-        assert_se(sd_rtnl_message_rewind(message) >= 0);
-
-        assert_se(sd_rtnl_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
-        assert_se(streq(name, name_out));
-
-        assert_se(sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &mac_out) >= 0);
-        assert_se(streq(mac, ether_addr_to_string(&mac_out, buffer)));
-
-        assert_se(sd_rtnl_message_read_u32(message, IFLA_MTU, &mtu_out) >= 0);
-        assert_se(mtu == mtu_out);
-}
-
-static void test_link_get(sd_rtnl *rtnl, int ifindex) {
-        sd_rtnl_message *m;
-        sd_rtnl_message *r;
-        unsigned int mtu = 1500;
-        const char *str_data;
-        uint8_t u8_data;
-        uint32_t u32_data;
-        struct ether_addr eth_data;
-
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
-        assert_se(m);
-
-        /* u8 test cases  */
-        assert_se(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
-        assert_se(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
-        assert_se(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
-
-        /* u32 test cases */
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0);
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
-
-        assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
-
-        assert_se(sd_rtnl_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
-
-        assert_se(sd_rtnl_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
-        assert_se(sd_rtnl_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
-        assert_se(sd_rtnl_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
-
-        assert_se(sd_rtnl_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
-        assert_se(sd_rtnl_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
-        assert_se(sd_rtnl_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
-        assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
-        assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
-
-        assert_se(sd_rtnl_message_read_ether_addr(r, IFLA_ADDRESS, &eth_data) == 0);
-
-        assert_se(sd_rtnl_flush(rtnl) >= 0);
-        assert_se((m = sd_rtnl_message_unref(m)) == NULL);
-        assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-}
-
-
-static void test_address_get(sd_rtnl *rtnl, int ifindex) {
-        sd_rtnl_message *m;
-        sd_rtnl_message *r;
-        struct in_addr in_data;
-        struct ifa_cacheinfo cache;
-        const char *label;
-
-        assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
-        assert_se(m);
-
-        assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
-
-        assert_se(sd_rtnl_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
-        assert_se(sd_rtnl_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
-        assert_se(sd_rtnl_message_read_string(r, IFA_LABEL, &label) == 0);
-        assert_se(sd_rtnl_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
-
-        assert_se(sd_rtnl_flush(rtnl) >= 0);
-        assert_se((m = sd_rtnl_message_unref(m)) == NULL);
-        assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-
-}
-
-static void test_route(void) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req;
-        struct in_addr addr, addr_data;
-        uint32_t index = 2, u32_data;
-        int r;
-
-        r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
-        if (r < 0) {
-                log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
-                return;
-        }
-
-        addr.s_addr = htonl(INADDR_LOOPBACK);
-
-        r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
-        if (r < 0) {
-                log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
-                return;
-        }
-
-        r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
-        if (r < 0) {
-                log_error_errno(r, "Could not append RTA_OIF attribute: %m");
-                return;
-        }
-
-        assert_se(sd_rtnl_message_rewind(req) >= 0);
-
-        assert_se(sd_rtnl_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
-        assert_se(addr_data.s_addr == addr.s_addr);
-
-        assert_se(sd_rtnl_message_read_u32(req, RTA_OIF, &u32_data) >= 0);
-        assert_se(u32_data == index);
-
-        assert_se((req = sd_rtnl_message_unref(req)) == NULL);
-}
-
-static void test_multiple(void) {
-        sd_rtnl *rtnl1, *rtnl2;
-
-        assert_se(sd_rtnl_open(&rtnl1) >= 0);
-        assert_se(sd_rtnl_open(&rtnl2) >= 0);
-
-        rtnl1 = sd_rtnl_unref(rtnl1);
-        rtnl2 = sd_rtnl_unref(rtnl2);
-}
-
-static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
-        char *ifname = userdata;
-        const char *data;
-
-        assert_se(rtnl);
-        assert_se(m);
-
-        log_info("got link info about %s", ifname);
-        free(ifname);
-
-        assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &data) >= 0);
-        assert_se(streq(data, "lo"));
-
-        return 1;
-}
-
-static void test_event_loop(int ifindex) {
-        _cleanup_event_unref_ sd_event *event = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        char *ifname;
-
-        ifname = strdup("lo2");
-        assert_se(ifname);
-
-        assert_se(sd_rtnl_open(&rtnl) >= 0);
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
-
-        assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
-
-        assert_se(sd_event_default(&event) >= 0);
-
-        assert_se(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
-
-        assert_se(sd_event_run(event, 0) >= 0);
-
-        assert_se(sd_rtnl_detach_event(rtnl) >= 0);
-
-        assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
-        int *counter = userdata;
-        int r;
-
-        (*counter) --;
-
-        r = sd_rtnl_message_get_errno(m);
-
-        log_info_errno(r, "%d left in pipe. got reply: %m", *counter);
-
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static void test_async(int ifindex) {
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
-        uint32_t serial;
-        char *ifname;
-
-        ifname = strdup("lo");
-        assert_se(ifname);
-
-        assert_se(sd_rtnl_open(&rtnl) >= 0);
-
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
-
-        assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
-
-        assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
-        assert_se(sd_rtnl_process(rtnl, &r) >= 0);
-
-        assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static void test_pipe(int ifindex) {
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
-        int counter = 0;
-
-        assert_se(sd_rtnl_open(&rtnl) >= 0);
-
-        assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
-        assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
-
-        counter ++;
-        assert_se(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
-
-        counter ++;
-        assert_se(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
-
-        while (counter > 0) {
-                assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
-                assert_se(sd_rtnl_process(rtnl, NULL) >= 0);
-        }
-
-        assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static void test_container(void) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        uint16_t u16_data;
-        uint32_t u32_data;
-        const char *string_data;
-
-        assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
-
-        assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
-        assert_se(sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
-        assert_se(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
-        assert_se(sd_rtnl_message_close_container(m) >= 0);
-        assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
-        assert_se(sd_rtnl_message_close_container(m) >= 0);
-        assert_se(sd_rtnl_message_close_container(m) == -EINVAL);
-
-        assert_se(sd_rtnl_message_rewind(m) >= 0);
-
-        assert_se(sd_rtnl_message_enter_container(m, IFLA_LINKINFO) >= 0);
-        assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
-        assert_se(streq("vlan", string_data));
-
-        assert_se(sd_rtnl_message_enter_container(m, IFLA_INFO_DATA) >= 0);
-        assert_se(sd_rtnl_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0);
-        assert_se(sd_rtnl_message_exit_container(m) >= 0);
-
-        assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
-        assert_se(streq("vlan", string_data));
-        assert_se(sd_rtnl_message_exit_container(m) >= 0);
-
-        assert_se(sd_rtnl_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0);
-
-        assert_se(sd_rtnl_message_exit_container(m) == -EINVAL);
-}
-
-static void test_match(void) {
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-
-        assert_se(sd_rtnl_open(&rtnl) >= 0);
-
-        assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
-        assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
-
-        assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
-        assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
-        assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
-
-        assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static void test_get_addresses(sd_rtnl *rtnl) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        sd_rtnl_message *m;
-
-        assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
-
-        assert_se(sd_rtnl_call(rtnl, req, 0, &reply) >= 0);
-
-        for (m = reply; m; m = sd_rtnl_message_next(m)) {
-                uint16_t type;
-                unsigned char scope, flags;
-                int family, ifindex;
-
-                assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
-                assert_se(type == RTM_NEWADDR);
-
-                assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0);
-                assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0);
-                assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0);
-                assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0);
-
-                assert_se(ifindex > 0);
-                assert_se(family == AF_INET || family == AF_INET6);
-
-                log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex);
-        }
-}
-
-static void test_message(void) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-
-        assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
-        assert_se(sd_rtnl_message_get_errno(m) == -ETIMEDOUT);
-}
-
-int main(void) {
-        sd_rtnl *rtnl;
-        sd_rtnl_message *m;
-        sd_rtnl_message *r;
-        const char *string_data;
-        int if_loopback;
-        uint16_t type;
-
-        test_message();
-
-        test_match();
-
-        test_multiple();
-
-        test_route();
-
-        test_container();
-
-        assert_se(sd_rtnl_open(&rtnl) >= 0);
-        assert_se(rtnl);
-
-        if_loopback = (int) if_nametoindex("lo");
-        assert_se(if_loopback > 0);
-
-        test_async(if_loopback);
-
-        test_pipe(if_loopback);
-
-        test_event_loop(if_loopback);
-
-        test_link_configure(rtnl, if_loopback);
-
-        test_get_addresses(rtnl);
-
-        test_message_link_bridge(rtnl);
-
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
-        assert_se(m);
-
-        assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
-        assert_se(type == RTM_GETLINK);
-
-        assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
-
-        assert_se(sd_rtnl_call(rtnl, m, 0, &r) == 1);
-        assert_se(sd_rtnl_message_get_type(r, &type) >= 0);
-        assert_se(type == RTM_NEWLINK);
-
-        assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-
-        assert_se(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
-        assert_se((m = sd_rtnl_message_unref(m)) == NULL);
-        assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-
-        test_link_get(rtnl, if_loopback);
-        test_address_get(rtnl, if_loopback);
-
-        assert_se(sd_rtnl_flush(rtnl) >= 0);
-        assert_se((m = sd_rtnl_message_unref(m)) == NULL);
-        assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-        assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-
-        return EXIT_SUCCESS;
-}
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 8e20f70..9d6c453 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -24,7 +24,7 @@
 #include <net/if.h>
 
 #include "sd-network.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "sd-hwdb.h"
 #include "sd-device.h"
 
@@ -33,7 +33,7 @@
 #include "util.h"
 #include "pager.h"
 #include "lldp.h"
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "device-util.h"
 #include "hwdb-util.h"
 #include "arphrd-list.h"
@@ -112,19 +112,19 @@ static int link_info_compare(const void *a, const void *b) {
         return x->ifindex - y->ifindex;
 }
 
-static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
+static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) {
         _cleanup_free_ LinkInfo *links = NULL;
         size_t size = 0, c = 0;
-        sd_rtnl_message *i;
+        sd_netlink_message *i;
         int r;
 
-        for (i = m; i; i = sd_rtnl_message_next(i)) {
+        for (i = m; i; i = sd_netlink_message_next(i)) {
                 const char *name;
                 unsigned iftype;
                 uint16_t type;
                 int ifindex;
 
-                r = sd_rtnl_message_get_type(i, &type);
+                r = sd_netlink_message_get_type(i, &type);
                 if (r < 0)
                         return r;
 
@@ -135,7 +135,7 @@ static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
                 if (r < 0)
                         return r;
 
-                r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
+                r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
                 if (r < 0)
                         return r;
 
@@ -192,14 +192,14 @@ static void setup_state_to_color(const char *state, const char **on, const char
 }
 
 static int list_links(int argc, char *argv[], void *userdata) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         _cleanup_free_ LinkInfo *links = NULL;
         int r, c, i;
 
         pager_open_if_enabled();
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -207,11 +207,11 @@ static int list_links(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return rtnl_log_create_error(r);
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return rtnl_log_create_error(r);
 
-        r = sd_rtnl_call(rtnl, req, 0, &reply);
+        r = sd_netlink_call(rtnl, req, 0, &reply);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate links: %m");
 
@@ -287,14 +287,14 @@ static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
 }
 
 static int get_gateway_description(
-                sd_rtnl *rtnl,
+                sd_netlink *rtnl,
                 sd_hwdb *hwdb,
                 int ifindex,
                 int family,
                 union in_addr_union *gateway,
                 char **gateway_description) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        sd_rtnl_message *m;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *m;
         int r;
 
         assert(rtnl);
@@ -307,27 +307,27 @@ static int get_gateway_description(
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call(rtnl, req, 0, &reply);
+        r = sd_netlink_call(rtnl, req, 0, &reply);
         if (r < 0)
                 return r;
 
-        for (m = reply; m; m = sd_rtnl_message_next(m)) {
+        for (m = reply; m; m = sd_netlink_message_next(m)) {
                 union in_addr_union gw = {};
                 struct ether_addr mac = {};
                 uint16_t type;
                 int ifi, fam;
 
-                r = sd_rtnl_message_get_errno(m);
+                r = sd_netlink_message_get_errno(m);
                 if (r < 0) {
                         log_error_errno(r, "got error: %m");
                         continue;
                 }
 
-                r = sd_rtnl_message_get_type(m, &type);
+                r = sd_netlink_message_get_type(m, &type);
                 if (r < 0) {
                         log_error_errno(r, "could not get type: %m");
                         continue;
@@ -360,13 +360,13 @@ static int get_gateway_description(
 
                 switch (fam) {
                 case AF_INET:
-                        r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
+                        r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
                         if (r < 0)
                                 continue;
 
                         break;
                 case AF_INET6:
-                        r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
+                        r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
                         if (r < 0)
                                 continue;
 
@@ -378,7 +378,7 @@ static int get_gateway_description(
                 if (!in_addr_equal(fam, &gw, gateway))
                         continue;
 
-                r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
+                r = sd_netlink_message_read_ether_addr(m, NDA_LLADDR, &mac);
                 if (r < 0)
                         continue;
 
@@ -393,7 +393,7 @@ static int get_gateway_description(
 }
 
 static int dump_gateways(
-                sd_rtnl *rtnl,
+                sd_netlink *rtnl,
                 sd_hwdb *hwdb,
                 const char *prefix,
                 int ifindex) {
@@ -442,7 +442,7 @@ static int dump_gateways(
 }
 
 static int dump_addresses(
-                sd_rtnl *rtnl,
+                sd_netlink *rtnl,
                 const char *prefix,
                 int ifindex) {
 
@@ -493,12 +493,12 @@ static void dump_list(const char *prefix, char **l) {
 }
 
 static int link_status_one(
-                sd_rtnl *rtnl,
+                sd_netlink *rtnl,
                 sd_hwdb *hwdb,
                 const char *name) {
         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
         _cleanup_device_unref_ sd_device *d = NULL;
         char devid[2 + DECIMAL_STR_MAX(int)];
         _cleanup_free_ char *t = NULL, *network = NULL;
@@ -523,13 +523,13 @@ static int link_status_one(
                 if (r < 0)
                         return rtnl_log_create_error(r);
 
-                r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
+                r = sd_netlink_message_append_string(req, IFLA_IFNAME, name);
         }
 
         if (r < 0)
                 return rtnl_log_create_error(r);
 
-        r = sd_rtnl_call(rtnl, req, 0, &reply);
+        r = sd_netlink_call(rtnl, req, 0, &reply);
         if (r < 0)
                 return log_error_errno(r, "Failed to query link: %m");
 
@@ -537,7 +537,7 @@ static int link_status_one(
         if (r < 0)
                 return rtnl_log_parse_error(r);
 
-        r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
+        r = sd_netlink_message_read_string(reply, IFLA_IFNAME, &name);
         if (r < 0)
                 return rtnl_log_parse_error(r);
 
@@ -545,7 +545,7 @@ static int link_status_one(
         if (r < 0)
                 return rtnl_log_parse_error(r);
 
-        have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
+        have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
 
         if (have_mac) {
                 const uint8_t *p;
@@ -561,7 +561,7 @@ static int link_status_one(
                         have_mac = false;
         }
 
-        sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
+        sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
 
         sd_network_link_get_operational_state(ifindex, &operational_state);
         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
@@ -666,11 +666,11 @@ static int link_status_one(
 
 static int link_status(int argc, char *argv[], void *userdata) {
         _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         char **name;
         int r;
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -711,7 +711,7 @@ static int link_status(int argc, char *argv[], void *userdata) {
         pager_open_if_enabled();
 
         if (arg_all) {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+                _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
                 _cleanup_free_ LinkInfo *links = NULL;
                 int c, i;
 
@@ -719,11 +719,11 @@ static int link_status(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return rtnl_log_create_error(r);
 
-                r = sd_rtnl_message_request_dump(req, true);
+                r = sd_netlink_message_request_dump(req, true);
                 if (r < 0)
                         return rtnl_log_create_error(r);
 
-                r = sd_rtnl_call(rtnl, req, 0, &reply);
+                r = sd_netlink_call(rtnl, req, 0, &reply);
                 if (r < 0)
                         return log_error_errno(r, "Failed to enumerate links: %m");
 
@@ -897,8 +897,8 @@ static char *lldp_system_caps(uint16_t cap) {
 }
 
 static int link_lldp_status(int argc, char *argv[], void *userdata) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         _cleanup_free_ LinkInfo *links = NULL;
         const char *state, *word;
 
@@ -910,7 +910,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
 
         pager_open_if_enabled();
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -918,11 +918,11 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return rtnl_log_create_error(r);
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return rtnl_log_create_error(r);
 
-        r = sd_rtnl_call(rtnl, req, 0, &reply);
+        r = sd_netlink_call(rtnl, req, 0, &reply);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate links: %m");
 
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 069ba3e..944da3f 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -151,8 +151,8 @@ int address_release(Address *address, Link *link) {
 }
 
 int address_drop(Address *address, Link *link,
-                 sd_rtnl_message_handler_t callback) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+                 sd_netlink_message_handler_t callback) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(address);
@@ -174,13 +174,13 @@ int address_drop(Address *address, Link *link,
                 return log_error_errno(r, "Could not set prefixlen: %m");
 
         if (address->family == AF_INET)
-                r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
+                r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
         else if (address->family == AF_INET6)
-                r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
+                r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -190,8 +190,8 @@ int address_drop(Address *address, Link *link,
 }
 
 int address_update(Address *address, Link *link,
-                   sd_rtnl_message_handler_t callback) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+                   sd_netlink_message_handler_t callback) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(address);
@@ -216,7 +216,7 @@ int address_update(Address *address, Link *link,
                 return log_error_errno(r, "Could not set flags: %m");
 
         if (address->flags & ~0xff && link->rtnl_extended_attrs) {
-                r = sd_rtnl_message_append_u32(req, IFA_FLAGS, address->flags);
+                r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
                 if (r < 0)
                         return log_error_errno(r, "Could not set extended flags: %m");
         }
@@ -226,29 +226,29 @@ int address_update(Address *address, Link *link,
                 return log_error_errno(r, "Could not set scope: %m");
 
         if (address->family == AF_INET)
-                r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
+                r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
         else if (address->family == AF_INET6)
-                r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
+                r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
 
         if (address->family == AF_INET) {
-                r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
+                r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
                 if (r < 0)
                         return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
         }
 
         if (address->label) {
-                r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
+                r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
                 if (r < 0)
                         return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
         }
 
-        r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
+        r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -317,8 +317,8 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
 }
 
 int address_configure(Address *address, Link *link,
-                      sd_rtnl_message_handler_t callback) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+                      sd_netlink_message_handler_t callback) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(address);
@@ -348,7 +348,7 @@ int address_configure(Address *address, Link *link,
                 return log_error_errno(r, "Could not set flags: %m");
 
         if (address->flags & ~0xff) {
-                r = sd_rtnl_message_append_u32(req, IFA_FLAGS, address->flags);
+                r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
                 if (r < 0)
                         return log_error_errno(r, "Could not set extended flags: %m");
         }
@@ -358,39 +358,39 @@ int address_configure(Address *address, Link *link,
                 return log_error_errno(r, "Could not set scope: %m");
 
         if (address->family == AF_INET)
-                r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
+                r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
         else if (address->family == AF_INET6)
-                r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
+                r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
 
         if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
                 if (address->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
+                        r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
                 else if (address->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
+                        r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
         } else {
                 if (address->family == AF_INET) {
-                        r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
+                        r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
                         if (r < 0)
                                 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
                 }
         }
 
         if (address->label) {
-                r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
+                r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
                 if (r < 0)
                         return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
         }
 
-        r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
+        r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
                                               &address->cinfo);
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 71cc722..d446bfa 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -27,7 +27,7 @@
 #include "network-internal.h"
 #include "dhcp-lease-internal.h"
 
-static int dhcp4_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
+static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
                                void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
@@ -37,7 +37,7 @@ static int dhcp4_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
 
         link->dhcp4_messages --;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
                 log_link_error(link, "could not set DHCPv4 route: %s",
                                strerror(-r));
@@ -285,14 +285,14 @@ static int dhcp_lease_lost(Link *link) {
         return 0;
 }
 
-static int dhcp4_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
+static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
                                  void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
         assert(link);
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
                 log_link_error(link, "could not set DHCPv4 address: %s",
                                strerror(-r));
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 33e1813..3a5ac1c 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -35,14 +35,14 @@ static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
         return 0;
 }
 
-static int dhcp6_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
+static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
                                  void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
         assert(link);
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
                 if (link->rtnl_extended_attrs) {
                         log_link_warning(link, "Could not set extended netlink attributes, reverting to fallback mechanism");
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index 796d111..0f2510e 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -80,13 +80,13 @@ int fdb_entry_new_static(Network *const network,
         return 0;
 }
 
-static int set_fdb_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         Link *link = userdata;
         int r;
 
         assert(link);
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST)
                 log_link_error_errno(link, r, "Could not add FDB entry: %m");
 
@@ -95,8 +95,8 @@ static int set_fdb_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
 /* send a request to the kernel to add a FDB entry in its static MAC table. */
 int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
-        sd_rtnl *rtnl;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+        sd_netlink *rtnl;
         int r;
 
         assert(link);
@@ -120,19 +120,19 @@ int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
         if (r < 0)
                 return rtnl_log_create_error(r);
 
-        r = sd_rtnl_message_append_ether_addr(req, NDA_LLADDR, fdb_entry->mac_addr);
+        r = sd_netlink_message_append_ether_addr(req, NDA_LLADDR, fdb_entry->mac_addr);
         if (r < 0)
                 return rtnl_log_create_error(r);
 
         /* VLAN Id is optional. We'll add VLAN Id only if it's specified. */
         if (0 != fdb_entry->vlan_id) {
-                r = sd_rtnl_message_append_u16(req, NDA_VLAN, fdb_entry->vlan_id);
+                r = sd_netlink_message_append_u16(req, NDA_VLAN, fdb_entry->vlan_id);
                 if (r < 0)
                         return rtnl_log_create_error(r);
         }
 
         /* send message to the kernel to update its internal static MAC table. */
-        r = sd_rtnl_call_async(rtnl, req, set_fdb_handler, link, 0, NULL);
+        r = sd_netlink_call_async(rtnl, req, set_fdb_handler, link, 0, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 14b8770..0a27a30 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -73,14 +73,14 @@ static int ipv4ll_address_lost(Link *link) {
         return 0;
 }
 
-static int ipv4ll_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
         assert(link);
         assert(!link->ipv4ll_route);
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
                 log_link_error(link, "could not set ipv4ll route: %s", strerror(-r));
                 link_enter_failed(link);
@@ -94,14 +94,14 @@ static int ipv4ll_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat
         return 1;
 }
 
-static int ipv4ll_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
         assert(link);
         assert(!link->ipv4ll_address);
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
                 log_link_error(link, "could not set ipv4ll address: %s", strerror(-r));
                 link_enter_failed(link);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index b194788..16243a5 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -121,7 +121,7 @@ static bool link_ipv6_forward_enabled(Link *link) {
                 ? ((old & flag) ? (" -" string) : (" +" string)) \
                 : "")
 
-static int link_update_flags(Link *link, sd_rtnl_message *m) {
+static int link_update_flags(Link *link, sd_netlink_message *m) {
         unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
         uint8_t operstate;
         int r;
@@ -132,7 +132,7 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
         if (r < 0)
                 return log_link_warning_errno(link, r, "Could not get link flags: %m");
 
-        r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate);
+        r = sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &operstate);
         if (r < 0)
                 /* if we got a message without operstate, take it to mean
                    the state was unchanged */
@@ -193,7 +193,7 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
         return 0;
 }
 
-static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
+static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
         _cleanup_link_unref_ Link *link = NULL;
         uint16_t type;
         const char *ifname;
@@ -203,7 +203,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
         assert(message);
         assert(ret);
 
-        r = sd_rtnl_message_get_type(message, &type);
+        r = sd_netlink_message_get_type(message, &type);
         if (r < 0)
                 return r;
         else if (type != RTM_NEWLINK)
@@ -215,7 +215,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
         else if (ifindex <= 0)
                 return -EINVAL;
 
-        r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
+        r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
         if (r < 0)
                 return r;
 
@@ -232,7 +232,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
         if (!link->ifname)
                 return -ENOMEM;
 
-        r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
+        r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
         if (r < 0)
                 log_link_debug(link, "MAC address not found for new device, continuing without");
 
@@ -497,7 +497,7 @@ void link_client_handler(Link *link) {
         return;
 }
 
-static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -511,7 +511,7 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST)
                 log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
 
@@ -554,7 +554,7 @@ static int link_enter_set_routes(Link *link) {
         return 0;
 }
 
-int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -565,14 +565,14 @@ int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -ESRCH)
                 log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
 
         return 1;
 }
 
-static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -589,7 +589,7 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST)
                 log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
         else if (r >= 0)
@@ -682,7 +682,7 @@ static int link_enter_set_addresses(Link *link) {
         return 0;
 }
 
-int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -693,7 +693,7 @@ int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EADDRNOTAVAIL)
                 log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
 
@@ -715,13 +715,13 @@ static int link_set_bridge_fdb(Link *const link) {
         return r;
 }
 
-static int link_set_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
         log_link_debug(link, "Set link");
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
                 log_link_error_errno(link, r, "Could not join netdev: %m");
                 link_enter_failed(link);
@@ -784,7 +784,7 @@ int link_set_hostname(Link *link, const char *hostname) {
         return 0;
 }
 
-static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -795,7 +795,7 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0)
                 log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
 
@@ -803,7 +803,7 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 }
 
 int link_set_mtu(Link *link, uint32_t mtu) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
@@ -816,11 +816,11 @@ int link_set_mtu(Link *link, uint32_t mtu) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
-        r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
+        r = sd_netlink_message_append_u32(req, IFLA_MTU, mtu);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append MTU: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -830,7 +830,7 @@ int link_set_mtu(Link *link, uint32_t mtu) {
 }
 
 static int link_set_bridge(Link *link) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
@@ -847,21 +847,21 @@ static int link_set_bridge(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set message family: %m");
 
-        r = sd_rtnl_message_open_container(req, IFLA_PROTINFO);
+        r = sd_netlink_message_open_container(req, IFLA_PROTINFO);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
 
         if(link->network->cost != 0) {
-                r = sd_rtnl_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
+                r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
         }
 
-        r = sd_rtnl_message_close_container(req);
+        r = sd_netlink_message_close_container(req);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, link_set_handler, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, link_set_handler, link, 0, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -952,7 +952,7 @@ bool link_has_carrier(Link *link) {
         return false;
 }
 
-static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -961,7 +961,7 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0)
                 /* we warn but don't fail the link, as it may be
                    brought up later */
@@ -971,7 +971,7 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 }
 
 static int link_up(Link *link) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         uint8_t ipv6ll_mode;
         int r;
 
@@ -991,48 +991,48 @@ static int link_up(Link *link) {
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
         if (link->network->mac) {
-                r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
+                r = sd_netlink_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set MAC address: %m");
         }
 
         if (link->network->mtu) {
-                r = sd_rtnl_message_append_u32(req, IFLA_MTU, link->network->mtu);
+                r = sd_netlink_message_append_u32(req, IFLA_MTU, link->network->mtu);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set MTU: %m");
         }
 
-        r = sd_rtnl_message_open_container(req, IFLA_AF_SPEC);
+        r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
 
         if (socket_ipv6_is_supported()) {
                 /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
-                r = sd_rtnl_message_open_container(req, AF_INET6);
+                r = sd_netlink_message_open_container(req, AF_INET6);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
 
                 ipv6ll_mode = link_ipv6ll_enabled(link) ? IN6_ADDR_GEN_MODE_EUI64 : IN6_ADDR_GEN_MODE_NONE;
-                r = sd_rtnl_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
+                r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m");
 
                 if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
-                        r = sd_rtnl_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
+                        r = sd_netlink_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
                         if (r < 0)
                                 return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m");
                 }
 
-                r = sd_rtnl_message_close_container(req);
+                r = sd_netlink_message_close_container(req);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
         }
 
-        r = sd_rtnl_message_close_container(req);
+        r = sd_netlink_message_close_container(req);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1041,7 +1041,7 @@ static int link_up(Link *link) {
         return 0;
 }
 
-static int link_down_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -1050,7 +1050,7 @@ static int link_down_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0)
                 log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname);
 
@@ -1058,7 +1058,7 @@ static int link_down_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
 }
 
 static int link_down(Link *link) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
@@ -1076,7 +1076,7 @@ static int link_down(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set link flags: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, link_down_handler, link,  0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, link_down_handler, link,  0, NULL);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
@@ -1360,7 +1360,7 @@ static int link_joined(Link *link) {
         return link_enter_set_addresses(link);
 }
 
-static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
+static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m,
                                void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
@@ -1373,7 +1373,7 @@ static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
                 log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
                 link_enter_failed(link);
@@ -1578,7 +1578,7 @@ static int link_configure(Link *link) {
         return link_enter_join_netdev(link);
 }
 
-static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
+static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
                                        void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         Network *network;
@@ -1636,7 +1636,7 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
 }
 
 int link_initialized(Link *link, struct udev_device *device) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
@@ -1664,7 +1664,7 @@ int link_initialized(Link *link, struct udev_device *device) {
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req,
+        r = sd_netlink_call_async(link->manager->rtnl, req,
                                link_initialized_and_synced, link, 0, NULL);
         if (r < 0)
                 return r;
@@ -1687,7 +1687,7 @@ static Address* link_get_equal_address(Link *link, Address *needle) {
         return NULL;
 }
 
-int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
+int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link = NULL;
         uint16_t type;
@@ -1702,15 +1702,15 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
         assert(message);
         assert(m);
 
-        if (sd_rtnl_message_is_error(message)) {
-                r = sd_rtnl_message_get_errno(message);
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
                 if (r < 0)
                         log_warning_errno(r, "rtnl: failed to receive address: %m");
 
                 return 0;
         }
 
-        r = sd_rtnl_message_get_type(message, &type);
+        r = sd_netlink_message_get_type(message, &type);
         if (r < 0) {
                 log_warning_errno(r, "rtnl: could not get message type: %m");
                 return 0;
@@ -1768,7 +1768,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
 
         switch (address->family) {
         case AF_INET:
-                r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
+                r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
                         return 0;
@@ -1777,7 +1777,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
                 break;
 
         case AF_INET6:
-                r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
+                r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
                         return 0;
@@ -1794,7 +1794,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
                 return 0;
         }
 
-        r = sd_rtnl_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo);
+        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo);
         if (r >= 0) {
                 if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
                         valid_str = "ever";
@@ -1847,7 +1847,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
         return 1;
 }
 
-int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
+int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
         Link *link;
         _cleanup_udev_device_unref_ struct udev_device *device = NULL;
         char ifindex_str[2 + DECIMAL_STR_MAX(int)];
@@ -1953,7 +1953,7 @@ int link_carrier_reset(Link *link) {
 }
 
 
-int link_update(Link *link, sd_rtnl_message *m) {
+int link_update(Link *link, sd_netlink_message *m) {
         struct ether_addr mac;
         const char *ifname;
         uint32_t mtu;
@@ -1974,7 +1974,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
                         return r;
         }
 
-        r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
+        r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname);
         if (r >= 0 && !streq(ifname, link->ifname)) {
                 log_link_info(link, "Renamed to %s", ifname);
 
@@ -1990,7 +1990,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
                         return r;
         }
 
-        r = sd_rtnl_message_read_u32(m, IFLA_MTU, &mtu);
+        r = sd_netlink_message_read_u32(m, IFLA_MTU, &mtu);
         if (r >= 0 && mtu > 0) {
                 link->mtu = mtu;
                 if (!link->original_mtu) {
@@ -2010,7 +2010,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
 
         /* The kernel may broadcast NEWLINK messages without the MAC address
            set, simply ignore them. */
-        r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
+        r = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
         if (r >= 0) {
                 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet,
                            ETH_ALEN)) {
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index c599952..2dcbbda 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -94,19 +94,19 @@ struct Link {
 Link *link_unref(Link *link);
 Link *link_ref(Link *link);
 int link_get(Manager *m, int ifindex, Link **ret);
-int link_add(Manager *manager, sd_rtnl_message *message, Link **ret);
+int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
 void link_drop(Link *link);
 
-int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata);
-int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata);
+int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
 
 void link_enter_failed(Link *link);
 int link_initialized(Link *link, struct udev_device *device);
 
 void link_client_handler(Link *link);
 
-int link_update(Link *link, sd_rtnl_message *message);
-int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata);
+int link_update(Link *link, sd_netlink_message *message);
+int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata);
 
 int link_save(Link *link);
 
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 9936a8e..a5c2351 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -29,12 +29,12 @@
 #include "networkd-link.h"
 #include "libudev-private.h"
 #include "udev-util.h"
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "bus-util.h"
 #include "def.h"
 #include "virt.h"
 
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "sd-daemon.h"
 
 /* use 8 MB for receive socket kernel queue. */
@@ -274,7 +274,7 @@ static int manager_connect_udev(Manager *m) {
         return 0;
 }
 
-static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
+static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link = NULL;
         NetDev *netdev = NULL;
@@ -286,15 +286,15 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
         assert(message);
         assert(m);
 
-        if (sd_rtnl_message_is_error(message)) {
-                r = sd_rtnl_message_get_errno(message);
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
                 if (r < 0)
                         log_warning_errno(r, "rtnl: could not receive link: %m");
 
                 return 0;
         }
 
-        r = sd_rtnl_message_get_type(message, &type);
+        r = sd_netlink_message_get_type(message, &type);
         if (r < 0) {
                 log_warning_errno(r, "rtnl: could not get message type: %m");
                 return 0;
@@ -313,7 +313,7 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
         } else
                 link_get(m, ifindex, &link);
 
-        r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
+        r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
         if (r < 0) {
                 log_warning_errno(r, "rtnl: received link message without ifname: %m");
                 return 0;
@@ -385,33 +385,33 @@ static int manager_connect_rtnl(Manager *m) {
 
         fd = systemd_netlink_fd();
         if (fd < 0)
-                r = sd_rtnl_open(&m->rtnl);
+                r = sd_netlink_open(&m->rtnl);
         else
-                r = sd_rtnl_open_fd(&m->rtnl, fd);
+                r = sd_netlink_open_fd(&m->rtnl, fd);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
+        r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
+        r = sd_netlink_attach_event(m->rtnl, m->event, 0);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
         if (r < 0)
                 return r;
 
@@ -498,7 +498,7 @@ void manager_free(Manager *m) {
         while ((pool = m->address_pools))
                 address_pool_free(pool);
 
-        sd_rtnl_unref(m->rtnl);
+        sd_netlink_unref(m->rtnl);
 
         free(m);
 }
@@ -570,8 +570,8 @@ bool manager_should_reload(Manager *m) {
 }
 
 int manager_rtnl_enumerate_links(Manager *m) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        sd_rtnl_message *link;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *link;
         int r;
 
         assert(m);
@@ -581,15 +581,15 @@ int manager_rtnl_enumerate_links(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+        r = sd_netlink_call(m->rtnl, req, 0, &reply);
         if (r < 0)
                 return r;
 
-        for (link = reply; link; link = sd_rtnl_message_next(link)) {
+        for (link = reply; link; link = sd_netlink_message_next(link)) {
                 int k;
 
                 m->enumerating = true;
@@ -605,8 +605,8 @@ int manager_rtnl_enumerate_links(Manager *m) {
 }
 
 int manager_rtnl_enumerate_addresses(Manager *m) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        sd_rtnl_message *addr;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *addr;
         int r;
 
         assert(m);
@@ -616,15 +616,15 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+        r = sd_netlink_call(m->rtnl, req, 0, &reply);
         if (r < 0)
                 return r;
 
-        for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
+        for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
                 int k;
 
                 m->enumerating = true;
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index d7f9bb4..6336ff5 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -24,8 +24,8 @@
 #include <linux/if_bonding.h>
 
 #include "conf-parser.h"
-#include "sd-rtnl.h"
-#include "rtnl-types.h"
+#include "sd-netlink.h"
+#include "netlink-types.h"
 #include "networkd-netdev-bond.h"
 #include "missing.h"
 
@@ -178,7 +178,7 @@ static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
         }
 }
 
-static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Bond *b = BOND(netdev);
         ArpIpTarget *target = NULL;
         int r, i = 0;
@@ -189,14 +189,14 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
         assert(m);
 
         if (b->mode != _NETDEV_BOND_MODE_INVALID) {
-                r = sd_rtnl_message_append_u8(m, IFLA_BOND_MODE,
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE,
                                               bond_mode_to_kernel(b->mode));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m");
         }
 
         if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
-                r = sd_rtnl_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
                                               bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
@@ -204,38 +204,38 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
 
         if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
             b->mode == NETDEV_BOND_MODE_802_3AD) {
-                r = sd_rtnl_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
                 if (r < 0) {
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
                 }
         }
 
         if (b->miimon != 0) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
                 if (r < 0)
                         log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
         }
 
         if (b->downdelay != 0) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
         }
 
         if (b->updelay != 0) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_UPDELAY attribute: %m");
         }
 
         if (b->arp_interval != 0) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
 
                 if ((b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC) &&
                     (b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC)) {
-                        r = sd_rtnl_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
+                        r = sd_netlink_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
                 }
@@ -243,79 +243,79 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
 
         if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
             b->mode == NETDEV_BOND_MODE_802_3AD) {
-                r = sd_rtnl_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
         }
 
         if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
             b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP) {
-                r = sd_rtnl_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
         }
 
         if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
         }
 
         if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
         }
 
         if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->primary_reselect);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->primary_reselect);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
         }
 
         if (b->resend_igmp <= RESEND_IGMP_MAX) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
         }
 
         if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX &&
             b->mode == NETDEV_BOND_MODE_BALANCE_RR) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
         }
 
         if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
-                r = sd_rtnl_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
         }
 
         if (b->min_links != 0) {
-                r = sd_rtnl_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
+                r = sd_netlink_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
+        r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
 
         if (b->arp_interval > 0)  {
                 if (b->n_arp_ip_targets > 0) {
 
-                        r = sd_rtnl_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
+                        r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
 
                         LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
-                                r = sd_rtnl_message_append_u32(m, i++, target->ip.in.s_addr);
+                                r = sd_netlink_message_append_u32(m, i++, target->ip.in.s_addr);
                                 if (r < 0)
                                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
                         }
 
-                        r = sd_rtnl_message_close_container(m);
+                        r = sd_netlink_message_close_container(m);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
                 }
diff --git a/src/network/networkd-netdev-ipvlan.c b/src/network/networkd-netdev-ipvlan.c
index f1c8e0c..5eb4a1e 100644
--- a/src/network/networkd-netdev-ipvlan.c
+++ b/src/network/networkd-netdev-ipvlan.c
@@ -32,7 +32,7 @@ static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode");
 
-static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *req) {
+static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
         IPVlan *m = IPVLAN(netdev);
         int r;
 
@@ -42,7 +42,7 @@ static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
         assert(netdev->ifname);
 
         if (m->mode != _NETDEV_IPVLAN_MODE_INVALID) {
-                r = sd_rtnl_message_append_u16(req, IFLA_IPVLAN_MODE, m->mode);
+                r = sd_netlink_message_append_u16(req, IFLA_IPVLAN_MODE, m->mode);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPVLAN_MODE attribute: %m");
         }
diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c
index a8bf6e6..c2c5649 100644
--- a/src/network/networkd-netdev-macvlan.c
+++ b/src/network/networkd-netdev-macvlan.c
@@ -34,7 +34,7 @@ static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
 
-static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *req) {
+static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
         MacVlan *m = MACVLAN(netdev);
         int r;
 
@@ -44,7 +44,7 @@ static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_rtn
         assert(netdev->ifname);
 
         if (m->mode != _NETDEV_MACVLAN_MODE_INVALID) {
-                r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode);
+                r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_MODE attribute: %m");
         }
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index 8af4be4..5533fb5 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -25,7 +25,7 @@
 #include <linux/if_tunnel.h>
 #include <linux/ip6_tunnel.h>
 
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "networkd-netdev-tunnel.h"
 #include "networkd-link.h"
 #include "util.h"
@@ -43,7 +43,7 @@ static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
 
-static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Tunnel *t = IPIP(netdev);
         int r;
 
@@ -53,30 +53,30 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
         assert(t);
         assert(t->family == AF_INET);
 
-        r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
+        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL  attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
+        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
 
         return r;
 }
 
-static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Tunnel *t = SIT(netdev);
         int r;
 
@@ -86,30 +86,30 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
         assert(t);
         assert(t->family == AF_INET);
 
-        r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
+        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
+        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
 
         return r;
 }
 
-static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Tunnel *t;
         int r;
 
@@ -125,34 +125,34 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
         assert(link);
         assert(m);
 
-        r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
         if (r < 0)
                 log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
+        r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, t->tos);
+        r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
         if (r < 0)
                 log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
+        r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
 
         return r;
 }
 
-static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Tunnel *t;
         int r;
 
@@ -168,26 +168,26 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
         assert(link);
         assert(m);
 
-        r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
 
-        r = sd_rtnl_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
+        r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
 
-        r = sd_rtnl_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
+        r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
+        r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
 
         return r;
 }
 
-static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Tunnel *t = VTI(netdev);
         int r;
 
@@ -197,22 +197,22 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
         assert(t);
         assert(t->family == AF_INET);
 
-        r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
 
         return r;
 }
 
-static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Tunnel *t = VTI6(netdev);
         int r;
 
@@ -222,22 +222,22 @@ static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
         assert(t);
         assert(t->family == AF_INET6);
 
-        r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
 
-        r = sd_rtnl_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6);
+        r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
 
-        r = sd_rtnl_message_append_in6_addr(m, IFLA_VTI_REMOTE, &t->remote.in6);
+        r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_REMOTE, &t->remote.in6);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
 
         return r;
 }
 
-static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Tunnel *t = IP6TNL(netdev);
         uint8_t proto;
         int r;
@@ -248,19 +248,19 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
         assert(t);
         assert(t->family == AF_INET6);
 
-        r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
 
-        r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
+        r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
 
-        r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
+        r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
+        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
 
@@ -277,7 +277,7 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
                 break;
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
+        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_MODE attribute: %m");
 
diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c
index 7bb02d1..e20f9f7 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/networkd-netdev-veth.c
@@ -22,10 +22,10 @@
 #include <net/if.h>
 #include <linux/veth.h>
 
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "networkd-netdev-veth.h"
 
-static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         Veth *v = VETH(netdev);
         int r;
 
@@ -34,23 +34,23 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
         assert(v);
         assert(m);
 
-        r = sd_rtnl_message_open_container(m, VETH_INFO_PEER);
+        r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append VETH_INFO_PEER attribute: %m");
 
         if (v->ifname_peer) {
-                r = sd_rtnl_message_append_string(m, IFLA_IFNAME, v->ifname_peer);
+                r = sd_netlink_message_append_string(m, IFLA_IFNAME, v->ifname_peer);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink interface name: %m");
         }
 
         if (v->mac_peer) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, v->mac_peer);
+                r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, v->mac_peer);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
         }
 
-        r = sd_rtnl_message_close_container(m);
+        r = sd_netlink_message_close_container(m);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
 
diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c
index 0ed024b..d53e7be 100644
--- a/src/network/networkd-netdev-vlan.c
+++ b/src/network/networkd-netdev-vlan.c
@@ -23,7 +23,7 @@
 
 #include "networkd-netdev-vlan.h"
 
-static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *req) {
+static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
         VLan *v = VLAN(netdev);
         int r;
 
@@ -33,7 +33,7 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
         assert(req);
 
         if (v->id <= VLANID_MAX) {
-                r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, v->id);
+                r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id);
                 if (r < 0) {
                         log_netdev_error(netdev,
                                          "Could not append IFLA_VLAN_ID attribute: %s",
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 01a1e50..2a5c5f0 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -21,13 +21,13 @@
 
 #include <net/if.h>
 
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "networkd-netdev-vxlan.h"
 #include "networkd-link.h"
 #include "conf-parser.h"
 #include "missing.h"
 
-static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         VxLan *v = VXLAN(netdev);
         int r;
 
@@ -38,66 +38,66 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
 
 
         if (v->id <= VXLAN_VID_MAX) {
-                r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_ID, v->id);
+                r = sd_netlink_message_append_u32(m, IFLA_VXLAN_ID, v->id);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_ID attribute: %m");
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->group.in);
+        r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->group.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m");
 
-        r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
+        r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m");
 
         if(v->ttl) {
-                r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
+                r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m");
         }
 
         if(v->tos) {
-                r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
+                r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m");
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_LEARNING, v->learning);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_LEARNING, v->learning);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LEARNING attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_RSC, v->route_short_circuit);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_RSC, v->route_short_circuit);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_RSC attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_PROXY, v->arp_proxy);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_PROXY, v->arp_proxy);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PROXY attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_L2MISS, v->l2miss);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_L2MISS, v->l2miss);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L2MISS attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_L3MISS, v->l3miss);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_L3MISS, v->l3miss);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m");
 
         if(v->fdb_ageing) {
-                r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
+                r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m");
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_UDP_CSUM, v->udpcsum);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_CSUM, v->udpcsum);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_CSUM attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_TX attribute: %m");
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
+        r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_RX attribute: %m");
 
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 66fd0fa..ece9ecc 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -77,7 +77,7 @@ DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
 
 static void netdev_cancel_callbacks(NetDev *netdev) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
         netdev_join_callback *callback;
 
         if (!netdev)
@@ -180,8 +180,8 @@ static int netdev_enter_failed(NetDev *netdev) {
         return 0;
 }
 
-static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(netdev);
@@ -196,11 +196,11 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_hand
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
 
-        r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
+        r = sd_netlink_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
 
-        r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
+        r = sd_netlink_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
         if (r < 0)
                 return log_netdev_error(netdev, "Could not send rtnetlink message: %m");
 
@@ -241,13 +241,13 @@ static int netdev_enter_ready(NetDev *netdev) {
 }
 
 /* callback for netdev's created without a backing Link */
-static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_netdev_unref_ NetDev *netdev = userdata;
         int r;
 
         assert(netdev->state != _NETDEV_STATE_INVALID);
 
-        r = sd_rtnl_message_get_errno(m);
+        r = sd_netlink_message_get_errno(m);
         if (r == -EEXIST)
                 log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
         else if (r < 0) {
@@ -262,7 +262,7 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
         return 1;
 }
 
-int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
+int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
@@ -292,7 +292,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callbac
         return 0;
 }
 
-int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
+int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
         uint16_t type;
         const char *kind;
         const char *received_kind;
@@ -302,7 +302,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
         assert(netdev);
         assert(message);
 
-        r = sd_rtnl_message_get_type(message, &type);
+        r = sd_netlink_message_get_type(message, &type);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not get rtnl message type: %m");
 
@@ -333,7 +333,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
                         return 0;
         }
 
-        r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
+        r = sd_netlink_message_read_string(message, IFLA_IFNAME, &received_name);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not get IFNAME: %m");
 
@@ -343,15 +343,15 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
                 return r;
         }
 
-        r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
+        r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
 
-        r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
+        r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
 
-        r = sd_rtnl_message_exit_container(message);
+        r = sd_netlink_message_exit_container(message);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
 
@@ -431,7 +431,7 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
 }
 
 static int netdev_create(NetDev *netdev, Link *link,
-                         sd_rtnl_message_handler_t callback) {
+                         sd_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
@@ -447,39 +447,39 @@ static int netdev_create(NetDev *netdev, Link *link,
 
                 log_netdev_debug(netdev, "Created");
         } else {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+                _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
 
                 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
 
-                r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
+                r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
 
                 if (netdev->mac) {
-                        r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
+                        r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
                 }
 
                 if (netdev->mtu) {
-                        r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
+                        r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
                 }
 
                 if (link) {
-                        r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
+                        r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINK attribute: %m");
                 }
 
-                r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
+                r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
 
-                r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
+                r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
 
@@ -489,22 +489,22 @@ static int netdev_create(NetDev *netdev, Link *link,
                                 return r;
                 }
 
-                r = sd_rtnl_message_close_container(m);
+                r = sd_netlink_message_close_container(m);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
 
-                r = sd_rtnl_message_close_container(m);
+                r = sd_netlink_message_close_container(m);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
 
                 if (link) {
-                        r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
+                        r = sd_netlink_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
                         link_ref(link);
                 } else {
-                        r = sd_rtnl_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
+                        r = sd_netlink_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
@@ -520,7 +520,7 @@ static int netdev_create(NetDev *netdev, Link *link,
 }
 
 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
-int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
+int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 1ded495..a004f2f 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -29,7 +29,7 @@ typedef struct NetDevVTable NetDevVTable;
 typedef struct netdev_join_callback netdev_join_callback;
 
 struct netdev_join_callback {
-        sd_rtnl_message_handler_t callback;
+        sd_netlink_message_handler_t callback;
         Link *link;
 
         LIST_FIELDS(netdev_join_callback, callbacks);
@@ -129,7 +129,7 @@ struct NetDevVTable {
         void (*done)(NetDev *n);
 
         /* fill in message to create netdev */
-        int (*fill_message_create)(NetDev *netdev, Link *link, sd_rtnl_message *message);
+        int (*fill_message_create)(NetDev *netdev, Link *link, sd_netlink_message *message);
 
         /* specifies if netdev is independent, or a master device or a stacked device */
         NetDevCreateType create_type;
@@ -187,10 +187,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref);
 #define _cleanup_netdev_unref_ _cleanup_(netdev_unrefp)
 
 int netdev_get(Manager *manager, const char *name, NetDev **ret);
-int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *newlink);
-int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback);
+int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink);
+int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback);
 int netdev_get_mac(const char *ifname, struct ether_addr **ret);
-int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t cb);
+int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t cb);
 
 const char *netdev_kind_to_string(NetDevKind d) _const_;
 NetDevKind netdev_kind_from_string(const char *d) _pure_;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 7f110a5..31b10c4 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -97,8 +97,8 @@ void route_free(Route *route) {
 }
 
 int route_drop(Route *route, Link *link,
-               sd_rtnl_message_handler_t callback) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+               sd_netlink_message_handler_t callback) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
@@ -115,18 +115,18 @@ int route_drop(Route *route, Link *link,
 
         if (!in_addr_is_null(route->family, &route->in_addr)) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
         }
 
         if (route->dst_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_DST attribute: %m");
 
@@ -137,9 +137,9 @@ int route_drop(Route *route, Link *link,
 
         if (route->src_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_DST attribute: %m");
 
@@ -150,9 +150,9 @@ int route_drop(Route *route, Link *link,
 
         if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
         }
@@ -161,15 +161,15 @@ int route_drop(Route *route, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not set scope: %m");
 
-        r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
+        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
 
-        r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
+        r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -179,8 +179,8 @@ int route_drop(Route *route, Link *link,
 }
 
 int route_configure(Route *route, Link *link,
-                    sd_rtnl_message_handler_t callback) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+                    sd_netlink_message_handler_t callback) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
@@ -197,18 +197,18 @@ int route_configure(Route *route, Link *link,
 
         if (!in_addr_is_null(route->family, &route->in_addr)) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
         }
 
         if (route->dst_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_DST attribute: %m");
 
@@ -219,9 +219,9 @@ int route_configure(Route *route, Link *link,
 
         if (route->src_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
 
@@ -232,9 +232,9 @@ int route_configure(Route *route, Link *link,
 
         if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
                 if (route->family == AF_INET)
-                        r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
                 else if (route->family == AF_INET6)
-                        r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
         }
@@ -243,15 +243,15 @@ int route_configure(Route *route, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not set scope: %m");
 
-        r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
+        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
 
-        r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
+        r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
 
-        r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c
index 341bcae..2d51237 100644
--- a/src/network/networkd-wait-online-link.c
+++ b/src/network/networkd-wait-online-link.c
@@ -82,7 +82,7 @@ Link *link_free(Link *l) {
         return NULL;
  }
 
-int link_update_rtnl(Link *l, sd_rtnl_message *m) {
+int link_update_rtnl(Link *l, sd_netlink_message *m) {
         const char *ifname;
         int r;
 
@@ -94,7 +94,7 @@ int link_update_rtnl(Link *l, sd_rtnl_message *m) {
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
+        r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname);
         if (r < 0)
                 return r;
 
diff --git a/src/network/networkd-wait-online-link.h b/src/network/networkd-wait-online-link.h
index 90ea6b3..0681966 100644
--- a/src/network/networkd-wait-online-link.h
+++ b/src/network/networkd-wait-online-link.h
@@ -39,7 +39,7 @@ struct Link {
 
 int link_new(Manager *m, Link **ret, int ifindex, const char *ifname);
 Link *link_free(Link *l);
-int link_update_rtnl(Link *l, sd_rtnl_message *m);
+int link_update_rtnl(Link *l, sd_netlink_message *m);
 int link_update_monitor(Link *l);
 bool link_relevant(Link *l);
 
diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c
index 39f3845..1fc724f 100644
--- a/src/network/networkd-wait-online-manager.c
+++ b/src/network/networkd-wait-online-manager.c
@@ -23,7 +23,7 @@
 #include <linux/if.h>
 #include <fnmatch.h>
 
-#include "rtnl-util.h"
+#include "netlink-util.h"
 
 #include "network-internal.h"
 #include "networkd-wait-online-link.h"
@@ -93,7 +93,7 @@ bool manager_all_configured(Manager *m) {
         return one_ready;
 }
 
-static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
         Manager *m = userdata;
         uint16_t type;
         Link *l;
@@ -104,7 +104,7 @@ static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userda
         assert(m);
         assert(mm);
 
-        r = sd_rtnl_message_get_type(mm, &type);
+        r = sd_netlink_message_get_type(mm, &type);
         if (r < 0)
                 goto fail;
 
@@ -112,7 +112,7 @@ static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userda
         if (r < 0)
                 goto fail;
 
-        r = sd_rtnl_message_read_string(mm, IFLA_IFNAME, &ifname);
+        r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname);
         if (r < 0)
                 goto fail;
 
@@ -155,7 +155,7 @@ fail:
         return 0;
 }
 
-static int on_rtnl_event(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
         Manager *m = userdata;
         int r;
 
@@ -170,26 +170,26 @@ static int on_rtnl_event(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
 }
 
 static int manager_rtnl_listen(Manager *m) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        sd_rtnl_message *i;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *i;
         int r;
 
         assert(m);
 
         /* First, subscribe to interfaces coming and going */
-        r = sd_rtnl_open(&m->rtnl);
+        r = sd_netlink_open(&m->rtnl);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
+        r = sd_netlink_attach_event(m->rtnl, m->event, 0);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, on_rtnl_event, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, on_rtnl_event, m);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, on_rtnl_event, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, on_rtnl_event, m);
         if (r < 0)
                 return r;
 
@@ -198,15 +198,15 @@ static int manager_rtnl_listen(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+        r = sd_netlink_call(m->rtnl, req, 0, &reply);
         if (r < 0)
                 return r;
 
-        for (i = reply; i; i = sd_rtnl_message_next(i)) {
+        for (i = reply; i; i = sd_netlink_message_next(i)) {
                 r = manager_process_link(m->rtnl, i, m);
                 if (r < 0)
                         return r;
@@ -323,7 +323,7 @@ void manager_free(Manager *m) {
         sd_network_monitor_unref(m->network_monitor);
 
         sd_event_source_unref(m->rtnl_event_source);
-        sd_rtnl_unref(m->rtnl);
+        sd_netlink_unref(m->rtnl);
 
         sd_event_unref(m->event);
         free(m);
diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h
index 73d1296..627c46b 100644
--- a/src/network/networkd-wait-online.h
+++ b/src/network/networkd-wait-online.h
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "sd-event.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "sd-network.h"
 
 #include "hashmap.h"
@@ -38,7 +38,7 @@ struct Manager {
         char **interfaces;
         char **ignore;
 
-        sd_rtnl *rtnl;
+        sd_netlink *rtnl;
         sd_event_source *rtnl_event_source;
 
         sd_network_monitor *network_monitor;
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 2c191a7..ac6e2c8 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -24,7 +24,7 @@
 #include <arpa/inet.h>
 
 #include "sd-event.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "sd-bus.h"
 #include "sd-dhcp-client.h"
 #include "sd-dhcp-server.h"
@@ -34,7 +34,7 @@
 #include "udev.h"
 #include "sd-lldp.h"
 
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "hashmap.h"
 #include "list.h"
 #include "set.h"
@@ -218,7 +218,7 @@ struct AddressPool {
 };
 
 struct Manager {
-        sd_rtnl *rtnl;
+        sd_netlink *rtnl;
         sd_event *event;
         sd_event_source *bus_retry_event_source;
         sd_bus *bus;
@@ -342,8 +342,8 @@ const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsig
 int route_new_static(Network *network, unsigned section, Route **ret);
 int route_new_dynamic(Route **ret, unsigned char rtm_protocol);
 void route_free(Route *route);
-int route_configure(Route *route, Link *link, sd_rtnl_message_handler_t callback);
-int route_drop(Route *route, Link *link, sd_rtnl_message_handler_t callback);
+int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
+int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback);
 
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
@@ -368,9 +368,9 @@ int config_parse_route_scope(const char *unit, const char *filename, unsigned li
 int address_new_static(Network *network, unsigned section, Address **ret);
 int address_new_dynamic(Address **ret);
 void address_free(Address *address);
-int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
-int address_update(Address *address, Link *link, sd_rtnl_message_handler_t callback);
-int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback);
+int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback);
+int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback);
+int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback);
 int address_establish(Address *address, Link *link);
 int address_release(Address *address, Link *link);
 bool address_equal(Address *a1, Address *a2);
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index 67fcca2..4382140 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -3,7 +3,7 @@
 #include "networkd-netdev-macvlan.h"
 #include "dhcp6-internal.h"
 #include "dhcp6-protocol.h"
-#include "rtnl-internal.h"
+#include "netlink-internal.h"
 #include "ethtool-util.h"
 
 #include "test-tables.h"
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 6a21ed5..3f0b3d9 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -55,7 +55,7 @@
 #include "sd-daemon.h"
 #include "sd-bus.h"
 #include "sd-id128.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "random-util.h"
 #include "log.h"
 #include "util.h"
@@ -75,7 +75,7 @@
 #include "bus-error.h"
 #include "ptyfwd.h"
 #include "env-util.h"
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "udev-util.h"
 #include "blkid-util.h"
 #include "gpt.h"
@@ -1966,7 +1966,7 @@ static int flush_ports(union in_addr_union *exposed) {
         return 0;
 }
 
-static int expose_ports(sd_rtnl *rtnl, union in_addr_union *exposed) {
+static int expose_ports(sd_netlink *rtnl, union in_addr_union *exposed) {
         _cleanup_free_ struct local_address *addresses = NULL;
         _cleanup_free_ char *pretty = NULL;
         union in_addr_union new_exposed;
@@ -2020,7 +2020,7 @@ static int expose_ports(sd_rtnl *rtnl, union in_addr_union *exposed) {
         return 0;
 }
 
-static int on_address_change(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         union in_addr_union *exposed = userdata;
 
         assert(rtnl);
@@ -2031,7 +2031,7 @@ static int on_address_change(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
         return 0;
 }
 
-static int watch_rtnl(sd_event *event, int recv_fd, union in_addr_union *exposed, sd_rtnl **ret) {
+static int watch_rtnl(sd_event *event, int recv_fd, union in_addr_union *exposed, sd_netlink **ret) {
         union {
                 struct cmsghdr cmsghdr;
                 uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -2041,7 +2041,7 @@ static int watch_rtnl(sd_event *event, int recv_fd, union in_addr_union *exposed
                 .msg_controllen = sizeof(control),
         };
         struct cmsghdr *cmsg;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         int fd, r;
         ssize_t k;
 
@@ -2062,21 +2062,21 @@ static int watch_rtnl(sd_event *event, int recv_fd, union in_addr_union *exposed
         assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
         memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
 
-        r = sd_rtnl_open_fd(&rtnl, fd);
+        r = sd_netlink_open_fd(&rtnl, fd);
         if (r < 0) {
                 safe_close(fd);
                 return log_error_errno(r, "Failed to create rtnl object: %m");
         }
 
-        r = sd_rtnl_add_match(rtnl, RTM_NEWADDR, on_address_change, exposed);
+        r = sd_netlink_add_match(rtnl, RTM_NEWADDR, on_address_change, exposed);
         if (r < 0)
                 return log_error_errno(r, "Failed to subscribe to RTM_NEWADDR messages: %m");
 
-        r = sd_rtnl_add_match(rtnl, RTM_DELADDR, on_address_change, exposed);
+        r = sd_netlink_add_match(rtnl, RTM_DELADDR, on_address_change, exposed);
         if (r < 0)
                 return log_error_errno(r, "Failed to subscribe to RTM_DELADDR messages: %m");
 
-        r = sd_rtnl_attach_event(rtnl, event, 0);
+        r = sd_netlink_attach_event(rtnl, event, 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to add to even loop: %m");
 
@@ -2550,8 +2550,8 @@ static int generate_mac(struct ether_addr *mac, sd_id128_t hash_key, uint64_t id
 }
 
 static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         struct ether_addr mac_host, mac_container;
         int r, i;
 
@@ -2574,7 +2574,7 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) {
         if (r < 0)
                 return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -2582,51 +2582,51 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) {
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate netlink message: %m");
 
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, iface_name);
+        r = sd_netlink_message_append_string(m, IFLA_IFNAME, iface_name);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink interface name: %m");
 
-        r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, &mac_host);
+        r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_host);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink MAC address: %m");
 
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
+        r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
         if (r < 0)
                 return log_error_errno(r, "Failed to open netlink container: %m");
 
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "veth");
+        r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
         if (r < 0)
                 return log_error_errno(r, "Failed to open netlink container: %m");
 
-        r = sd_rtnl_message_open_container(m, VETH_INFO_PEER);
+        r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
         if (r < 0)
                 return log_error_errno(r, "Failed to open netlink container: %m");
 
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, "host0");
+        r = sd_netlink_message_append_string(m, IFLA_IFNAME, "host0");
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink interface name: %m");
 
-        r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, &mac_container);
+        r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_container);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink MAC address: %m");
 
-        r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
+        r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink namespace field: %m");
 
-        r = sd_rtnl_message_close_container(m);
+        r = sd_netlink_message_close_container(m);
         if (r < 0)
                 return log_error_errno(r, "Failed to close netlink container: %m");
 
-        r = sd_rtnl_message_close_container(m);
+        r = sd_netlink_message_close_container(m);
         if (r < 0)
                 return log_error_errno(r, "Failed to close netlink container: %m");
 
-        r = sd_rtnl_message_close_container(m);
+        r = sd_netlink_message_close_container(m);
         if (r < 0)
                 return log_error_errno(r, "Failed to close netlink container: %m");
 
-        r = sd_rtnl_call(rtnl, m, 0, NULL);
+        r = sd_netlink_call(rtnl, m, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to add new veth interfaces (host0, %s): %m", iface_name);
 
@@ -2640,8 +2640,8 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) {
 }
 
 static int setup_bridge(const char veth_name[], int *ifi) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         int r, bridge;
 
         if (!arg_private_network)
@@ -2659,7 +2659,7 @@ static int setup_bridge(const char veth_name[], int *ifi) {
 
         *ifi = bridge;
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -2671,15 +2671,15 @@ static int setup_bridge(const char veth_name[], int *ifi) {
         if (r < 0)
                 return log_error_errno(r, "Failed to set IFF_UP flag: %m");
 
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, veth_name);
+        r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink interface name field: %m");
 
-        r = sd_rtnl_message_append_u32(m, IFLA_MASTER, bridge);
+        r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink master field: %m");
 
-        r = sd_rtnl_call(rtnl, m, 0, NULL);
+        r = sd_netlink_call(rtnl, m, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to add veth interface to bridge: %m");
 
@@ -2710,7 +2710,7 @@ static int parse_interface(struct udev *udev, const char *name) {
 
 static int move_network_interfaces(pid_t pid) {
         _cleanup_udev_unref_ struct udev *udev = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         char **i;
         int r;
 
@@ -2720,7 +2720,7 @@ static int move_network_interfaces(pid_t pid) {
         if (strv_isempty(arg_network_interfaces))
                 return 0;
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -2731,7 +2731,7 @@ static int move_network_interfaces(pid_t pid) {
         }
 
         STRV_FOREACH(i, arg_network_interfaces) {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+                _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
                 int ifi;
 
                 ifi = parse_interface(udev, *i);
@@ -2742,11 +2742,11 @@ static int move_network_interfaces(pid_t pid) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to allocate netlink message: %m");
 
-                r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
+                r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
                 if (r < 0)
                         return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
 
-                r = sd_rtnl_call(rtnl, m, 0, NULL);
+                r = sd_netlink_call(rtnl, m, 0, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
         }
@@ -2756,7 +2756,7 @@ static int move_network_interfaces(pid_t pid) {
 
 static int setup_macvlan(pid_t pid) {
         _cleanup_udev_unref_ struct udev *udev = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         unsigned idx = 0;
         char **i;
         int r;
@@ -2767,7 +2767,7 @@ static int setup_macvlan(pid_t pid) {
         if (strv_isempty(arg_network_macvlan))
                 return 0;
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -2778,7 +2778,7 @@ static int setup_macvlan(pid_t pid) {
         }
 
         STRV_FOREACH(i, arg_network_macvlan) {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+                _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
                 _cleanup_free_ char *n = NULL;
                 struct ether_addr mac;
                 int ifi;
@@ -2795,7 +2795,7 @@ static int setup_macvlan(pid_t pid) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to allocate netlink message: %m");
 
-                r = sd_rtnl_message_append_u32(m, IFLA_LINK, ifi);
+                r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink interface index: %m");
 
@@ -2805,39 +2805,39 @@ static int setup_macvlan(pid_t pid) {
 
                 strshorten(n, IFNAMSIZ-1);
 
-                r = sd_rtnl_message_append_string(m, IFLA_IFNAME, n);
+                r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink interface name: %m");
 
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
+                r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink MAC address: %m");
 
-                r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
+                r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink namespace field: %m");
 
-                r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
+                r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
                 if (r < 0)
                         return log_error_errno(r, "Failed to open netlink container: %m");
 
-                r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
+                r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
                 if (r < 0)
                         return log_error_errno(r, "Failed to open netlink container: %m");
 
-                r = sd_rtnl_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
+                r = sd_netlink_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
                 if (r < 0)
                         return log_error_errno(r, "Failed to append macvlan mode: %m");
 
-                r = sd_rtnl_message_close_container(m);
+                r = sd_netlink_message_close_container(m);
                 if (r < 0)
                         return log_error_errno(r, "Failed to close netlink container: %m");
 
-                r = sd_rtnl_message_close_container(m);
+                r = sd_netlink_message_close_container(m);
                 if (r < 0)
                         return log_error_errno(r, "Failed to close netlink container: %m");
 
-                r = sd_rtnl_call(rtnl, m, 0, NULL);
+                r = sd_netlink_call(rtnl, m, 0, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
         }
@@ -2847,7 +2847,7 @@ static int setup_macvlan(pid_t pid) {
 
 static int setup_ipvlan(pid_t pid) {
         _cleanup_udev_unref_ struct udev *udev = NULL;
-        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         char **i;
         int r;
 
@@ -2857,7 +2857,7 @@ static int setup_ipvlan(pid_t pid) {
         if (strv_isempty(arg_network_ipvlan))
                 return 0;
 
-        r = sd_rtnl_open(&rtnl);
+        r = sd_netlink_open(&rtnl);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
@@ -2868,7 +2868,7 @@ static int setup_ipvlan(pid_t pid) {
         }
 
         STRV_FOREACH(i, arg_network_ipvlan) {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+                _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
                 _cleanup_free_ char *n = NULL;
                 int ifi;
 
@@ -2880,7 +2880,7 @@ static int setup_ipvlan(pid_t pid) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to allocate netlink message: %m");
 
-                r = sd_rtnl_message_append_u32(m, IFLA_LINK, ifi);
+                r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink interface index: %m");
 
@@ -2890,35 +2890,35 @@ static int setup_ipvlan(pid_t pid) {
 
                 strshorten(n, IFNAMSIZ-1);
 
-                r = sd_rtnl_message_append_string(m, IFLA_IFNAME, n);
+                r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink interface name: %m");
 
-                r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
+                r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add netlink namespace field: %m");
 
-                r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
+                r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
                 if (r < 0)
                         return log_error_errno(r, "Failed to open netlink container: %m");
 
-                r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
+                r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
                 if (r < 0)
                         return log_error_errno(r, "Failed to open netlink container: %m");
 
-                r = sd_rtnl_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
+                r = sd_netlink_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add ipvlan mode: %m");
 
-                r = sd_rtnl_message_close_container(m);
+                r = sd_netlink_message_close_container(m);
                 if (r < 0)
                         return log_error_errno(r, "Failed to close netlink container: %m");
 
-                r = sd_rtnl_message_close_container(m);
+                r = sd_netlink_message_close_container(m);
                 if (r < 0)
                         return log_error_errno(r, "Failed to close netlink container: %m");
 
-                r = sd_rtnl_call(rtnl, m, 0, NULL);
+                r = sd_netlink_call(rtnl, m, 0, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
         }
@@ -4681,7 +4681,7 @@ int main(int argc, char *argv[]) {
                 ssize_t l;
                                 _cleanup_event_unref_ sd_event *event = NULL;
                                 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
-                                _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+                                _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
                                 char last_char = 0;
 
                 r = barrier_create(&barrier);
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 27d9129..ff8dc3a 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -124,7 +124,7 @@ void link_add_rrs(Link *l, bool force_remove) {
                 link_address_add_rrs(a, force_remove);
 }
 
-int link_update_rtnl(Link *l, sd_rtnl_message *m) {
+int link_update_rtnl(Link *l, sd_netlink_message *m) {
         const char *n = NULL;
         int r;
 
@@ -135,9 +135,9 @@ int link_update_rtnl(Link *l, sd_rtnl_message *m) {
         if (r < 0)
                 return r;
 
-        sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
+        sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
 
-        if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
+        if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
                 strncpy(l->name, n, sizeof(l->name)-1);
                 char_array_0(l->name);
         }
@@ -522,7 +522,7 @@ fail:
         log_debug_errno(r, "Failed to update address RRs: %m");
 }
 
-int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
+int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
         int r;
         assert(a);
         assert(m);
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index eee1846..e3ab27c 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -69,7 +69,7 @@ struct Link {
 
 int link_new(Manager *m, Link **ret, int ifindex);
 Link *link_free(Link *l);
-int link_update_rtnl(Link *l, sd_rtnl_message *m);
+int link_update_rtnl(Link *l, sd_netlink_message *m);
 int link_update_monitor(Link *l);
 bool link_relevant(Link *l, int family);
 LinkAddress* link_find_address(Link *l, int family, const union in_addr_union *in_addr);
@@ -82,7 +82,7 @@ void link_next_dns_server(Link *l);
 
 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr);
 LinkAddress *link_address_free(LinkAddress *a);
-int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m);
+int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m);
 bool link_address_relevant(LinkAddress *l);
 void link_address_add_rrs(LinkAddress *a, bool force_remove);
 
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index aa78885..dee5e61 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -24,7 +24,7 @@
 #include <poll.h>
 #include <netinet/in.h>
 
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "network-internal.h"
 #include "socket-util.h"
 #include "af-list.h"
@@ -41,7 +41,7 @@
 
 #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
 
-static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
         Manager *m = userdata;
         uint16_t type;
         Link *l;
@@ -51,7 +51,7 @@ static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userda
         assert(m);
         assert(mm);
 
-        r = sd_rtnl_message_get_type(mm, &type);
+        r = sd_netlink_message_get_type(mm, &type);
         if (r < 0)
                 goto fail;
 
@@ -102,7 +102,7 @@ fail:
         return 0;
 }
 
-static int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+static int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
         Manager *m = userdata;
         union in_addr_union address;
         uint16_t type;
@@ -114,7 +114,7 @@ static int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *use
         assert(mm);
         assert(m);
 
-        r = sd_rtnl_message_get_type(mm, &type);
+        r = sd_netlink_message_get_type(mm, &type);
         if (r < 0)
                 goto fail;
 
@@ -133,9 +133,9 @@ static int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *use
         switch (family) {
 
         case AF_INET:
-                r = sd_rtnl_message_read_in_addr(mm, IFA_LOCAL, &address.in);
+                r = sd_netlink_message_read_in_addr(mm, IFA_LOCAL, &address.in);
                 if (r < 0) {
-                        r = sd_rtnl_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
+                        r = sd_netlink_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
                         if (r < 0)
                                 goto fail;
                 }
@@ -143,9 +143,9 @@ static int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *use
                 break;
 
         case AF_INET6:
-                r = sd_rtnl_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
+                r = sd_netlink_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
                 if (r < 0) {
-                        r = sd_rtnl_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
+                        r = sd_netlink_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
                         if (r < 0)
                                 goto fail;
                 }
@@ -188,34 +188,34 @@ fail:
 }
 
 static int manager_rtnl_listen(Manager *m) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
-        sd_rtnl_message *i;
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *i;
         int r;
 
         assert(m);
 
         /* First, subscribe to interfaces coming and going */
-        r = sd_rtnl_open(&m->rtnl);
+        r = sd_netlink_open(&m->rtnl);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
+        r = sd_netlink_attach_event(m->rtnl, m->event, 0);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
         if (r < 0)
                 return r;
 
@@ -224,37 +224,37 @@ static int manager_rtnl_listen(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+        r = sd_netlink_call(m->rtnl, req, 0, &reply);
         if (r < 0)
                 return r;
 
-        for (i = reply; i; i = sd_rtnl_message_next(i)) {
+        for (i = reply; i; i = sd_netlink_message_next(i)) {
                 r = manager_process_link(m->rtnl, i, m);
                 if (r < 0)
                         return r;
         }
 
-        req = sd_rtnl_message_unref(req);
-        reply = sd_rtnl_message_unref(reply);
+        req = sd_netlink_message_unref(req);
+        reply = sd_netlink_message_unref(reply);
 
         /* Finally, enumerate all addresses, too */
         r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_request_dump(req, true);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+        r = sd_netlink_call(m->rtnl, req, 0, &reply);
         if (r < 0)
                 return r;
 
-        for (i = reply; i; i = sd_rtnl_message_next(i)) {
+        for (i = reply; i; i = sd_netlink_message_next(i)) {
                 r = manager_process_address(m->rtnl, i, m);
                 if (r < 0)
                         return r;
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 5a581cc..0f4ffad 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -23,7 +23,7 @@
 
 #include "sd-event.h"
 #include "sd-network.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "list.h"
 #include "hashmap.h"
 
@@ -50,7 +50,7 @@ struct Manager {
         /* Network */
         Hashmap *links;
 
-        sd_rtnl *rtnl;
+        sd_netlink *rtnl;
         sd_event_source *rtnl_event_source;
 
         sd_network_monitor *network_monitor;
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
new file mode 100644
index 0000000..3733673
--- /dev/null
+++ b/src/systemd/sd-netlink.h
@@ -0,0 +1,151 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosdnetlinkhfoo
+#define foosdnetlinkhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <netinet/in.h>
+#include <netinet/ether.h>
+#include <linux/rtnetlink.h>
+#include <linux/neighbour.h>
+
+#include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+typedef struct sd_netlink sd_netlink;
+typedef struct sd_netlink_message sd_netlink_message;
+
+/* callback */
+
+typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata);
+
+/* bus */
+int sd_netlink_new_from_netlink(sd_netlink **nl, int fd);
+int sd_netlink_open(sd_netlink **nl);
+int sd_netlink_open_fd(sd_netlink **nl, int fd);
+int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size);
+
+sd_netlink *sd_netlink_ref(sd_netlink *nl);
+sd_netlink *sd_netlink_unref(sd_netlink *nl);
+
+int sd_netlink_send(sd_netlink *nl, sd_netlink_message *message, uint32_t *serial);
+int sd_netlink_call_async(sd_netlink *nl, sd_netlink_message *message,
+                       sd_netlink_message_handler_t callback,
+                       void *userdata, uint64_t usec, uint32_t *serial);
+int sd_netlink_call_async_cancel(sd_netlink *nl, uint32_t serial);
+int sd_netlink_call(sd_netlink *nl, sd_netlink_message *message, uint64_t timeout,
+                 sd_netlink_message **reply);
+
+int sd_netlink_get_events(sd_netlink *nl);
+int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout);
+int sd_netlink_process(sd_netlink *nl, sd_netlink_message **ret);
+int sd_netlink_wait(sd_netlink *nl, uint64_t timeout);
+int sd_netlink_flush(sd_netlink *nl);
+
+int sd_netlink_add_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
+int sd_netlink_remove_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
+
+int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int priority);
+int sd_netlink_detach_event(sd_netlink *nl);
+
+int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data);
+int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data);
+int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data);
+int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data);
+int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data);
+int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data);
+int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data);
+int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info);
+
+int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type);
+int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key);
+int sd_netlink_message_close_container(sd_netlink_message *m);
+
+int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data);
+int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data);
+int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data);
+int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data);
+int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data);
+int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info);
+int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data);
+int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data);
+int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type);
+int sd_netlink_message_exit_container(sd_netlink_message *m);
+
+int sd_netlink_message_rewind(sd_netlink_message *m);
+
+sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m);
+
+sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m);
+sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m);
+
+int sd_netlink_message_request_dump(sd_netlink_message *m, int dump);
+int sd_netlink_message_is_error(sd_netlink_message *m);
+int sd_netlink_message_get_errno(sd_netlink_message *m);
+int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type);
+int sd_netlink_message_is_broadcast(sd_netlink_message *m);
+
+/* rtnl */
+
+int sd_rtnl_message_new_link(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index);
+int sd_rtnl_message_new_addr_update(sd_netlink *nl, sd_netlink_message **ret, int index, int family);
+int sd_rtnl_message_new_addr(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int family);
+int sd_rtnl_message_new_route(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, int rtm_family, unsigned char rtm_protocol);
+int sd_rtnl_message_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int nda_family);
+
+int sd_netlink_message_get_family(sd_netlink_message *m, int *family);
+
+int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
+int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope);
+int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags);
+int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen);
+int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope);
+int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags);
+int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex);
+
+int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change);
+int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type);
+int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family);
+int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex);
+int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags);
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type);
+
+int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
+int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
+int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
+int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len);
+int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len);
+
+int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags);
+int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state);
+int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *family);
+int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state);
+int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags);
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h
deleted file mode 100644
index b05690c..0000000
--- a/src/systemd/sd-rtnl.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdrtnlhfoo
-#define foosdrtnlhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <inttypes.h>
-#include <netinet/in.h>
-#include <netinet/ether.h>
-#include <linux/rtnetlink.h>
-#include <linux/neighbour.h>
-
-#include "sd-event.h"
-#include "_sd-common.h"
-
-_SD_BEGIN_DECLARATIONS;
-
-typedef struct sd_rtnl sd_rtnl;
-typedef struct sd_rtnl_message sd_rtnl_message;
-
-/* callback */
-
-typedef int (*sd_rtnl_message_handler_t)(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata);
-
-/* bus */
-int sd_rtnl_new_from_netlink(sd_rtnl **nl, int fd);
-int sd_rtnl_open(sd_rtnl **nl);
-int sd_rtnl_open_fd(sd_rtnl **nl, int fd);
-int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size);
-
-sd_rtnl *sd_rtnl_ref(sd_rtnl *nl);
-sd_rtnl *sd_rtnl_unref(sd_rtnl *nl);
-
-int sd_rtnl_send(sd_rtnl *nl, sd_rtnl_message *message, uint32_t *serial);
-int sd_rtnl_call_async(sd_rtnl *nl, sd_rtnl_message *message,
-                       sd_rtnl_message_handler_t callback,
-                       void *userdata, uint64_t usec, uint32_t *serial);
-int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial);
-int sd_rtnl_call(sd_rtnl *nl, sd_rtnl_message *message, uint64_t timeout,
-                 sd_rtnl_message **reply);
-
-int sd_rtnl_get_events(sd_rtnl *nl);
-int sd_rtnl_get_timeout(sd_rtnl *nl, uint64_t *timeout);
-int sd_rtnl_process(sd_rtnl *nl, sd_rtnl_message **ret);
-int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout);
-int sd_rtnl_flush(sd_rtnl *nl);
-
-int sd_rtnl_add_match(sd_rtnl *nl, uint16_t match, sd_rtnl_message_handler_t c, void *userdata);
-int sd_rtnl_remove_match(sd_rtnl *nl, uint16_t match, sd_rtnl_message_handler_t c, void *userdata);
-
-int sd_rtnl_attach_event(sd_rtnl *nl, sd_event *e, int priority);
-int sd_rtnl_detach_event(sd_rtnl *nl);
-
-/* messages */
-int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index);
-int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret, int index, int family);
-int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index,
-                             int family);
-int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type,
-                              int rtm_family, unsigned char rtm_protocol);
-int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index, int nda_family);
-
-sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m);
-sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m);
-
-int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump);
-int sd_rtnl_message_is_error(sd_rtnl_message *m);
-int sd_rtnl_message_get_errno(sd_rtnl_message *m);
-int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type);
-int sd_rtnl_message_is_broadcast(sd_rtnl_message *m);
-
-int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family);
-
-int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
-int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope);
-int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags);
-int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, int *family);
-int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen);
-int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope);
-int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags);
-int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex);
-
-int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change);
-int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type);
-int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family);
-int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex);
-int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags);
-int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type);
-
-int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
-int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
-int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope);
-int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family);
-int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len);
-int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len);
-
-int sd_rtnl_message_neigh_set_flags(sd_rtnl_message *m, uint8_t flags);
-int sd_rtnl_message_neigh_set_state(sd_rtnl_message *m, uint16_t state);
-int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family);
-int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *family);
-int sd_rtnl_message_neigh_get_state(sd_rtnl_message *m, uint16_t *state);
-int sd_rtnl_message_neigh_get_flags(sd_rtnl_message *m, uint8_t *flags);
-
-int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data);
-int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data);
-int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data);
-int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data);
-int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data);
-int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data);
-int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data);
-int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info);
-
-int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type);
-int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key);
-int sd_rtnl_message_close_container(sd_rtnl_message *m);
-
-int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data);
-int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data);
-int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data);
-int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data);
-int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data);
-int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info);
-int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data);
-int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data);
-int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type);
-int sd_rtnl_message_exit_container(sd_rtnl_message *m);
-
-int sd_rtnl_message_rewind(sd_rtnl_message *m);
-
-sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m);
-
-_SD_END_DECLARATIONS;
-
-#endif
diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c
new file mode 100644
index 0000000..1498432
--- /dev/null
+++ b/src/test/test-netlink-manual.c
@@ -0,0 +1,147 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Susant Sahani
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include <libkmod.h>
+
+#include "util.h"
+#include "macro.h"
+#include "sd-netlink.h"
+
+static int load_module(const char *mod_name) {
+        struct kmod_ctx *ctx;
+        struct kmod_list *list = NULL, *l;
+        int r;
+
+        ctx = kmod_new(NULL, NULL);
+        if (!ctx) {
+                kmod_unref(ctx);
+                return -ENOMEM;
+        }
+
+        r = kmod_module_new_from_lookup(ctx, mod_name, &list);
+        if (r < 0)
+                return -1;
+
+        kmod_list_foreach(l, list) {
+                struct kmod_module *mod = kmod_module_get_module(l);
+
+                r = kmod_module_probe_insert_module(mod, 0, NULL, NULL, NULL, NULL);
+                if (r >= 0)
+                        r = 0;
+                else
+                        r = -1;
+
+                kmod_module_unref(mod);
+        }
+
+        kmod_module_unref_list(list);
+        kmod_unref(ctx);
+
+        return r;
+}
+
+static int test_tunnel_configure(sd_netlink *rtnl) {
+        int r;
+        sd_netlink_message *m, *n;
+        struct in_addr local, remote;
+
+        /* skip test if module cannot be loaded */
+        r = load_module("ipip");
+        if(r < 0)
+                return EXIT_TEST_SKIP;
+
+        if(getuid() != 0)
+                return EXIT_TEST_SKIP;
+
+        /* IPIP tunnel */
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
+        assert_se(m);
+
+        assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "ipip-tunnel") >= 0);
+        assert_se(sd_netlink_message_append_u32(m, IFLA_MTU, 1234)>= 0);
+
+        assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
+
+        assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipip") >= 0);
+
+        inet_pton(AF_INET, "192.168.21.1", &local.s_addr);
+        assert_se(sd_netlink_message_append_u32(m, IFLA_IPTUN_LOCAL, local.s_addr) >= 0);
+
+        inet_pton(AF_INET, "192.168.21.2", &remote.s_addr);
+        assert_se(sd_netlink_message_append_u32(m, IFLA_IPTUN_REMOTE, remote.s_addr) >= 0);
+
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+
+        assert_se(sd_netlink_call(rtnl, m, -1, 0) == 1);
+
+        assert_se((m = sd_netlink_message_unref(m)) == NULL);
+
+        r = load_module("sit");
+        if(r < 0)
+                return EXIT_TEST_SKIP;
+
+        /* sit */
+        assert_se(sd_rtnl_message_new_link(rtnl, &n, RTM_NEWLINK, 0) >= 0);
+        assert_se(n);
+
+        assert_se(sd_netlink_message_append_string(n, IFLA_IFNAME, "sit-tunnel") >= 0);
+        assert_se(sd_netlink_message_append_u32(n, IFLA_MTU, 1234)>= 0);
+
+        assert_se(sd_netlink_message_open_container(n, IFLA_LINKINFO) >= 0);
+
+        assert_se(sd_netlink_message_open_container_union(n, IFLA_INFO_DATA, "sit") >= 0);
+
+        assert_se(sd_netlink_message_append_u8(n, IFLA_IPTUN_PROTO, IPPROTO_IPIP) >= 0);
+
+        inet_pton(AF_INET, "192.168.21.3", &local.s_addr);
+        assert_se(sd_netlink_message_append_u32(n, IFLA_IPTUN_LOCAL, local.s_addr) >= 0);
+
+        inet_pton(AF_INET, "192.168.21.4", &remote.s_addr);
+        assert_se(sd_netlink_message_append_u32(n, IFLA_IPTUN_REMOTE, remote.s_addr) >= 0);
+
+        assert_se(sd_netlink_message_close_container(n) >= 0);
+        assert_se(sd_netlink_message_close_container(n) >= 0);
+
+        assert_se(sd_netlink_call(rtnl, n, -1, 0) == 1);
+
+        assert_se((m = sd_netlink_message_unref(n)) == NULL);
+
+        return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[]) {
+        sd_netlink *rtnl;
+        int r;
+
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+        assert_se(rtnl);
+
+        r = test_tunnel_configure(rtnl);
+
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+
+        return r;
+}
diff --git a/src/test/test-rtnl-manual.c b/src/test/test-rtnl-manual.c
deleted file mode 100644
index 9fc860d..0000000
--- a/src/test/test-rtnl-manual.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Susant Sahani
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <linux/ip.h>
-#include <linux/if_tunnel.h>
-#include <libkmod.h>
-
-#include "util.h"
-#include "macro.h"
-#include "sd-rtnl.h"
-
-static int load_module(const char *mod_name) {
-        struct kmod_ctx *ctx;
-        struct kmod_list *list = NULL, *l;
-        int r;
-
-        ctx = kmod_new(NULL, NULL);
-        if (!ctx) {
-                kmod_unref(ctx);
-                return -ENOMEM;
-        }
-
-        r = kmod_module_new_from_lookup(ctx, mod_name, &list);
-        if (r < 0)
-                return -1;
-
-        kmod_list_foreach(l, list) {
-                struct kmod_module *mod = kmod_module_get_module(l);
-
-                r = kmod_module_probe_insert_module(mod, 0, NULL, NULL, NULL, NULL);
-                if (r >= 0)
-                        r = 0;
-                else
-                        r = -1;
-
-                kmod_module_unref(mod);
-        }
-
-        kmod_module_unref_list(list);
-        kmod_unref(ctx);
-
-        return r;
-}
-
-static int test_tunnel_configure(sd_rtnl *rtnl) {
-        int r;
-        sd_rtnl_message *m, *n;
-        struct in_addr local, remote;
-
-        /* skip test if module cannot be loaded */
-        r = load_module("ipip");
-        if(r < 0)
-                return EXIT_TEST_SKIP;
-
-        if(getuid() != 0)
-                return EXIT_TEST_SKIP;
-
-        /* IPIP tunnel */
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
-        assert_se(m);
-
-        assert_se(sd_rtnl_message_append_string(m, IFLA_IFNAME, "ipip-tunnel") >= 0);
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_MTU, 1234)>= 0);
-
-        assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
-
-        assert_se(sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "ipip") >= 0);
-
-        inet_pton(AF_INET, "192.168.21.1", &local.s_addr);
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_IPTUN_LOCAL, local.s_addr) >= 0);
-
-        inet_pton(AF_INET, "192.168.21.2", &remote.s_addr);
-        assert_se(sd_rtnl_message_append_u32(m, IFLA_IPTUN_REMOTE, remote.s_addr) >= 0);
-
-        assert_se(sd_rtnl_message_close_container(m) >= 0);
-        assert_se(sd_rtnl_message_close_container(m) >= 0);
-
-        assert_se(sd_rtnl_call(rtnl, m, -1, 0) == 1);
-
-        assert_se((m = sd_rtnl_message_unref(m)) == NULL);
-
-        r = load_module("sit");
-        if(r < 0)
-                return EXIT_TEST_SKIP;
-
-        /* sit */
-        assert_se(sd_rtnl_message_new_link(rtnl, &n, RTM_NEWLINK, 0) >= 0);
-        assert_se(n);
-
-        assert_se(sd_rtnl_message_append_string(n, IFLA_IFNAME, "sit-tunnel") >= 0);
-        assert_se(sd_rtnl_message_append_u32(n, IFLA_MTU, 1234)>= 0);
-
-        assert_se(sd_rtnl_message_open_container(n, IFLA_LINKINFO) >= 0);
-
-        assert_se(sd_rtnl_message_open_container_union(n, IFLA_INFO_DATA, "sit") >= 0);
-
-        assert_se(sd_rtnl_message_append_u8(n, IFLA_IPTUN_PROTO, IPPROTO_IPIP) >= 0);
-
-        inet_pton(AF_INET, "192.168.21.3", &local.s_addr);
-        assert_se(sd_rtnl_message_append_u32(n, IFLA_IPTUN_LOCAL, local.s_addr) >= 0);
-
-        inet_pton(AF_INET, "192.168.21.4", &remote.s_addr);
-        assert_se(sd_rtnl_message_append_u32(n, IFLA_IPTUN_REMOTE, remote.s_addr) >= 0);
-
-        assert_se(sd_rtnl_message_close_container(n) >= 0);
-        assert_se(sd_rtnl_message_close_container(n) >= 0);
-
-        assert_se(sd_rtnl_call(rtnl, n, -1, 0) == 1);
-
-        assert_se((m = sd_rtnl_message_unref(n)) == NULL);
-
-        return EXIT_SUCCESS;
-}
-
-int main(int argc, char *argv[]) {
-        sd_rtnl *rtnl;
-        int r;
-
-        assert_se(sd_rtnl_open(&rtnl) >= 0);
-        assert_se(rtnl);
-
-        r = test_tunnel_configure(rtnl);
-
-        assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-
-        return r;
-}
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 5610b28..63e54db 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -28,14 +28,14 @@
 #include "ethtool-util.h"
 
 #include "libudev-private.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "util.h"
 #include "log.h"
 #include "strv.h"
 #include "path-util.h"
 #include "conf-parser.h"
 #include "conf-files.h"
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "network-internal.h"
 #include "random-util.h"
 
@@ -46,7 +46,7 @@ struct link_config_ctx {
 
         bool enable_name_policy;
 
-        sd_rtnl *rtnl;
+        sd_netlink *rtnl;
 
         usec_t link_dirs_ts_usec;
 };
@@ -103,7 +103,7 @@ void link_config_ctx_free(link_config_ctx *ctx) {
 
         safe_close(ctx->ethtool_fd);
 
-        sd_rtnl_unref(ctx->rtnl);
+        sd_netlink_unref(ctx->rtnl);
 
         link_configs_free(ctx);
 
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 8d17c5e..7e16922 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -30,7 +30,7 @@
 #include <sys/wait.h>
 #include <sys/signalfd.h>
 
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "event-util.h"
 #include "formats-util.h"
 #include "process-util.h"
@@ -62,7 +62,7 @@ struct udev_event *udev_event_new(struct udev_device *dev) {
 void udev_event_unref(struct udev_event *event) {
         if (event == NULL)
                 return;
-        sd_rtnl_unref(event->rtnl);
+        sd_netlink_unref(event->rtnl);
         udev_list_cleanup(&event->run_list);
         udev_list_cleanup(&event->seclabel_list);
         free(event->program_result);
diff --git a/src/udev/udev.h b/src/udev/udev.h
index fd8504c..59751b4 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -22,7 +22,7 @@
 #include <sys/param.h>
 
 #include "macro.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
 #include "libudev.h"
 #include "libudev-private.h"
 #include "util.h"
@@ -43,7 +43,7 @@ struct udev_event {
         struct udev_list run_list;
         int exec_delay;
         usec_t birth_usec;
-        sd_rtnl *rtnl;
+        sd_netlink *rtnl;
         unsigned int builtin_run;
         unsigned int builtin_ret;
         bool inotify_watch;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 2affb59..2b1dbb8 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -45,7 +45,7 @@
 
 #include "signal-util.h"
 #include "event-util.h"
-#include "rtnl-util.h"
+#include "netlink-util.h"
 #include "cgroup-util.h"
 #include "process-util.h"
 #include "dev-setup.h"
@@ -339,7 +339,7 @@ static void worker_spawn(Manager *manager, struct event *event) {
         switch (pid) {
         case 0: {
                 struct udev_device *dev = NULL;
-                _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+                _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
                 int fd_monitor;
                 _cleanup_close_ int fd_signal = -1, fd_ep = -1;
                 struct epoll_event ep_signal = { .events = EPOLLIN };
@@ -455,7 +455,7 @@ static void worker_spawn(Manager *manager, struct event *event) {
 
                         if (udev_event->rtnl)
                                 /* in case rtnl was initialized */
-                                rtnl = sd_rtnl_ref(udev_event->rtnl);
+                                rtnl = sd_netlink_ref(udev_event->rtnl);
 
                         /* apply/restore inotify watch */
                         if (udev_event->inotify_watch) {

commit b655a0282c0869ed545fbd7a9cc2069d3afcaef2
Author: Umut Tezduyar Lindskog <umuttl at axis.com>
Date:   Fri Jun 12 14:33:48 2015 +0200

    man: mention sd_bus_message_get_creds as another way
    
    of retrieving sd_bus_creds even though sd_bus_creds itself
    contains very limited information.

diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml
index 54714de..8a193d5 100644
--- a/man/sd_bus_creds_get_pid.xml
+++ b/man/sd_bus_creds_get_pid.xml
@@ -299,10 +299,12 @@
     identified by the specified PID, with
     <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     in which case they describe the credentials of a bus peer
-    identified by the specified bus name, or with
+    identified by the specified bus name, with
     <citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     in which case they describe the credentials of the creator of a
-    bus.</para>
+    bus, or with
+    <citerefentry><refentrytitle>sd_bus_message_get_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+    in which case they describe the credentials of the sender of the message.</para>
 
     <para><function>sd_bus_creds_get_pid()</function> will retrieve
     the PID (process identifier). Similar,

commit 53318514cce4c129c9e8c97a5fba8ddbd09f1bb5
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Jun 10 15:20:02 2015 +0200

    udevd: event - don't log about failures of spawn processes when this is expected
    
    PROGRAM and IMPORT{program} uses the exit code of the spawn process to decide if a rule matches or not,
    a failing process is hence normal operation and not something we should warn about.
    
    We still warn about other types of failing processes.

diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 8d17c5e..cc97a88 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -42,6 +42,7 @@ typedef struct Spawn {
         pid_t pid;
         usec_t timeout_warn;
         usec_t timeout;
+        bool accept_failure;
 } Spawn;
 
 struct udev_event *udev_event_new(struct udev_device *dev) {
@@ -583,23 +584,24 @@ static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userd
 
         switch (si->si_code) {
         case CLD_EXITED:
-                if (si->si_status != 0)
-                        log_warning("process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
-                else {
-                        log_debug("process '%s' succeeded.", spawn->cmd);
+                if (si->si_status == 0) {
+                        log_debug("Process '%s' succeeded.", spawn->cmd);
                         sd_event_exit(sd_event_source_get_event(s), 0);
 
                         return 1;
-                }
+                } else if (spawn->accept_failure)
+                        log_debug("Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
+                else
+                        log_warning("Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
 
                 break;
         case CLD_KILLED:
         case CLD_DUMPED:
-                log_warning("process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
+                log_warning("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
 
                 break;
         default:
-                log_error("process '%s' failed due to unknown reason.", spawn->cmd);
+                log_error("Process '%s' failed due to unknown reason.", spawn->cmd);
         }
 
         sd_event_exit(sd_event_source_get_event(s), -EIO);
@@ -610,10 +612,12 @@ static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userd
 static int spawn_wait(struct udev_event *event,
                       usec_t timeout_usec,
                       usec_t timeout_warn_usec,
-                      const char *cmd, pid_t pid) {
+                      const char *cmd, pid_t pid,
+                      bool accept_failure) {
         Spawn spawn = {
                 .cmd = cmd,
                 .pid = pid,
+                .accept_failure = accept_failure,
         };
         _cleanup_event_unref_ sd_event *e = NULL;
         int r, ret;
@@ -698,6 +702,7 @@ out:
 int udev_event_spawn(struct udev_event *event,
                      usec_t timeout_usec,
                      usec_t timeout_warn_usec,
+                     bool accept_failure,
                      const char *cmd, char **envp,
                      char *result, size_t ressize) {
         int outpipe[2] = {-1, -1};
@@ -773,7 +778,7 @@ int udev_event_spawn(struct udev_event *event,
                            outpipe[READ_END], errpipe[READ_END],
                            result, ressize);
 
-                err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid);
+                err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
         }
 
 out:
@@ -930,7 +935,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_
 
                         udev_event_apply_format(event, cmd, program, sizeof(program));
                         envp = udev_device_get_properties_envp(event->dev);
-                        udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, NULL, 0);
+                        udev_event_spawn(event, timeout_usec, timeout_warn_usec, false, program, envp, NULL, 0);
                 }
         }
 }
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 7be9a23..8ebc061 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -641,7 +641,7 @@ static int import_program_into_properties(struct udev_event *event,
         int err;
 
         envp = udev_device_get_properties_envp(dev);
-        err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, result, sizeof(result));
+        err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, envp, result, sizeof(result));
         if (err < 0)
                 return err;
 
@@ -2131,7 +2131,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
                                   rules_str(rules, rule->rule.filename_off),
                                   rule->rule.filename_line);
 
-                        if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, result, sizeof(result)) < 0) {
+                        if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, envp, result, sizeof(result)) < 0) {
                                 if (cur->key.op != OP_NOMATCH)
                                         goto nomatch;
                         } else {
diff --git a/src/udev/udev.h b/src/udev/udev.h
index fd8504c..4d22f23 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -84,6 +84,7 @@ int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string,
 int udev_event_spawn(struct udev_event *event,
                      usec_t timeout_usec,
                      usec_t timeout_warn_usec,
+                     bool accept_failure,
                      const char *cmd, char **envp,
                      char *result, size_t ressize);
 void udev_event_execute_rules(struct udev_event *event,



More information about the systemd-commits mailing list