diff --git a/kayobe/plugins/filter/networkd.py b/kayobe/plugins/filter/networkd.py
index 5527224721fc8264b943fc9e1d0eb0ae376b3516..dac05b303cd06204d9ba701b2e0329f62b4ddb5e 100644
--- a/kayobe/plugins/filter/networkd.py
+++ b/kayobe/plugins/filter/networkd.py
@@ -284,7 +284,6 @@ def _network(context, name, inventory_hostname, bridge, bond, vlan_interfaces):
         {
             'Network': [
                 {'Address': ip},
-                {'Broadcast': 'true' if ip else None},
                 {'Gateway': gateway},
                 {'DHCP': ('yes' if bootproto and bootproto.lower() == 'dhcp'
                           else None)},
@@ -317,6 +316,34 @@ def _network(context, name, inventory_hostname, bridge, bond, vlan_interfaces):
     return _filter_options(config)
 
 
+def _vlan_parent_network(device, mtu, vlan_interfaces):
+    """Return a networkd network configuration for a VLAN parent interface.
+
+    :param device: name of the interface.
+    :param mtu: Interface MTU.
+    :param vlan_interfaces: List of VLAN subinterfaces of the interface.
+    """
+    config = [
+        {
+            'Match': [
+                {'Name': device},
+            ]
+        },
+        {
+            'Network': [
+                {'VLAN': vlan_interface}
+                for vlan_interface in vlan_interfaces
+            ]
+        },
+        {
+            'Link': [
+                {'MTUBytes': mtu},
+            ]
+        }
+    ]
+    return _filter_options(config)
+
+
 def _bridge_port_network(context, name, port, inventory_hostname,
                          vlan_interfaces):
     """Return a networkd network configuration for a bridge port.
@@ -437,6 +464,25 @@ def _veth_peer_network(context, veth, inventory_hostname):
     return _filter_options(config)
 
 
+def _add_to_result(result, prefix, device, config):
+    """Add configuration for an interface to a filter result.
+
+    :param result: the result dict.
+    :param prefix: the systemd-networkd configuration file prefix.
+    :param device: the interface being configured.
+    :param config: the configuration to add to the result.
+    :raises: AnsibleFilterError if the interface already exists in the result.
+    """
+    key = "%s%s" % (prefix, device)
+    # Catch the case where interface configuration is added multiple times.
+    # This should not happen.
+    if key in result:
+        raise errors.AnsibleFilterError(
+            "Programming error: duplicate interface configuration for %s"
+            % device)
+    result[key] = config
+
+
 @jinja2.contextfilter
 def networkd_netdevs(context, names, inventory_hostname=None):
     """Return a dict representation of networkd NetDev configuration.
@@ -459,7 +505,7 @@ def networkd_netdevs(context, names, inventory_hostname=None):
         device = networks.get_and_validate_interface(context, name,
                                                      inventory_hostname)
         netdev = _vlan_netdev(context, name, inventory_hostname)
-        result["%s%s" % (prefix, device)] = netdev
+        _add_to_result(result, prefix, device, netdev)
 
     # Bridges.
     for name in networks.net_select_bridges(context, names,
@@ -467,21 +513,21 @@ def networkd_netdevs(context, names, inventory_hostname=None):
         device = networks.get_and_validate_interface(context, name,
                                                      inventory_hostname)
         netdev = _bridge_netdev(context, name, inventory_hostname)
-        result["%s%s" % (prefix, device)] = netdev
+        _add_to_result(result, prefix, device, netdev)
 
     # Bonds.
     for name in networks.net_select_bonds(context, names, inventory_hostname):
         device = networks.get_and_validate_interface(context, name,
                                                      inventory_hostname)
         netdev = _bond_netdev(context, name, inventory_hostname)
-        result["%s%s" % (prefix, device)] = netdev
+        _add_to_result(result, prefix, device, netdev)
 
     # Virtual Ethernet pairs.
     veths = networks.get_ovs_veths(context, names, inventory_hostname)
     for veth in veths:
         netdev = _veth_netdev(context, veth, inventory_hostname)
         device = veth['name']
-        result["%s%s" % (prefix, device)] = netdev
+        _add_to_result(result, prefix, device, netdev)
 
     return result
 
@@ -551,9 +597,10 @@ def networkd_networks(context, names, inventory_hostname=None):
         device = networks.get_and_validate_interface(context, name,
                                                      inventory_hostname)
         vlan = networks.net_vlan(context, name, inventory_hostname)
+        mtu = networks.net_mtu(context, name, inventory_hostname)
         parent = networks.get_vlan_parent(device, vlan)
         vlan_interfaces = interface_to_vlans.setdefault(parent, [])
-        vlan_interfaces.append(device)
+        vlan_interfaces.append({"device": device, "mtu": mtu})
 
     # Prefix for configuration file names.
     prefix = utils.get_hostvar(context, "networkd_prefix", inventory_hostname)
@@ -568,8 +615,22 @@ def networkd_networks(context, names, inventory_hostname=None):
         bond = bond_member_to_bond.get(device)
         vlan_interfaces = interface_to_vlans.get(device, [])
         net = _network(context, name, inventory_hostname, bridge, bond,
-                       vlan_interfaces)
-        result["%s%s" % (prefix, device)] = net
+                       [vlan["device"] for vlan in vlan_interfaces])
+        _add_to_result(result, prefix, device, net)
+
+    # VLAN parent interfaces that are not in configured networks, bridge ports
+    # or bond members.
+    implied_vlan_parents = (set(interface_to_vlans) -
+                            set(interfaces) -
+                            set(bridge_port_to_bridge) -
+                            set(bond_member_to_bond))
+    for device in implied_vlan_parents:
+        vlan_interfaces = interface_to_vlans[device]
+        mtu = max([vlan["mtu"] for vlan in vlan_interfaces])
+        net = _vlan_parent_network(device, mtu,
+                                   [vlan["device"]
+                                    for vlan in vlan_interfaces])
+        _add_to_result(result, prefix, device, net)
 
     # Bridge ports that are not in configured networks.
     for name in networks.net_select_bridges(context, names,
@@ -580,9 +641,10 @@ def networkd_networks(context, names, inventory_hostname=None):
                                                  inventory_hostname)
         for port in set(bridge_ports) - set(interfaces):
             vlan_interfaces = interface_to_vlans.get(port, [])
-            netdev = _bridge_port_network(context, name, port,
-                                          inventory_hostname, vlan_interfaces)
-            result["%s%s" % (prefix, port)] = netdev
+            net = _bridge_port_network(context, name, port, inventory_hostname,
+                                       [vlan["device"]
+                                        for vlan in vlan_interfaces])
+            _add_to_result(result, prefix, port, net)
 
     # Bond members that are not in configured networks.
     for name in networks.net_select_bonds(context, names, inventory_hostname):
@@ -592,20 +654,22 @@ def networkd_networks(context, names, inventory_hostname=None):
                                                 inventory_hostname)
         for member in set(bond_members) - set(interfaces):
             vlan_interfaces = interface_to_vlans.get(member, [])
-            netdev = _bond_member_network(context, name, member,
-                                          inventory_hostname, vlan_interfaces)
-            result["%s%s" % (prefix, member)] = netdev
+            net = _bond_member_network(context, name, member,
+                                       inventory_hostname,
+                                       [vlan["device"]
+                                        for vlan in vlan_interfaces])
+            _add_to_result(result, prefix, member, net)
 
     # Virtual Ethernet pairs for Open vSwitch.
     veths = networks.get_ovs_veths(context, names, inventory_hostname)
     for veth in veths:
         net = _veth_network(context, veth, inventory_hostname)
         device = veth['name']
-        result["%s%s" % (prefix, device)] = net
+        _add_to_result(result, prefix, device, net)
 
         net = _veth_peer_network(context, veth, inventory_hostname)
         device = veth['peer']
-        result["%s%s" % (prefix, device)] = net
+        _add_to_result(result, prefix, device, net)
 
     return result
 
diff --git a/kayobe/tests/unit/plugins/filter/test_networkd.py b/kayobe/tests/unit/plugins/filter/test_networkd.py
index 5d17f1cb15fcb392a58f5a043eaf1d9005e15b24..12d2c3d6189cde782c618eb6ed373fe5bf07270c 100644
--- a/kayobe/tests/unit/plugins/filter/test_networkd.py
+++ b/kayobe/tests/unit/plugins/filter/test_networkd.py
@@ -298,7 +298,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
                 {
                     "Network": [
                         {"Address": "1.2.3.4/24"},
-                        {"Broadcast": "true"},
                     ]
                 },
             ]
@@ -347,7 +346,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
                 {
                     "Network": [
                         {"Address": "1.2.3.4/24"},
-                        {"Broadcast": "true"},
                         {"Gateway": "1.2.3.1"},
                         {"DHCP": "yes"},
                         {'UseGateway': "false"},
@@ -400,6 +398,18 @@ class TestNetworkdNetworks(BaseNetworkdTest):
     def test_vlan(self):
         nets = networkd.networkd_networks(self.context, ["net2"])
         expected = {
+            "50-kayobe-eth0": [
+                {
+                    "Match": [
+                        {"Name": "eth0"}
+                    ],
+                },
+                {
+                    "Network": [
+                        {"VLAN": "eth0.2"},
+                    ]
+                },
+            ],
             "50-kayobe-eth0.2": [
                 {
                     "Match": [
@@ -422,7 +432,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
                 {
                     "Network": [
                         {"Address": "1.2.3.4/24"},
-                        {"Broadcast": "true"},
                         {"VLAN": "eth0.2"},
                     ]
                 },
@@ -527,6 +536,106 @@ class TestNetworkdNetworks(BaseNetworkdTest):
         }
         self.assertEqual(expected, nets)
 
+    def test_bridge_with_bridge_port_vlan(self):
+        # Test the case where one of the bridge ports has a VLAN subinterface.
+        self._update_context({
+            "net2_interface": "eth1.2",
+        })
+        nets = networkd.networkd_networks(self.context, ["net2", "net3"])
+        expected = {
+            "50-kayobe-br0": [
+                {
+                    "Match": [
+                        {"Name": "br0"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth0": [
+                {
+                    "Match": [
+                        {"Name": "eth0"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bridge": "br0"},
+                    ]
+                },
+            ],
+            "50-kayobe-eth1": [
+                {
+                    "Match": [
+                        {"Name": "eth1"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bridge": "br0"},
+                        {"VLAN": "eth1.2"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth1.2": [
+                {
+                    "Match": [
+                        {"Name": "eth1.2"}
+                    ]
+                },
+            ],
+        }
+        self.assertEqual(expected, nets)
+
+    def test_bridge_with_bridge_port_vlan_net(self):
+        # Test the case where one of the bridge ports has a VLAN subinterface,
+        # and is also a Kayobe network (here eth0 is net1).
+        self._update_context({
+            "net1_ips": None,
+        })
+        nets = networkd.networkd_networks(self.context,
+                                          ["net1", "net2", "net3"])
+        expected = {
+            "50-kayobe-br0": [
+                {
+                    "Match": [
+                        {"Name": "br0"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth0": [
+                {
+                    "Match": [
+                        {"Name": "eth0"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bridge": "br0"},
+                        {"VLAN": "eth0.2"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth0.2": [
+                {
+                    "Match": [
+                        {"Name": "eth0.2"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth1": [
+                {
+                    "Match": [
+                        {"Name": "eth1"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bridge": "br0"},
+                    ]
+                },
+            ]
+        }
+        self.assertEqual(expected, nets)
+
     def test_bridge_no_interface(self):
         self._update_context({"net3_interface": None})
         self.assertRaises(errors.AnsibleFilterError,
@@ -617,6 +726,106 @@ class TestNetworkdNetworks(BaseNetworkdTest):
         }
         self.assertEqual(expected, nets)
 
+    def test_bond_with_bond_member_vlan(self):
+        # Test the case where one of the bond members has a VLAN subinterface.
+        self._update_context({
+            "net2_interface": "eth1.2",
+        })
+        nets = networkd.networkd_networks(self.context, ["net2", "net4"])
+        expected = {
+            "50-kayobe-bond0": [
+                {
+                    "Match": [
+                        {"Name": "bond0"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth0": [
+                {
+                    "Match": [
+                        {"Name": "eth0"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bond": "bond0"},
+                    ]
+                },
+            ],
+            "50-kayobe-eth1": [
+                {
+                    "Match": [
+                        {"Name": "eth1"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bond": "bond0"},
+                        {"VLAN": "eth1.2"},
+                    ]
+                },
+            ],
+            "50-kayobe-eth1.2": [
+                {
+                    "Match": [
+                        {"Name": "eth1.2"}
+                    ]
+                },
+            ],
+        }
+        self.assertEqual(expected, nets)
+
+    def test_bond_with_bond_member_vlan_net(self):
+        # Test the case where one of the bond members has a VLAN subinterface,
+        # and is also a Kayobe network (here eth0 is net1).
+        self._update_context({
+            "net1_ips": None,
+        })
+        nets = networkd.networkd_networks(self.context,
+                                          ["net1", "net2", "net4"])
+        expected = {
+            "50-kayobe-bond0": [
+                {
+                    "Match": [
+                        {"Name": "bond0"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth0": [
+                {
+                    "Match": [
+                        {"Name": "eth0"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bond": "bond0"},
+                        {"VLAN": "eth0.2"},
+                    ]
+                },
+            ],
+            "50-kayobe-eth0.2": [
+                {
+                    "Match": [
+                        {"Name": "eth0.2"}
+                    ]
+                },
+            ],
+            "50-kayobe-eth1": [
+                {
+                    "Match": [
+                        {"Name": "eth1"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bond": "bond0"},
+                    ]
+                },
+            ]
+        }
+        self.assertEqual(expected, nets)
+
     def test_bond_no_interface(self):
         self._update_context({"net4_interface": None})
         self.assertRaises(errors.AnsibleFilterError,
@@ -737,7 +946,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
                 {
                     "Network": [
                         {"Address": "1.2.3.4/24"},
-                        {"Broadcast": "true"},
                     ]
                 },
             ]
@@ -760,7 +968,6 @@ class TestNetworkdNetworks(BaseNetworkdTest):
                 {
                     "Network": [
                         {"Address": "1.2.3.4/24"},
-                        {"Broadcast": "true"},
                         {"VLAN": "eth0.2"},
                     ]
                 },
diff --git a/tox.ini b/tox.ini
index 43e829a20a95e974c1d1c137984a730d34e6b24e..bb75ac49e3ba3b0c540344005115d643bfddaf19 100644
--- a/tox.ini
+++ b/tox.ini
@@ -135,8 +135,9 @@ commands =
 
 [flake8]
 # E123, E125 skipped as they are invalid PEP-8.
+# W504 line break after binary operator
 
 show-source = True
-ignore = E123,E125
+ignore = E123,E125,W504
 builtins = _
 exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build