diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 42632a6540e..f11c3e142a6 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -115,6 +115,9 @@
ipvlan
An ipvlan device is a stacked device which receives packets from its underlying device based on IP address filtering.
+ ipvtap
+ An ipvtap device is a stacked device which receives packets from its underlying device based on IP address filtering and can be accessed using the tap user space interface.
+
macvlan
A macvlan device is a stacked device which receives packets from its underlying device based on MAC address filtering.
@@ -519,6 +522,15 @@
+
+ [IPVTAP] Section Options
+
+ The [IPVTAP] section only applies for
+ netdevs of kind ipvtap and accepts the
+ same key as [IPVLAN].
+
+
+
[VXLAN] Section Options
The [VXLAN] section only applies for
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index f207d2e5aae..cda9709ea00 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -337,6 +337,7 @@ static const char* const nl_union_link_info_data_table[] = {
[NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
[NL_UNION_LINK_INFO_DATA_MACVTAP] = "macvtap",
[NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
+ [NL_UNION_LINK_INFO_DATA_IPVTAP] = "ipvtap",
[NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
[NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
[NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
@@ -375,6 +376,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = {
.types = rtnl_link_info_data_macvlan_types },
[NL_UNION_LINK_INFO_DATA_IPVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types),
.types = rtnl_link_info_data_ipvlan_types },
+ [NL_UNION_LINK_INFO_DATA_IPVTAP] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types),
+ .types = rtnl_link_info_data_ipvlan_types },
[NL_UNION_LINK_INFO_DATA_VXLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vxlan_types),
.types = rtnl_link_info_data_vxlan_types },
[NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h
index a2b3087d159..8585280463a 100644
--- a/src/libsystemd/sd-netlink/netlink-types.h
+++ b/src/libsystemd/sd-netlink/netlink-types.h
@@ -62,6 +62,7 @@ typedef enum NLUnionLinkInfoData {
NL_UNION_LINK_INFO_DATA_MACVLAN,
NL_UNION_LINK_INFO_DATA_MACVTAP,
NL_UNION_LINK_INFO_DATA_IPVLAN,
+ NL_UNION_LINK_INFO_DATA_IPVTAP,
NL_UNION_LINK_INFO_DATA_VXLAN,
NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL,
NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL,
diff --git a/src/network/netdev/ipvlan.c b/src/network/netdev/ipvlan.c
index 5bb6a5bb35b..7b251767672 100644
--- a/src/network/netdev/ipvlan.c
+++ b/src/network/netdev/ipvlan.c
@@ -32,7 +32,10 @@ static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netl
assert(link);
assert(netdev->ifname);
- m = IPVLAN(netdev);
+ if (netdev->kind == NETDEV_KIND_IPVLAN)
+ m = IPVLAN(netdev);
+ else
+ m = IPVTAP(netdev);
assert(m);
@@ -56,7 +59,10 @@ static void ipvlan_init(NetDev *n) {
assert(n);
- m = IPVLAN(n);
+ if (n->kind == NETDEV_KIND_IPVLAN)
+ m = IPVLAN(n);
+ else
+ m = IPVTAP(n);
assert(m);
@@ -71,3 +77,11 @@ const NetDevVTable ipvlan_vtable = {
.fill_message_create = netdev_ipvlan_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
};
+
+const NetDevVTable ipvtap_vtable = {
+ .object_size = sizeof(IPVlan),
+ .init = ipvlan_init,
+ .sections = "Match\0NetDev\0IPVTAP\0",
+ .fill_message_create = netdev_ipvlan_fill_message_create,
+ .create_type = NETDEV_CREATE_STACKED,
+};
diff --git a/src/network/netdev/ipvlan.h b/src/network/netdev/ipvlan.h
index eb67b5c1959..140cacf4fcb 100644
--- a/src/network/netdev/ipvlan.h
+++ b/src/network/netdev/ipvlan.h
@@ -30,7 +30,9 @@ typedef struct IPVlan {
} IPVlan;
DEFINE_NETDEV_CAST(IPVLAN, IPVlan);
+DEFINE_NETDEV_CAST(IPVTAP, IPVlan);
extern const NetDevVTable ipvlan_vtable;
+extern const NetDevVTable ipvtap_vtable;
const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index e18d746befc..dd2184249e1 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -54,6 +54,8 @@ MACVLAN.Mode, config_parse_macvlan_mode,
MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
IPVLAN.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags)
+IPVTAP.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
+IPVTAP.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags)
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)
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 3f9d1e5f122..3968ab54956 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -45,6 +45,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_MACVLAN] = &macvlan_vtable,
[NETDEV_KIND_MACVTAP] = &macvtap_vtable,
[NETDEV_KIND_IPVLAN] = &ipvlan_vtable,
+ [NETDEV_KIND_IPVTAP] = &ipvtap_vtable,
[NETDEV_KIND_VXLAN] = &vxlan_vtable,
[NETDEV_KIND_IPIP] = &ipip_vtable,
[NETDEV_KIND_GRE] = &gre_vtable,
@@ -78,6 +79,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_MACVLAN] = "macvlan",
[NETDEV_KIND_MACVTAP] = "macvtap",
[NETDEV_KIND_IPVLAN] = "ipvlan",
+ [NETDEV_KIND_IPVTAP] = "ipvtap",
[NETDEV_KIND_VXLAN] = "vxlan",
[NETDEV_KIND_IPIP] = "ipip",
[NETDEV_KIND_GRE] = "gre",
diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h
index 29ecead029b..dcf072ce944 100644
--- a/src/network/netdev/netdev.h
+++ b/src/network/netdev/netdev.h
@@ -24,6 +24,7 @@ typedef enum NetDevKind {
NETDEV_KIND_MACVLAN,
NETDEV_KIND_MACVTAP,
NETDEV_KIND_IPVLAN,
+ NETDEV_KIND_IPVTAP,
NETDEV_KIND_VXLAN,
NETDEV_KIND_IPIP,
NETDEV_KIND_GRE,
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 3c6b5ac1004..825fbf603a0 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -44,6 +44,7 @@ Network.VLAN, config_parse_stacked_netdev,
Network.MACVLAN, config_parse_stacked_netdev, NETDEV_KIND_MACVLAN, offsetof(Network, stacked_netdev_names)
Network.MACVTAP, config_parse_stacked_netdev, NETDEV_KIND_MACVTAP, offsetof(Network, stacked_netdev_names)
Network.IPVLAN, config_parse_stacked_netdev, NETDEV_KIND_IPVLAN, offsetof(Network, stacked_netdev_names)
+Network.IPVTAP, config_parse_stacked_netdev, NETDEV_KIND_IPVTAP, offsetof(Network, stacked_netdev_names)
Network.VXLAN, config_parse_stacked_netdev, NETDEV_KIND_VXLAN, offsetof(Network, stacked_netdev_names)
Network.L2TP, config_parse_stacked_netdev, NETDEV_KIND_L2TP, offsetof(Network, stacked_netdev_names)
Network.MACsec, config_parse_stacked_netdev, NETDEV_KIND_MACSEC, offsetof(Network, stacked_netdev_names)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 755cd604dca..324026e975e 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -708,8 +708,8 @@ int config_parse_stacked_netdev(const char *unit,
assert(data);
assert(IN_SET(kind,
NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
- NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, NETDEV_KIND_L2TP,
- NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL));
+ NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
+ NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL));
if (!ifname_valid(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
diff --git a/test/fuzz/fuzz-netdev-parser/directives.netdev b/test/fuzz/fuzz-netdev-parser/directives.netdev
index 0b332a6e7a2..a49acacc3f5 100644
--- a/test/fuzz/fuzz-netdev-parser/directives.netdev
+++ b/test/fuzz/fuzz-netdev-parser/directives.netdev
@@ -151,6 +151,9 @@ VNetHeader=
[IPVLAN]
Mode=
Flags=
+[IPVTAP]
+Mode=
+Flags=
[Tun]
OneQueue=
MultiQueue=
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index ef29c7951f3..5861c41e757 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -104,6 +104,7 @@ Tunnel=
Gateway=
IPv4LL=
IPVLAN=
+IPVTAP=
EmitLLDP=
IPv6MTUBytes=
IPv4ProxyARP=