[systemd-commits] 2 commits - src/network src/systemd TODO

Tom Gundersen tomegun at kemper.freedesktop.org
Mon Jul 21 04:32:42 PDT 2014


 TODO                                    |    1 
 src/network/networkd-link.c             |   24 -
 src/network/networkd-netdev-bond.c      |   73 +----
 src/network/networkd-netdev-bond.h      |   12 
 src/network/networkd-netdev-bridge.c    |   65 -----
 src/network/networkd-netdev-bridge.h    |    6 
 src/network/networkd-netdev-dummy.c     |   56 ----
 src/network/networkd-netdev-dummy.h     |    6 
 src/network/networkd-netdev-gperf.gperf |   50 ++--
 src/network/networkd-netdev-macvlan.c   |   88 +------
 src/network/networkd-netdev-macvlan.h   |   12 
 src/network/networkd-netdev-tunnel.c    |  391 ++++++++------------------------
 src/network/networkd-netdev-tunnel.h    |   14 +
 src/network/networkd-netdev-tuntap.c    |   83 ++++--
 src/network/networkd-netdev-tuntap.h    |   12 
 src/network/networkd-netdev-veth.c      |   80 ++----
 src/network/networkd-netdev-veth.h      |    9 
 src/network/networkd-netdev-vlan.c      |   98 +-------
 src/network/networkd-netdev-vlan.h      |    8 
 src/network/networkd-netdev-vxlan.c     |   71 ++---
 src/network/networkd-netdev-vxlan.h     |   14 +
 src/network/networkd-netdev.c           |  321 ++++++++++++++++----------
 src/network/networkd-netdev.h           |  101 +++++---
 src/network/networkd-network.c          |   15 -
 src/network/sd-network.c                |   58 ----
 src/systemd/sd-network.h                |    4 
 26 files changed, 686 insertions(+), 986 deletions(-)

New commits:
commit aa9f11405829fd4755fef28602a7167dba3ddc89
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Jul 16 13:17:10 2014 +0200

    networkd: netdev - split NetDev struct into per-kind structs
    
    Similarly to how unit types work.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 7a0f30b..0a6f524 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1808,7 +1808,7 @@ static int link_enter_join_netdev(Link *link) {
                                 "MESSAGE=%-*s: enslaving by '%s'",
                                 IFNAMSIZ,
                                 link->ifname, link->network->bond->ifname,
-                                NETDEV(link->network->bond),
+                                NETDEVIF(link->network->bond),
                                 NULL);
 
                 r = netdev_join(link->network->bond, link, &netdev_join_handler);
@@ -1817,7 +1817,7 @@ static int link_enter_join_netdev(Link *link) {
                                         "MESSAGE=%-*s: could not join netdev '%s': %s",
                                         IFNAMSIZ,
                                         link->ifname, link->network->bond->ifname, strerror(-r),
-                                        NETDEV(link->network->bond),
+                                        NETDEVIF(link->network->bond),
                                         NULL);
                         link_enter_failed(link);
                         return r;
@@ -1831,7 +1831,7 @@ static int link_enter_join_netdev(Link *link) {
                                 "MESSAGE=%-*s: enslaving by '%s'",
                                 IFNAMSIZ,
                                 link->ifname, link->network->bridge->ifname,
-                                NETDEV(link->network->bridge),
+                                NETDEVIF(link->network->bridge),
                                 NULL);
 
                 r = netdev_join(link->network->bridge, link, &netdev_join_handler);
@@ -1840,7 +1840,7 @@ static int link_enter_join_netdev(Link *link) {
                                         "MESSAGE=%-*s: could not join netdev '%s': %s",
                                         IFNAMSIZ,
                                         link->ifname, link->network->bridge->ifname, strerror(-r),
-                                        NETDEV(link->network->bridge),
+                                        NETDEVIF(link->network->bridge),
                                         NULL);
                         link_enter_failed(link);
                         return r;
@@ -1854,7 +1854,7 @@ static int link_enter_join_netdev(Link *link) {
                                 "MESSAGE=%-*s: enslaving by '%s'",
                                 IFNAMSIZ,
                                 link->ifname, link->network->tunnel->ifname,
-                                NETDEV(link->network->tunnel),
+                                NETDEVIF(link->network->tunnel),
                                 NULL);
 
                 r = netdev_join(link->network->tunnel, link, &netdev_join_handler);
@@ -1863,7 +1863,7 @@ static int link_enter_join_netdev(Link *link) {
                                         "MESSAGE=%-*s: could not join netdev '%s': %s",
                                         IFNAMSIZ,
                                         link->ifname, link->network->tunnel->ifname, strerror(-r),
-                                        NETDEV(link->network->tunnel),
+                                        NETDEVIF(link->network->tunnel),
                                         NULL);
                         link_enter_failed(link);
                         return r;
@@ -1876,7 +1876,7 @@ static int link_enter_join_netdev(Link *link) {
                 log_struct_link(LOG_DEBUG, link,
                                 "MESSAGE=%-*s: enslaving by '%s'",
                                 IFNAMSIZ,
-                                link->ifname, vlan->ifname, NETDEV(vlan), NULL);
+                                link->ifname, vlan->ifname, NETDEVIF(vlan), NULL);
 
                 r = netdev_join(vlan, link, &netdev_join_handler);
                 if (r < 0) {
@@ -1884,7 +1884,7 @@ static int link_enter_join_netdev(Link *link) {
                                         "MESSAGE=%-*s: could not join netdev '%s': %s",
                                         IFNAMSIZ,
                                         link->ifname, vlan->ifname, strerror(-r),
-                                        NETDEV(vlan), NULL);
+                                        NETDEVIF(vlan), NULL);
                         link_enter_failed(link);
                         return r;
                 }
@@ -1896,7 +1896,7 @@ static int link_enter_join_netdev(Link *link) {
                 log_struct_link(LOG_DEBUG, link,
                                 "MESSAGE=%-*s: enslaving by '%s'",
                                 IFNAMSIZ,
-                                link->ifname, macvlan->ifname, NETDEV(macvlan), NULL);
+                                link->ifname, macvlan->ifname, NETDEVIF(macvlan), NULL);
 
                 r = netdev_join(macvlan, link, &netdev_join_handler);
                 if (r < 0) {
@@ -1904,7 +1904,7 @@ static int link_enter_join_netdev(Link *link) {
                                         "MESSAGE=%-*s: could not join netdev '%s': %s",
                                         IFNAMSIZ,
                                         link->ifname, macvlan->ifname, strerror(-r),
-                                        NETDEV(macvlan), NULL);
+                                        NETDEVIF(macvlan), NULL);
                         link_enter_failed(link);
                         return r;
                 }
@@ -1916,7 +1916,7 @@ static int link_enter_join_netdev(Link *link) {
                 log_struct_link(LOG_DEBUG, link,
                                 "MESSAGE=%*s: enslaving by '%s'",
                                 IFNAMSIZ,
-                                link->ifname, vxlan->ifname, NETDEV(vxlan), NULL);
+                                link->ifname, vxlan->ifname, NETDEVIF(vxlan), NULL);
 
                 r = netdev_join(vxlan, link, &netdev_join_handler);
                 if (r < 0) {
@@ -1924,7 +1924,7 @@ static int link_enter_join_netdev(Link *link) {
                                         "MESSAGE=%*s: could not join netdev '%s': %s",
                                         IFNAMSIZ,
                                         link->ifname, vxlan->ifname, strerror(-r),
-                                        NETDEV(vxlan), NULL);
+                                        NETDEVIF(vxlan), NULL);
                         link_enter_failed(link);
                         return r;
                 }
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 561ca2a..562f9eb 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -63,49 +63,18 @@ static uint8_t bond_mode_to_kernel(BondMode mode) {
         }
 }
 
-static int netdev_bond_fill_message_create(NetDev *netdev, sd_rtnl_message *m) {
+static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        Bond *b = BOND(netdev);
         int r;
 
+        assert(netdev);
+        assert(!link);
+        assert(b);
         assert(m);
 
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
-                                                 netdev_kind_to_string(netdev->kind));
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->bond_mode != _NETDEV_BOND_MODE_INVALID) {
+        if (b->mode != _NETDEV_BOND_MODE_INVALID) {
                 r = sd_rtnl_message_append_u8(m, IFLA_BOND_MODE,
-                                              bond_mode_to_kernel(netdev->bond_mode));
+                                              bond_mode_to_kernel(b->mode));
                 if (r < 0) {
                         log_error_netdev(netdev,
                                          "Could not append IFLA_BOND_MODE attribute: %s",
@@ -114,26 +83,22 @@ static int netdev_bond_fill_message_create(NetDev *netdev, sd_rtnl_message *m) {
                 }
         }
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
+        return 0;
+}
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
+static void bond_init(NetDev *netdev) {
+        Bond *b = BOND(netdev);
+
+        assert(netdev);
+        assert(b);
 
-        return r;
+        b->mode = _NETDEV_BOND_MODE_INVALID;
 }
 
 const NetDevVTable bond_vtable = {
+        .object_size = sizeof(Bond),
+        .init = bond_init,
+        .sections = "Match\0NetDev\0Bond\0",
         .fill_message_create = netdev_bond_fill_message_create,
-        .enslave = netdev_enslave,
+        .create_type = NETDEV_CREATE_MASTER,
 };
diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h
index 03ef081..09731b7 100644
--- a/src/network/networkd-netdev-bond.h
+++ b/src/network/networkd-netdev-bond.h
@@ -21,9 +21,9 @@
 
 #pragma once
 
-#include "networkd-netdev.h"
+typedef struct Bond Bond;
 
-extern const NetDevVTable bond_vtable;
+#include "networkd-netdev.h"
 
 typedef enum BondMode {
         NETDEV_BOND_MODE_BALANCE_RR,
@@ -37,6 +37,14 @@ typedef enum BondMode {
         _NETDEV_BOND_MODE_INVALID = -1
 } BondMode;
 
+struct Bond {
+        NetDev meta;
+
+        BondMode mode;
+};
+
+extern const NetDevVTable bond_vtable;
+
 const char *bond_mode_to_string(BondMode d) _const_;
 BondMode bond_mode_from_string(const char *d) _pure_;
 
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 7ae304e..91b7051 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -28,67 +28,8 @@
 #include "networkd-netdev-bridge.h"
 #include "missing.h"
 
-static int netdev_bridge_fill_message_create(NetDev *netdev, sd_rtnl_message *m) {
-        int r;
-
-        assert(netdev);
-        assert(netdev->ifname);
-        assert(m);
-
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "bridge");
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        return r;
-}
-
 const NetDevVTable bridge_vtable = {
-        .fill_message_create = netdev_bridge_fill_message_create,
-        .enslave = netdev_enslave,
+        .object_size = sizeof(Bridge),
+        .sections = "Match\0NetDev\0",
+        .create_type = NETDEV_CREATE_MASTER,
 };
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index 4d971c6..a7d02b1 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -21,6 +21,12 @@
 
 #pragma once
 
+typedef struct Bridge Bridge;
+
 #include "networkd-netdev.h"
 
+struct Bridge {
+        NetDev meta;
+};
+
 extern const NetDevVTable bridge_vtable;
diff --git a/src/network/networkd-netdev-dummy.c b/src/network/networkd-netdev-dummy.c
index 2f861a7..01c10a2 100644
--- a/src/network/networkd-netdev-dummy.c
+++ b/src/network/networkd-netdev-dummy.c
@@ -28,58 +28,8 @@
 #include "sd-rtnl.h"
 #include "networkd-netdev-dummy.h"
 
-static int netdev_dummy_fill_message_create(NetDev *netdev, sd_rtnl_message *m) {
-        int r;
-
-        assert(netdev);
-        assert(netdev->ifname);
-        assert(m);
-
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "dummy");
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        return r;
-}
-
 const NetDevVTable dummy_vtable = {
-        .fill_message_create = netdev_dummy_fill_message_create,
+        .object_size = sizeof(Dummy),
+        .sections = "Match\0NetDev\0",
+        .create_type = NETDEV_CREATE_INDEPENDENT,
 };
diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h
index dcbd3cc..0d321e5 100644
--- a/src/network/networkd-netdev-dummy.h
+++ b/src/network/networkd-netdev-dummy.h
@@ -21,6 +21,12 @@
 
 #pragma once
 
+typedef struct Dummy Dummy;
+
 #include "networkd-netdev.h"
 
+struct Dummy {
+        NetDev meta;
+};
+
 extern const NetDevVTable dummy_vtable;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 090dfb3..b46b8db 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -27,28 +27,28 @@ NetDev.Name,             config_parse_ifname,                0,
 NetDev.Kind,             config_parse_netdev_kind,           0,                             offsetof(NetDev, kind)
 NetDev.MTUBytes,         config_parse_iec_size,              0,                             offsetof(NetDev, mtu)
 NetDev.MACAddress,       config_parse_hwaddr,                0,                             offsetof(NetDev, mac)
-VLAN.Id,                 config_parse_uint64,                0,                             offsetof(NetDev, vlanid)
-MACVLAN.Mode,            config_parse_macvlan_mode,          0,                             offsetof(NetDev, macvlan_mode)
-Tunnel.Local,            config_parse_tunnel_address,        0,                             offsetof(NetDev, local)
-Tunnel.Remote,           config_parse_tunnel_address,        0,                             offsetof(NetDev, remote)
-Tunnel.TOS,              config_parse_unsigned,              0,                             offsetof(NetDev, tos)
-Tunnel.TTL,              config_parse_unsigned,              0,                             offsetof(NetDev, ttl)
-Tunnel.DiscoverPathMTU,  config_parse_bool,                  0,                             offsetof(NetDev, tunnel_pmtudisc)
-Peer.Name,               config_parse_ifname,                0,                             offsetof(NetDev, ifname_peer)
-Peer.MACAddress,         config_parse_hwaddr,                0,                             offsetof(NetDev, mac_peer)
-VXLAN.Id,                config_parse_uint64,                0,                             offsetof(NetDev, vxlanid)
-VXLAN.Group,             config_parse_tunnel_address,        0,                             offsetof(NetDev, group)
-VXLAN.TOS,               config_parse_unsigned,              0,                             offsetof(NetDev, tos)
-VXLAN.TTL,               config_parse_unsigned,              0,                             offsetof(NetDev, ttl)
-VXLAN.MacLearning,       config_parse_bool,                  0,                             offsetof(NetDev, learning)
-Tun.OneQueue,            config_parse_bool,                  0,                             offsetof(NetDev, one_queue)
-Tun.MultiQueue,          config_parse_bool,                  0,                             offsetof(NetDev, multi_queue)
-Tun.PacketInfo,          config_parse_bool,                  0,                             offsetof(NetDev, packet_info)
-Tun.User,                config_parse_string,                0,                             offsetof(NetDev, user_name)
-Tun.Group,               config_parse_string,                0,                             offsetof(NetDev, group_name)
-Tap.OneQueue,            config_parse_bool,                  0,                             offsetof(NetDev, one_queue)
-Tap.MultiQueue,          config_parse_bool,                  0,                             offsetof(NetDev, multi_queue)
-Tap.PacketInfo,          config_parse_bool,                  0,                             offsetof(NetDev, packet_info)
-Tap.User,                config_parse_string,                0,                             offsetof(NetDev, user_name)
-Tap.Group,               config_parse_string,                0,                             offsetof(NetDev, group_name)
-Bond.Mode,               config_parse_bond_mode,             0,                             offsetof(NetDev, bond_mode)
+VLAN.Id,                 config_parse_uint64,                0,                             offsetof(VLan, id)
+MACVLAN.Mode,            config_parse_macvlan_mode,          0,                             offsetof(MacVlan, mode)
+Tunnel.Local,            config_parse_tunnel_address,        0,                             offsetof(Tunnel, local)
+Tunnel.Remote,           config_parse_tunnel_address,        0,                             offsetof(Tunnel, remote)
+Tunnel.TOS,              config_parse_unsigned,              0,                             offsetof(Tunnel, tos)
+Tunnel.TTL,              config_parse_unsigned,              0,                             offsetof(Tunnel, ttl)
+Tunnel.DiscoverPathMTU,  config_parse_bool,                  0,                             offsetof(Tunnel, pmtudisc)
+Peer.Name,               config_parse_ifname,                0,                             offsetof(Veth, ifname_peer)
+Peer.MACAddress,         config_parse_hwaddr,                0,                             offsetof(Veth, mac_peer)
+VXLAN.Id,                config_parse_uint64,                0,                             offsetof(VxLan, id)
+VXLAN.Group,             config_parse_tunnel_address,        0,                             offsetof(VxLan, group)
+VXLAN.TOS,               config_parse_unsigned,              0,                             offsetof(VxLan, tos)
+VXLAN.TTL,               config_parse_unsigned,              0,                             offsetof(VxLan, ttl)
+VXLAN.MacLearning,       config_parse_bool,                  0,                             offsetof(VxLan, learning)
+Tun.OneQueue,            config_parse_bool,                  0,                             offsetof(TunTap, one_queue)
+Tun.MultiQueue,          config_parse_bool,                  0,                             offsetof(TunTap, multi_queue)
+Tun.PacketInfo,          config_parse_bool,                  0,                             offsetof(TunTap, packet_info)
+Tun.User,                config_parse_string,                0,                             offsetof(TunTap, user_name)
+Tun.Group,               config_parse_string,                0,                             offsetof(TunTap, group_name)
+Tap.OneQueue,            config_parse_bool,                  0,                             offsetof(TunTap, one_queue)
+Tap.MultiQueue,          config_parse_bool,                  0,                             offsetof(TunTap, multi_queue)
+Tap.PacketInfo,          config_parse_bool,                  0,                             offsetof(TunTap, packet_info)
+Tap.User,                config_parse_string,                0,                             offsetof(TunTap, user_name)
+Tap.Group,               config_parse_string,                0,                             offsetof(TunTap, group_name)
+Bond.Mode,               config_parse_bond_mode,             0,                             offsetof(Bond, mode)
diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c
index bfa1ff1..2e5554a 100644
--- a/src/network/networkd-netdev-macvlan.c
+++ b/src/network/networkd-netdev-macvlan.c
@@ -37,67 +37,16 @@ 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) {
+        MacVlan *m = MACVLAN(netdev);
         int r;
 
         assert(netdev);
-        assert(netdev->kind == NETDEV_KIND_MACVLAN);
+        assert(m);
         assert(link);
         assert(netdev->ifname);
 
-        r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINK attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->mtu) {
-                r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_MTU attribute: %s",
-                                         strerror(-r));
-                        return r;
-                }
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not open IFLA_LINKINFO container: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, "macvlan");
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not open IFLA_INFO_DATA container: %s",
-                                  strerror(-r));
-                return r;
-        }
-
-        if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
-        r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
+        if (m->mode != _NETDEV_MACVLAN_MODE_INVALID) {
+        r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_MACVLAN_MODE attribute: %s",
@@ -106,25 +55,22 @@ static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_rtn
                 }
         }
 
-        r = sd_rtnl_message_close_container(req);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not close IFLA_INFO_DATA container %s",
-                                 strerror(-r));
-                return r;
-        }
+        return 0;
+}
 
-        r = sd_rtnl_message_close_container(req);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not close IFLA_LINKINFO container %s",
-                                 strerror(-r));
-                return r;
-        }
+static void macvlan_init(NetDev *n) {
+        MacVlan *m = MACVLAN(n);
 
-        return 0;
+        assert(n);
+        assert(m);
+
+        m->mode = _NETDEV_MACVLAN_MODE_INVALID;
 }
 
 const NetDevVTable macvlan_vtable = {
-        .fill_message_create_on_link = netdev_macvlan_fill_message_create,
+        .object_size = sizeof(MacVlan),
+        .init = macvlan_init,
+        .sections = "Match\0NetDev\0MACVLAN\0",
+        .fill_message_create = netdev_macvlan_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
 };
diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h
index ea268cc..d61efc1 100644
--- a/src/network/networkd-netdev-macvlan.h
+++ b/src/network/networkd-netdev-macvlan.h
@@ -21,9 +21,9 @@
 
 #pragma once
 
-#include "networkd-netdev.h"
+typedef struct MacVlan MacVlan;
 
-extern const NetDevVTable macvlan_vtable;
+#include "networkd-netdev.h"
 
 typedef enum MacVlanMode {
         NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
@@ -34,6 +34,14 @@ typedef enum MacVlanMode {
         _NETDEV_MACVLAN_MODE_INVALID = -1
 } MacVlanMode;
 
+struct MacVlan {
+        NetDev meta;
+
+        MacVlanMode mode;
+};
+
+extern const NetDevVTable macvlan_vtable;
+
 const char *macvlan_mode_to_string(MacVlanMode d) _const_;
 MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
 
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index 2ecfef8..4561f8d 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -33,61 +33,14 @@
 #include "conf-parser.h"
 
 static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        Tunnel *t = IPIP(netdev);
         int r;
 
         assert(netdev);
-        assert(netdev->kind == NETDEV_KIND_IPIP);
-        assert(netdev->ifname);
-        assert(netdev->manager);
-        assert(netdev->manager->rtnl);
         assert(link);
         assert(m);
-        assert(netdev->family == AF_INET);
-
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if(netdev->mtu) {
-                r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_MTU attribute: %s",
-                                         strerror(-r));
-                        return r;
-                }
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
-                                                 netdev_kind_to_string(netdev->kind));
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
+        assert(t);
+        assert(t->family == AF_INET);
 
         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
         if (r < 0) {
@@ -97,7 +50,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &netdev->local.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
@@ -105,7 +58,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &netdev->remote.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
@@ -113,7 +66,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
                 return r;
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, netdev->ttl);
+        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_TTL  attribute: %s",
@@ -121,81 +74,18 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
                 return r;
         }
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
         return r;
 }
 
 static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        Tunnel *t = SIT(netdev);
         int r;
 
         assert(netdev);
-        assert(netdev->kind == NETDEV_KIND_SIT);
-        assert(netdev->ifname);
-        assert(netdev->manager);
-        assert(netdev->manager->rtnl);
         assert(link);
         assert(m);
-        assert(netdev->family == AF_INET);
-
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if(netdev->mtu) {
-                r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_MTU attribute: %s",
-                                         strerror(-r));
-                        return r;
-                }
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
-                                                 netdev_kind_to_string(netdev->kind));
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
+        assert(t);
+        assert(t->family == AF_INET);
 
         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
         if (r < 0) {
@@ -205,7 +95,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &netdev->local.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
@@ -213,7 +103,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &netdev->remote.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
@@ -221,7 +111,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, netdev->ttl);
+        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_TTL  attribute: %s",
@@ -229,81 +119,18 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
         return r;
 }
 
 static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        Tunnel *t = GRE(netdev);
         int r;
 
         assert(netdev);
-        assert(netdev->kind == NETDEV_KIND_GRE);
-        assert(netdev->ifname);
-        assert(netdev->manager);
-        assert(netdev->manager->rtnl);
         assert(link);
         assert(m);
-        assert(netdev->family == AF_INET);
-
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if(netdev->mtu) {
-                r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_MTU attribute: %s",
-                                         strerror(-r));
-                        return r;
-                }
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
-                                                 netdev_kind_to_string(netdev->kind));
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
+        assert(t);
+        assert(t->family == AF_INET);
 
         r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
         if (r < 0) {
@@ -313,7 +140,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &netdev->local.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_GRE_LOCAL attribute: %s",
@@ -321,7 +148,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &netdev->remote.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_GRE_REMOTE attribute: %s",
@@ -329,7 +156,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, netdev->ttl);
+        r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_GRE_TTL attribute: %s",
@@ -337,7 +164,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, netdev->tos);
+        r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, t->tos);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_GRE_TOS attribute: %s",
@@ -345,81 +172,18 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
         return r;
 }
 
 static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        Tunnel *t = VTI(netdev);
         int r;
 
         assert(netdev);
-        assert(netdev->kind == NETDEV_KIND_VTI);
-        assert(netdev->ifname);
-        assert(netdev->manager);
-        assert(netdev->manager->rtnl);
         assert(link);
         assert(m);
-        assert(netdev->family == AF_INET);
-
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if(netdev->mtu) {
-                r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_MTU attribute: %s",
-                                         strerror(-r));
-                        return r;
-                }
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
-                                                 netdev_kind_to_string(netdev->kind));
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
+        assert(t);
+        assert(t->family == AF_INET);
 
         r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
         if (r < 0) {
@@ -429,7 +193,7 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &netdev->local.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
@@ -437,7 +201,7 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &netdev->remote.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
@@ -445,40 +209,45 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
                 return r;
         }
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
         return r;
 }
 
 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
+        Tunnel *t = NULL;
+
         assert(netdev);
         assert(filename);
 
-        if (netdev->local.in.s_addr == INADDR_ANY) {
+        switch (netdev->kind) {
+        case NETDEV_KIND_IPIP:
+                t = IPIP(netdev);
+                break;
+        case NETDEV_KIND_SIT:
+                t = SIT(netdev);
+                break;
+        case NETDEV_KIND_GRE:
+                t = GRE(netdev);
+                break;
+        case NETDEV_KIND_VTI:
+                t = VTI(netdev);
+                break;
+        default:
+                assert_not_reached("Invalid tunnel kind");
+        }
+
+        assert(t);
+
+        if (t->local.in.s_addr == INADDR_ANY) {
                log_warning("Tunnel without local address configured in %s. Ignoring", filename);
                return -EINVAL;
         }
 
-        if (netdev->remote.in.s_addr == INADDR_ANY) {
+        if (t->remote.in.s_addr == INADDR_ANY) {
                log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
                return -EINVAL;
         }
 
-        if (netdev->family != AF_INET) {
+        if (t->family != AF_INET) {
               log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
               return -EINVAL;
         }
@@ -496,7 +265,7 @@ int config_parse_tunnel_address(const char *unit,
                                 const char *rvalue,
                                 void *data,
                                 void *userdata) {
-        NetDev *n = userdata;
+        Tunnel *t = userdata;
         union in_addr_union *addr = data;
         int r;
 
@@ -505,7 +274,7 @@ int config_parse_tunnel_address(const char *unit,
         assert(rvalue);
         assert(data);
 
-        r = net_parse_inaddr(rvalue, &n->family, addr);
+        r = net_parse_inaddr(rvalue, &t->family, addr);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                            "Tunnel address is invalid, ignoring assignment: %s", rvalue);
@@ -515,22 +284,74 @@ int config_parse_tunnel_address(const char *unit,
         return 0;
 }
 
+static void ipip_init(NetDev *n) {
+        Tunnel *t = IPIP(n);
+
+        assert(n);
+        assert(t);
+
+        t->pmtudisc = true;
+}
+
+static void sit_init(NetDev *n) {
+        Tunnel *t = SIT(n);
+
+        assert(n);
+        assert(t);
+
+        t->pmtudisc = true;
+}
+
+static void vti_init(NetDev *n) {
+        Tunnel *t = VTI(n);
+
+        assert(n);
+        assert(t);
+
+        t->pmtudisc = true;
+}
+
+static void gre_init(NetDev *n) {
+        Tunnel *t = GRE(n);
+
+        assert(n);
+        assert(t);
+
+        t->pmtudisc = true;
+}
+
 const NetDevVTable ipip_vtable = {
-        .fill_message_create_on_link = netdev_ipip_fill_message_create,
+        .object_size = sizeof(Tunnel),
+        .init = ipip_init,
+        .sections = "Match\0NetDev\0Tunnel\0",
+        .fill_message_create = netdev_ipip_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
 
 const NetDevVTable sit_vtable = {
-        .fill_message_create_on_link = netdev_sit_fill_message_create,
+        .object_size = sizeof(Tunnel),
+        .init = sit_init,
+        .sections = "Match\0NetDev\0Tunnel\0",
+        .fill_message_create = netdev_sit_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
 
 const NetDevVTable vti_vtable = {
-        .fill_message_create_on_link = netdev_vti_fill_message_create,
+        .object_size = sizeof(Tunnel),
+        .init = vti_init,
+        .sections = "Match\0NetDev\0Tunnel\0",
+        .fill_message_create = netdev_vti_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
 
 const NetDevVTable gre_vtable = {
-        .fill_message_create_on_link = netdev_gre_fill_message_create,
+        .object_size = sizeof(Tunnel),
+        .init = gre_init,
+        .sections = "Match\0NetDev\0Tunnel\0",
+        .fill_message_create = netdev_gre_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h
index b30204b..000a646 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/networkd-netdev-tunnel.h
@@ -21,8 +21,22 @@
 
 #pragma once
 
+typedef struct Tunnel Tunnel;
+
 #include "networkd-netdev.h"
 
+struct Tunnel {
+        NetDev meta;
+
+        int family;
+
+        unsigned ttl;
+        unsigned tos;
+        union in_addr_union local;
+        union in_addr_union remote;
+        bool pmtudisc;
+};
+
 extern const NetDevVTable ipip_vtable;
 extern const NetDevVTable sit_vtable;
 extern const NetDevVTable vti_vtable;
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 8f60461..dd3bd96 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -28,24 +28,27 @@
 #define TUN_DEV "/dev/net/tun"
 
 static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
+        TunTap *t;
 
         assert(netdev);
+        assert(netdev->ifname);
         assert(ifr);
 
-        memset(ifr, 0, sizeof(*ifr));
-
-        if (netdev->kind == NETDEV_KIND_TAP)
+        if (netdev->kind == NETDEV_KIND_TAP) {
+                t = TAP(netdev);
                 ifr->ifr_flags |= IFF_TAP;
-        else
+        } else {
+                t = TUN(netdev);
                 ifr->ifr_flags |= IFF_TUN;
+        }
 
-        if (!netdev->packet_info)
+        if (!t->packet_info)
                 ifr->ifr_flags |= IFF_NO_PI;
 
-        if (netdev->one_queue)
+        if (t->one_queue)
                 ifr->ifr_flags |= IFF_ONE_QUEUE;
 
-        if (netdev->multi_queue)
+        if (t->multi_queue)
                 ifr->ifr_flags |= IFF_MULTI_QUEUE;
 
         strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
@@ -55,12 +58,16 @@ static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
 
 static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
         _cleanup_close_ int fd;
+        TunTap *t = NULL;
         const char *user;
         const char *group;
         uid_t uid;
         gid_t gid;
         int r = 0;
 
+        assert(netdev);
+        assert(ifr);
+
         fd = open(TUN_DEV, O_RDWR);
         if (fd < 0) {
                 log_error_netdev(netdev,
@@ -77,14 +84,21 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
                 return r;
         }
 
-        if(netdev->user_name) {
+        if (netdev->kind == NETDEV_KIND_TAP)
+                t = TAP(netdev);
+        else
+                t = TUN(netdev);
+
+        assert(t);
 
-                user = netdev->user_name;
+        if(t->user_name) {
+
+                user = t->user_name;
 
                 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
                 if (r < 0) {
                         log_error("Cannot resolve user name %s: %s",
-                                  netdev->user_name, strerror(-r));
+                                  t->user_name, strerror(-r));
                         return 0;
                 }
 
@@ -96,14 +110,14 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
                 }
         }
 
-        if(netdev->group_name) {
+        if(t->group_name) {
 
-                group = netdev->group_name;
+                group = t->group_name;
 
                 r = get_group_creds(&group, &gid);
                 if (r < 0) {
                         log_error("Cannot resolve group name %s: %s",
-                                  netdev->group_name, strerror(-r));
+                                  t->group_name, strerror(-r));
                         return 0;
                 }
 
@@ -129,34 +143,47 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
 }
 
 static int netdev_create_tuntap(NetDev *netdev) {
-        struct ifreq ifr;
+        struct ifreq ifr = {};
         int r;
 
-        assert(netdev);
-        assert(netdev->ifname);
-
-        switch(netdev->kind) {
-        case NETDEV_KIND_TUN:
-        case NETDEV_KIND_TAP:
-                break;
-        default:
-                return -ENOTSUP;
-        }
-
         r = netdev_fill_tuntap_message(netdev, &ifr);
         if(r < 0)
                 return r;
 
-        log_debug_netdev(netdev, "Creating tuntap netdev: %s",
-                         netdev_kind_to_string(netdev->kind));
-
         return netdev_tuntap_add(netdev, &ifr);
 }
 
+static void tuntap_done(NetDev *netdev) {
+        TunTap *t = NULL;
+
+        assert(netdev);
+
+        if (netdev->kind == NETDEV_KIND_TUN)
+                t = TUN(netdev);
+        else
+                t = TAP(netdev);
+
+        assert(t);
+
+        free(t->user_name);
+        t->user_name = NULL;
+
+        free(t->group_name);
+        t->group_name = NULL;
+}
+
 const NetDevVTable tun_vtable = {
+        .object_size = sizeof(TunTap),
+        .sections = "Match\0NetDev\0Tun\0",
+        .done = tuntap_done,
         .create = netdev_create_tuntap,
+        .create_type = NETDEV_CREATE_INDEPENDENT,
 };
 
 const NetDevVTable tap_vtable = {
+        .object_size = sizeof(TunTap),
+        .sections = "Match\0NetDev\0Tap\0",
+        .done = tuntap_done,
         .create = netdev_create_tuntap,
+        .create_type = NETDEV_CREATE_INDEPENDENT,
 };
diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h
index 2b6e48f..b804875 100644
--- a/src/network/networkd-netdev-tuntap.h
+++ b/src/network/networkd-netdev-tuntap.h
@@ -21,7 +21,19 @@
 
 #pragma once
 
+typedef struct TunTap TunTap;
+
 #include "networkd-netdev.h"
 
+struct TunTap {
+        NetDev meta;
+
+        char *user_name;
+        char *group_name;
+        bool one_queue;
+        bool multi_queue;
+        bool packet_info;
+};
+
 extern const NetDevVTable tun_vtable;
 extern const NetDevVTable tap_vtable;
diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c
index c995bbb..da09ef9 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/networkd-netdev-veth.c
@@ -27,47 +27,15 @@
 #include "sd-rtnl.h"
 #include "networkd-netdev-veth.h"
 
-static int netdev_veth_fill_message_create(NetDev *netdev, sd_rtnl_message *m) {
+static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        Veth *v = VETH(netdev);
         int r;
 
         assert(netdev);
-        assert(netdev->ifname);
+        assert(!link);
+        assert(v);
         assert(m);
 
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "veth");
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
         r = sd_rtnl_message_open_container(m, VETH_INFO_PEER);
         if (r < 0) {
                 log_error_netdev(netdev,
@@ -76,16 +44,16 @@ static int netdev_veth_fill_message_create(NetDev *netdev, sd_rtnl_message *m) {
                 return r;
         }
 
-        if (netdev->ifname_peer) {
-                r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname_peer);
+        if (v->ifname_peer) {
+                r = sd_rtnl_message_append_string(m, IFLA_IFNAME, v->ifname_peer);
                 if (r < 0) {
                         log_error("Failed to add netlink interface name: %s", strerror(-r));
                         return r;
                 }
         }
 
-        if (netdev->mac_peer) {
-                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac_peer);
+        if (v->mac_peer) {
+                r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, v->mac_peer);
                 if (r < 0) {
                         log_error_netdev(netdev,
                                          "Could not append IFLA_ADDRESS attribute: %s",
@@ -102,34 +70,28 @@ static int netdev_veth_fill_message_create(NetDev *netdev, sd_rtnl_message *m) {
                 return r;
         }
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
         return r;
 }
 
 static int netdev_veth_verify(NetDev *netdev, const char *filename) {
+        Veth *v = VETH(netdev);
         int r;
 
         assert(netdev);
+        assert(v);
         assert(filename);
 
-        if (!netdev->ifname_peer) {
+        if (!v->ifname_peer) {
                 log_warning("Veth NetDev without peer name configured in %s. Ignoring",
                             filename);
                 return -EINVAL;
         }
 
-        if (!netdev->mac_peer) {
-                r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
+        if (!v->mac_peer) {
+                r = netdev_get_mac(v->ifname_peer, &v->mac_peer);
                 if (r < 0) {
                         log_warning("Failed to generate predictable MAC address for %s. Ignoring",
-                                  netdev->ifname_peer);
+                                  v->ifname_peer);
                         return -EINVAL;
                 }
         }
@@ -137,7 +99,21 @@ static int netdev_veth_verify(NetDev *netdev, const char *filename) {
         return 0;
 }
 
+static void veth_done(NetDev *n) {
+        Veth *v = VETH(n);
+
+        assert(n);
+        assert(v);
+
+        free(v->ifname_peer);
+        free(v->mac_peer);
+}
+
 const NetDevVTable veth_vtable = {
+        .object_size = sizeof(Veth),
+        .sections = "Match\0NetDev\0Peer\0",
+        .done = veth_done,
         .fill_message_create = netdev_veth_fill_message_create,
+        .create_type = NETDEV_CREATE_INDEPENDENT,
         .config_verify = netdev_veth_verify,
 };
diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h
index 93dcdfa..85d8b49 100644
--- a/src/network/networkd-netdev-veth.h
+++ b/src/network/networkd-netdev-veth.h
@@ -21,6 +21,15 @@
 
 #pragma once
 
+typedef struct Veth Veth;
+
 #include "networkd-netdev.h"
 
+struct Veth {
+        NetDev meta;
+
+        char *ifname_peer;
+        struct ether_addr *mac_peer;
+};
+
 extern const NetDevVTable veth_vtable;
diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c
index b625f4b..13c4456 100644
--- a/src/network/networkd-netdev-vlan.c
+++ b/src/network/networkd-netdev-vlan.c
@@ -26,68 +26,16 @@
 #include "list.h"
 
 static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *req) {
+        VLan *v = VLAN(netdev);
         int r;
 
         assert(netdev);
-        assert(netdev->ifname);
-        assert(netdev->kind == NETDEV_KIND_VLAN);
+        assert(v);
         assert(link);
         assert(req);
 
-        r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINK attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->mtu) {
-                r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_MTU attribute: %s",
-                                         strerror(-r));
-                        return r;
-                }
-        }
-
-        if (netdev->mac) {
-                r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not append IFLA_ADDRESS attribute: %s",
-                                         strerror(-r));
-                    return r;
-                }
-        }
-
-        r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not open IFLA_LINKINFO container: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, "vlan");
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not open IFLA_INFO_DATA container: %s",
-                                  strerror(-r));
-                return r;
-        }
-
-        if (netdev->vlanid <= VLANID_MAX) {
-                r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
+        if (v->id <= VLANID_MAX) {
+                r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, v->id);
                 if (r < 0) {
                         log_error_netdev(netdev,
                                          "Could not append IFLA_VLAN_ID attribute: %s",
@@ -96,38 +44,38 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
                 }
         }
 
-        r = sd_rtnl_message_close_container(req);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not close IFLA_INFO_DATA container %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_close_container(req);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not close IFLA_LINKINFO container %s",
-                                 strerror(-r));
-                return r;
-        }
-
         return 0;
 }
 
 static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
+        VLan *v = VLAN(netdev);
+
         assert(netdev);
+        assert(v);
         assert(filename);
 
-        if (netdev->vlanid > VLANID_MAX) {
-                log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
+        if (v->id > VLANID_MAX) {
+                log_warning("VLAN without valid Id (%"PRIu64") configured in %s. Ignoring", v->id, filename);
                 return -EINVAL;
         }
 
         return 0;
 }
 
+static void vlan_init(NetDev *netdev) {
+        VLan *v = VLAN(netdev);
+
+        assert(netdev);
+        assert(v);
+
+        v->id = VLANID_MAX + 1;
+}
+
 const NetDevVTable vlan_vtable = {
-        .fill_message_create_on_link = netdev_vlan_fill_message_create,
+        .object_size = sizeof(VLan),
+        .init = vlan_init,
+        .sections = "Match\0NetDev\0VLAN\0",
+        .fill_message_create = netdev_vlan_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_vlan_verify,
 };
diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h
index 95f630f..0c0fbbe 100644
--- a/src/network/networkd-netdev-vlan.h
+++ b/src/network/networkd-netdev-vlan.h
@@ -21,8 +21,16 @@
 
 #pragma once
 
+typedef struct VLan VLan;
+
 #include "networkd-netdev.h"
 
 #define VLANID_MAX 4094
 
+struct VLan {
+        NetDev meta;
+
+        uint64_t id;
+};
+
 extern const NetDevVTable vlan_vtable;
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 38692c6..215c117 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -28,39 +28,17 @@
 #include "missing.h"
 
 static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        VxLan *v = VXLAN(netdev);
         int r;
 
         assert(netdev);
+        assert(v);
         assert(link);
-        assert(link->ifname);
         assert(m);
 
-        r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_IFNAME, attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
 
-        r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "vxlan");
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_INFO_DATA attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        if (netdev->vlanid <= VXLAN_VID_MAX) {
-                r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_ID, netdev->vxlanid);
+        if (v->id <= VXLAN_VID_MAX) {
+                r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_ID, v->id);
                 if (r < 0) {
                         log_error_netdev(netdev,
                                          "Could not append IFLA_VXLAN_ID attribute: %s",
@@ -69,7 +47,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
                 }
         }
 
-        r = sd_rtnl_message_append_in_addr(m, IFLA_VXLAN_GROUP, &netdev->group.in);
+        r = sd_rtnl_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->group.in);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_VXLAN_GROUP attribute: %s",
@@ -85,8 +63,8 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
                 return r;
         }
 
-        if(netdev->ttl) {
-                r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TTL, netdev->ttl);
+        if(v->ttl) {
+                r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
                 if (r < 0) {
                         log_error_netdev(netdev,
                                          "Could not append IFLA_VXLAN_TTL attribute: %s",
@@ -95,8 +73,8 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
                 }
         }
 
-        if(netdev->tos) {
-                r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TOS, netdev->tos);
+        if(v->tos) {
+                r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
                 if (r < 0) {
                         log_error_netdev(netdev,
                                          "Could not append IFLA_VXLAN_TOS attribute: %s",
@@ -105,7 +83,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
                 }
         }
 
-        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_LEARNING, netdev->learning);
+        r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_LEARNING, v->learning);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_VXLAN_LEARNING attribute: %s",
@@ -113,22 +91,17 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
                 return r;
         }
 
-        r = sd_rtnl_message_close_container(m);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                                 "Could not append IFLA_LINKINFO attribute: %s",
-                                 strerror(-r));
-                return r;
-        }
-
         return r;
 }
 
 static int netdev_vxlan_verify(NetDev *netdev, const char *filename) {
+        VxLan *v = VXLAN(netdev);
+
         assert(netdev);
+        assert(v);
         assert(filename);
 
-        if (netdev->vxlanid > VXLAN_VID_MAX) {
+        if (v->id > VXLAN_VID_MAX) {
                 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
                 return -EINVAL;
         }
@@ -136,7 +109,21 @@ static int netdev_vxlan_verify(NetDev *netdev, const char *filename) {
         return 0;
 }
 
+static void vxlan_init(NetDev *netdev) {
+        VxLan *v = VXLAN(netdev);
+
+        assert(netdev);
+        assert(v);
+
+        v->id = VXLAN_VID_MAX + 1;
+        v->learning = true;
+}
+
 const NetDevVTable vxlan_vtable = {
-        .fill_message_create_on_link = netdev_vxlan_fill_message_create,
+        .object_size = sizeof(VxLan),
+        .init = vxlan_init,
+        .sections = "Match\0NetDev\0VXLAN\0",
+        .fill_message_create = netdev_vxlan_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_vxlan_verify,
 };
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index a2de271..8c906f1 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -21,8 +21,22 @@
 
 #pragma once
 
+typedef struct VxLan VxLan;
+
 #include "networkd-netdev.h"
 
+#include "in-addr-util.h"
+
 #define VXLAN_VID_MAX (1u << 24) - 1
 
+struct VxLan {
+        NetDev meta;
+
+        uint64_t id;
+        union in_addr_union group;
+        unsigned tos;
+        unsigned ttl;
+        bool learning;
+};
+
 extern const NetDevVTable vxlan_vtable;
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 86f2250..4a6f6e3 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -22,15 +22,6 @@
 #include <net/if.h>
 
 #include "networkd-netdev.h"
-#include "networkd-netdev-bridge.h"
-#include "networkd-netdev-bond.h"
-#include "networkd-netdev-vlan.h"
-#include "networkd-netdev-macvlan.h"
-#include "networkd-netdev-vxlan.h"
-#include "networkd-netdev-tunnel.h"
-#include "networkd-netdev-veth.h"
-#include "networkd-netdev-dummy.h"
-#include "networkd-netdev-tuntap.h"
 #include "network-internal.h"
 #include "path-util.h"
 #include "conf-files.h"
@@ -111,17 +102,17 @@ static void netdev_free(NetDev *netdev) {
 
         free(netdev->description);
         free(netdev->ifname);
-        free(netdev->ifname_peer);
         free(netdev->mac);
-        free(netdev->mac_peer);
-        free(netdev->user_name);
-        free(netdev->group_name);
 
         condition_free_list(netdev->match_host);
         condition_free_list(netdev->match_virt);
         condition_free_list(netdev->match_kernel);
         condition_free_list(netdev->match_arch);
 
+        if (NETDEV_VTABLE(netdev) &&
+            NETDEV_VTABLE(netdev)->done)
+                NETDEV_VTABLE(netdev)->done(netdev);
+
         free(netdev);
 }
 
@@ -268,6 +259,8 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
                 return 1;
         }
 
+        log_debug_netdev(netdev, "created");
+
         return 1;
 }
 
@@ -294,46 +287,10 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callbac
                 link_ref(link);
 
                 LIST_PREPEND(callbacks, netdev->callbacks, cb);
-        }
-
-        return 0;
-}
-
-/* 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 r;
-
-        assert(netdev);
-        assert(netdev->manager);
-        assert(netdev->manager->rtnl);
-        assert(NETDEV_VTABLE(netdev));
-
-        if (NETDEV_VTABLE(netdev)->fill_message_create_on_link) {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
-
-                r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
-                                             RTM_NEWLINK, 0);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not allocate RTM_SETLINK message: %s",
-                                         strerror(-r));
-                        return r;
-                }
-
-                NETDEV_VTABLE(netdev)->fill_message_create_on_link(netdev, link, req);
 
-                r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not send rtnetlink message: %s", strerror(-r));
-                        return r;
-                }
-
-                link_ref(link);
-        } else if (NETDEV_VTABLE(netdev)->enslave) {
-                return NETDEV_VTABLE(netdev)->enslave(netdev, link, callback);
-        } else
-                assert_not_reached("Joining link to netdev of invalid kind");
+                log_debug_netdev(netdev, "will enslave '%s', when reday",
+                                 link->ifname);
+        }
 
         return 0;
 }
@@ -487,8 +444,156 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
         return 0;
 }
 
+static int netdev_create(NetDev *netdev, Link *link) {
+        int r;
+
+        assert(netdev);
+
+        /* create netdev */
+        if (NETDEV_VTABLE(netdev)->create) {
+                r = NETDEV_VTABLE(netdev)->create(netdev);
+                if (r < 0)
+                        return r;
+
+                log_debug_netdev(netdev, "created");
+        } else {
+                _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+
+                r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
+                if (r < 0) {
+                        log_error_netdev(netdev,
+                                         "Could not allocate RTM_NEWLINK message: %s",
+                                         strerror(-r));
+                        return r;
+                }
+
+                r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
+                if (r < 0) {
+                        log_error_netdev(netdev,
+                                         "Could not append IFLA_IFNAME, attribute: %s",
+                                         strerror(-r));
+                        return r;
+                }
+
+                if (netdev->mac) {
+                        r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
+                        if (r < 0) {
+                                log_error_netdev(netdev,
+                                                 "Could not append IFLA_ADDRESS attribute: %s",
+                                                 strerror(-r));
+                            return r;
+                        }
+                }
+
+                if (netdev->mtu) {
+                        r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
+                        if (r < 0) {
+                                log_error_netdev(netdev,
+                                                 "Could not append IFLA_MTU attribute: %s",
+                                                 strerror(-r));
+                                return r;
+                        }
+                }
+
+                if (link) {
+                        r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
+                        if (r < 0) {
+                                log_error_netdev(netdev,
+                                                 "Colud not append IFLA_LINK attribute: %s",
+                                                 strerror(-r));
+                                return r;
+                        }
+                }
+
+                r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
+                if (r < 0) {
+                        log_error_netdev(netdev,
+                                         "Could not append IFLA_LINKINFO attribute: %s",
+                                         strerror(-r));
+                        return r;
+                }
+
+                r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
+                                                         netdev_kind_to_string(netdev->kind));
+                if (r < 0) {
+                        log_error_netdev(netdev,
+                                         "Could not append IFLA_INFO_DATA attribute: %s",
+                                         strerror(-r));
+                        return r;
+                }
+
+                if (NETDEV_VTABLE(netdev)->fill_message_create) {
+                        r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_rtnl_message_close_container(m);
+                if (r < 0) {
+                        log_error_netdev(netdev,
+                                         "Could not append IFLA_LINKINFO attribute: %s",
+                                         strerror(-r));
+                        return r;
+                }
+
+                r = sd_rtnl_message_close_container(m);
+                if (r < 0) {
+                        log_error_netdev(netdev,
+                                         "Could not append IFLA_LINKINFO attribute: %s",
+                                         strerror(-r));
+                        return r;
+                }
+
+
+                r = sd_rtnl_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
+                if (r < 0) {
+                        log_error_netdev(netdev,
+                                         "Could not send rtnetlink message: %s", strerror(-r));
+                        return r;
+                }
+
+                netdev_ref(netdev);
+
+                netdev->state = NETDEV_STATE_CREATING;
+
+                log_debug_netdev(netdev, "creating");
+        }
+
+        return 0;
+}
+
+/* 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 r;
+
+        assert(netdev);
+        assert(netdev->manager);
+        assert(netdev->manager->rtnl);
+        assert(NETDEV_VTABLE(netdev));
+
+        switch (NETDEV_VTABLE(netdev)->create_type) {
+        case NETDEV_CREATE_MASTER:
+                r = netdev_enslave(netdev, link, callback);
+                if (r < 0)
+                        return r;
+
+                break;
+        case NETDEV_CREATE_STACKED:
+                r = netdev_create(netdev, link);
+                if (r < 0)
+                        return r;
+
+                break;
+        default:
+                assert_not_reached("Can not join independent netdev");
+        }
+
+        return 0;
+}
+
 static int netdev_load_one(Manager *manager, const char *filename) {
         _cleanup_netdev_unref_ NetDev *netdev = NULL;
+        _cleanup_free_ NetDev *netdev_raw = NULL;
         _cleanup_fclose_ FILE *file = NULL;
         int r;
 
@@ -508,69 +613,65 @@ static int netdev_load_one(Manager *manager, const char *filename) {
                 return 0;
         }
 
-        netdev = new0(NetDev, 1);
-        if (!netdev)
+        netdev_raw = new0(NetDev, 1);
+        if (!netdev_raw)
                 return log_oom();
 
-        netdev->n_ref = 1;
-        netdev->manager = manager;
-        netdev->state = _NETDEV_STATE_INVALID;
-        netdev->kind = _NETDEV_KIND_INVALID;
-        netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
-        netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
-        netdev->vlanid = VLANID_MAX + 1;
-        netdev->vxlanid = VXLAN_VID_MAX + 1;
-        netdev->tunnel_pmtudisc = true;
-        netdev->learning = true;
+        netdev_raw->kind = _NETDEV_KIND_INVALID;
 
         r = config_parse(NULL, filename, file,
-                         "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
+                         "Match\0NetDev\0",
                          config_item_perf_lookup, network_netdev_gperf_lookup,
-                         false, false, true, netdev);
+                         true, false, true, netdev_raw);
         if (r < 0)
                 return r;
 
+        r = fseek(file, 0, SEEK_SET);
+        if (r < 0)
+                return -errno;
+
         /* skip out early if configuration does not match the environment */
         if (net_match_config(NULL, NULL, NULL, NULL, NULL,
-                             netdev->match_host, netdev->match_virt,
-                             netdev->match_kernel, netdev->match_arch,
+                             netdev_raw->match_host, netdev_raw->match_virt,
+                             netdev_raw->match_kernel, netdev_raw->match_arch,
                              NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
                 return 0;
 
-        if (!NETDEV_VTABLE(netdev)) {
+        if (!NETDEV_VTABLE(netdev_raw)) {
                 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
                 return 0;
         }
 
-        /* verify configuration */
-        if (NETDEV_VTABLE(netdev)->config_verify) {
-                r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
-                if (r < 0)
-                        return 0;
-        }
-
-        if (!netdev->ifname) {
+        if (!netdev_raw->ifname) {
                 log_warning("NetDev without Name configured in %s. Ignoring", filename);
                 return 0;
         }
 
-        if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
-                log_warning("VLAN Id configured for a %s in %s. Ignoring",
-                            netdev_kind_to_string(netdev->kind), filename);
-                return 0;
-        }
+        netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
+        if (!netdev)
+                return log_oom();
 
-        if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
-                log_warning("VXLAN Id configured for a %s in %s. Ignoring",
-                            netdev_kind_to_string(netdev->kind), filename);
-                return 0;
-        }
+        netdev->n_ref = 1;
+        netdev->manager = manager;
+        netdev->state = _NETDEV_STATE_INVALID;
+        netdev->kind = netdev_raw->kind;
+        netdev->ifname = netdev_raw->ifname;
 
-        if (netdev->kind != NETDEV_KIND_MACVLAN &&
-            netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
-                log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
-                            netdev_kind_to_string(netdev->kind), filename);
-                return 0;
+        if (NETDEV_VTABLE(netdev)->init)
+                NETDEV_VTABLE(netdev)->init(netdev);
+
+        r = config_parse(NULL, filename, file,
+                         NETDEV_VTABLE(netdev)->sections,
+                         config_item_perf_lookup, network_netdev_gperf_lookup,
+                         false, false, false, netdev);
+        if (r < 0)
+                return r;
+
+        /* verify configuration */
+        if (NETDEV_VTABLE(netdev)->config_verify) {
+                r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
+                if (r < 0)
+                        return 0;
         }
 
         netdev->filename = strdup(filename);
@@ -594,38 +695,16 @@ static int netdev_load_one(Manager *manager, const char *filename) {
 
         log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
 
-        /* create netdev */
-        if (NETDEV_VTABLE(netdev)->fill_message_create) {
-                _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-
-                r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not allocate RTM_NEWLINK message: %s",
-                                         strerror(-r));
-                        return r;
-                }
-
-                r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, m);
+        switch (NETDEV_VTABLE(netdev)->create_type) {
+        case NETDEV_CREATE_MASTER:
+        case NETDEV_CREATE_INDEPENDENT:
+                r = netdev_create(netdev, NULL);
                 if (r < 0)
                         return r;
 
-                r = sd_rtnl_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
-                if (r < 0) {
-                        log_error_netdev(netdev,
-                                         "Could not send rtnetlink message: %s", strerror(-r));
-                        return r;
-                }
-
-                netdev_ref(netdev);
-
-                log_debug_netdev(netdev, "creating");
-
-                netdev->state = NETDEV_STATE_CREATING;
-        } else if (NETDEV_VTABLE(netdev)->create) {
-                r = NETDEV_VTABLE(netdev)->create(netdev);
-                if (r < 0)
-                        return r;
+                break;
+        default:
+                break;
         }
 
         netdev = NULL;
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 042e160..e9a8a16 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -66,6 +66,14 @@ typedef enum NetDevState {
         _NETDEV_STATE_INVALID = -1,
 } NetDevState;
 
+typedef enum NetDevCreateType {
+        NETDEV_CREATE_INDEPENDENT,
+        NETDEV_CREATE_MASTER,
+        NETDEV_CREATE_STACKED,
+        _NETDEV_CREATE_MAX,
+        _NETDEV_CREATE_INVALID = -1,
+} NetDevCreateType;
+
 struct NetDev {
         Manager *manager;
 
@@ -78,49 +86,50 @@ struct NetDev {
         Condition *match_kernel;
         Condition *match_arch;
 
+        NetDevState state;
+        NetDevKind kind;
         char *description;
         char *ifname;
-        char *ifname_peer;
-        char *user_name;
-        char *group_name;
-        size_t mtu;
         struct ether_addr *mac;
-        struct ether_addr *mac_peer;
-        NetDevKind kind;
-
-        uint64_t vlanid;
-        uint64_t vxlanid;
-        int32_t macvlan_mode;
-        int32_t bond_mode;
-
+        size_t mtu;
         int ifindex;
-        NetDevState state;
-
-        bool tunnel_pmtudisc;
-        bool learning;
-        bool one_queue;
-        bool multi_queue;
-        bool packet_info;
-
-        unsigned ttl;
-        unsigned tos;
-        int family;
-        union in_addr_union local;
-        union in_addr_union remote;
-        union in_addr_union group;
 
         LIST_HEAD(netdev_join_callback, callbacks);
 };
 
+#include "networkd-netdev-bridge.h"
+#include "networkd-netdev-bond.h"
+#include "networkd-netdev-vlan.h"
+#include "networkd-netdev-macvlan.h"
+#include "networkd-netdev-vxlan.h"
+#include "networkd-netdev-veth.h"
+#include "networkd-netdev-tunnel.h"
+#include "networkd-netdev-dummy.h"
+#include "networkd-netdev-tuntap.h"
+
 struct NetDevVTable {
-        /* fill in message to create netdev */
-        int (*fill_message_create)(NetDev *netdev, sd_rtnl_message *message);
+        /* How much memory does an object of this unit type need */
+        size_t object_size;
+
+        /* Config file sections this netdev kind understands, separated
+         * by NUL chars */
+        const char *sections;
 
-        /* fill in message to create netdev on top of a given link */
-        int (*fill_message_create_on_link)(NetDev *netdev, Link *link, sd_rtnl_message *message);
+        /* This should reset all type-specific variables. This should
+         * not allocate memory, and is called with zero-initialized
+         * data. It should hence only initialize variables that need
+         * to be set != 0. */
+        void (*init)(NetDev *n);
 
-        /* fill in message to enslave link by netdev */
-        int (*enslave)(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback);
+        /* This should free all kind-specific variables. It should be
+         * idempotent. */
+        void (*done)(NetDev *n);
+
+        /* fill in message to create netdev */
+        int (*fill_message_create)(NetDev *netdev, Link *link, sd_rtnl_message *message);
+
+        /* specifies if netdev is independent, or a master device or a stacked device */
+        NetDevCreateType create_type;
 
         /* create netdev, if not done via rtnl */
         int (*create)(NetDev *netdev);
@@ -133,6 +142,32 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
 
 #define NETDEV_VTABLE(n) netdev_vtable[(n)->kind]
 
+/* For casting a netdev into the various netdev kinds */
+#define DEFINE_CAST(UPPERCASE, MixedCase)                                   \
+        static inline MixedCase* UPPERCASE(NetDev *n) {                     \
+                if (_unlikely_(!n || n->kind != NETDEV_KIND_##UPPERCASE))   \
+                        return NULL;                                        \
+                                                                            \
+                return (MixedCase*) n;                                      \
+        }
+
+/* For casting the various netdev kinds into a netdev */
+#define NETDEV(n) (&(n)->meta)
+
+DEFINE_CAST(BRIDGE, Bridge);
+DEFINE_CAST(BOND, Bond);
+DEFINE_CAST(VLAN, VLan);
+DEFINE_CAST(MACVLAN, MacVlan);
+DEFINE_CAST(VXLAN, VxLan);
+DEFINE_CAST(IPIP, Tunnel);
+DEFINE_CAST(GRE, Tunnel);
+DEFINE_CAST(SIT, Tunnel);
+DEFINE_CAST(VTI, Tunnel);
+DEFINE_CAST(VETH, Veth);
+DEFINE_CAST(DUMMY, Dummy);
+DEFINE_CAST(TUN, TunTap);
+DEFINE_CAST(TAP, TunTap);
+
 int netdev_load(Manager *manager);
 void netdev_drop(NetDev *netdev);
 
@@ -167,4 +202,4 @@ const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsign
 
 #define log_struct_netdev(level, netdev, ...) log_struct(level, "INTERFACE=%s", netdev->ifname, __VA_ARGS__)
 
-#define NETDEV(netdev) "INTERFACE=%s", netdev->ifname
+#define NETDEVIF(netdev) "INTERFACE=%s", netdev->ifname
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 3e46a1a..bc93042 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -66,11 +66,11 @@ static int network_load_one(Manager *manager, const char *filename) {
         if (!network->vlans)
                 return log_oom();
 
-        network->macvlans = hashmap_new(uint64_hash_func, uint64_compare_func);
+        network->macvlans = hashmap_new(string_hash_func, string_compare_func);
         if (!network->macvlans)
                 return log_oom();
 
-        network->vxlans = hashmap_new(uint64_hash_func, uint64_compare_func);
+        network->vxlans = hashmap_new(string_hash_func, string_compare_func);
         if (!network->vxlans)
                 return log_oom();
 
@@ -323,10 +323,11 @@ int config_parse_netdev(const char *unit,
 
                 break;
         case NETDEV_KIND_VLAN:
-                r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
+                r = hashmap_put(network->vlans, netdev->ifname, netdev);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                                   "Can not add VLAN to network: %s", rvalue);
+                                   "Can not add VLAN '%s' to network: %s",
+                                   rvalue, strerror(-r));
                         return 0;
                 }
 
@@ -335,7 +336,8 @@ int config_parse_netdev(const char *unit,
                 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                                   "Can not add MACVLAN to network: %s", rvalue);
+                                   "Can not add MACVLAN '%s' to network: %s",
+                                   rvalue, strerror(-r));
                         return 0;
                 }
 
@@ -344,7 +346,8 @@ int config_parse_netdev(const char *unit,
                 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                                   "Can not add VXLAN to network: %s", rvalue);
+                                   "Can not add VXLAN '%s' to network: %s",
+                                   rvalue, strerror(-r));
                         return 0;
                 }
 

commit 653912918f594ebbca46806b302ef6b477402575
Author: Tom Gundersen <teg at jklm.no>
Date:   Sat Jul 19 01:37:22 2014 +0200

    sd-network: drop get_ifindices
    
    People should use rtnl for this, and then only query sd-network by the ifindices it finds.

diff --git a/TODO b/TODO
index bfa06de..4a1313d 100644
--- a/TODO
+++ b/TODO
@@ -29,7 +29,6 @@ Features:
     releases (probably not even a directory in /run for it)
   - the order between ipv6 and ipv4 dns servers probably matters,
     hence the current DNS apis won't suffice
-  - sd_network_get_ifindices() sounds redundant, rtnetlink can do that too
 
 * resolved:
   - IDN (?)
diff --git a/src/network/sd-network.c b/src/network/sd-network.c
index 0844e58..91d6275 100644
--- a/src/network/sd-network.c
+++ b/src/network/sd-network.c
@@ -206,64 +206,6 @@ _public_ int sd_network_dhcp_use_ntp(int ifindex) {
         return network_get_boolean("DHCP_USE_NTP", ifindex);
 }
 
-_public_ int sd_network_get_ifindices(int **ifindices) {
-        _cleanup_closedir_ DIR *d;
-        int r = 0;
-        unsigned n = 0;
-        _cleanup_free_ int *l = NULL;
-
-        d = opendir("/run/systemd/netif/links/");
-        if (!d)
-                return -errno;
-
-        for (;;) {
-                struct dirent *de;
-                int k;
-                int ifindex;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0)
-                        return -errno;
-
-                if (!de)
-                        break;
-
-                dirent_ensure_type(d, de);
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                k = safe_atoi(de->d_name, &ifindex);
-                if (k < 0)
-                        continue;
-
-                if (ifindices) {
-                        if ((unsigned) r >= n) {
-                                int *t;
-
-                                n = MAX(16, 2*r);
-                                t = realloc(l, sizeof(int) * n);
-                                if (!t)
-                                        return -ENOMEM;
-
-                                l = t;
-                        }
-
-                        assert((unsigned) r < n);
-                        l[r++] = ifindex;
-                } else
-                        r++;
-        }
-
-        if (ifindices) {
-                *ifindices = l;
-                l = NULL;
-        }
-
-        return r;
-}
-
 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
         return (int) (unsigned long) m - 1;
 }
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 0f32c44..e454705 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -88,10 +88,6 @@ int sd_network_get_dns(int ifindex, struct in_addr **addr);
 /* Get IPv6 DNS entries statically configured for the link */
 int sd_network_get_dns6(int ifindex, struct in6_addr **addr);
 
-/* Get all network interfaces' indices, and store them in *indices. Returns
- * the number of indices. If indices is NULL, only returns the number of indices. */
-int sd_network_get_ifindices(int **ifindices);
-
 /* Monitor object */
 typedef struct sd_network_monitor sd_network_monitor;
 



More information about the systemd-commits mailing list