diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index c2957fd1823..b258e0c965f 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -819,6 +819,13 @@
Accepts the same key in [VXLAN] section.
+
+ Independent=
+
+ Takes a boolean. When true, the vxlan interface is created without underlying interfaces.
+ Defaults to false.
+
+
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index c532dfd2683..2e69b17fe37 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -134,6 +134,7 @@ VXLAN.PortRange, config_parse_port_range,
VXLAN.DestinationPort, config_parse_ip_port, 0, offsetof(VxLan, dest_port)
VXLAN.FlowLabel, config_parse_flow_label, 0, 0
VXLAN.IPDoNotFragment, config_parse_df, 0, offsetof(VxLan, df)
+VXLAN.Independent, config_parse_bool, 0, offsetof(VxLan, independent)
GENEVE.Id, config_parse_geneve_vni, 0, offsetof(Geneve, id)
GENEVE.Remote, config_parse_geneve_address, 0, offsetof(Geneve, remote)
GENEVE.TOS, config_parse_uint8, 0, offsetof(Geneve, tos)
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 446a580e2cc..3e32d830290 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -823,6 +823,9 @@ int netdev_load_one(Manager *manager, const char *filename) {
case NETDEV_KIND_XFRM:
independent = XFRM(netdev)->independent;
break;
+ case NETDEV_KIND_VXLAN:
+ independent = VXLAN(netdev)->independent;
+ break;
default:
break;
}
diff --git a/src/network/netdev/vxlan.c b/src/network/netdev/vxlan.c
index 373ff789aae..d941b7d6334 100644
--- a/src/network/netdev/vxlan.c
+++ b/src/network/netdev/vxlan.c
@@ -25,7 +25,6 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
int r;
assert(netdev);
- assert(link);
assert(m);
v = VXLAN(netdev);
@@ -63,7 +62,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LOCAL attribute: %m");
}
- r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
+ r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LINK, link ? link->ifindex : 0);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m");
diff --git a/src/network/netdev/vxlan.h b/src/network/netdev/vxlan.h
index cf8ae8845e8..d836215c466 100644
--- a/src/network/netdev/vxlan.h
+++ b/src/network/netdev/vxlan.h
@@ -56,6 +56,7 @@ struct VxLan {
bool group_policy;
bool generic_protocol_extension;
bool inherit;
+ bool independent;
struct ifla_vxlan_port_range port_range;
};
diff --git a/test/fuzz/fuzz-netdev-parser/directives.netdev b/test/fuzz/fuzz-netdev-parser/directives.netdev
index ef1f18fa402..4c223f908eb 100644
--- a/test/fuzz/fuzz-netdev-parser/directives.netdev
+++ b/test/fuzz/fuzz-netdev-parser/directives.netdev
@@ -116,6 +116,7 @@ PortRange=
UDPChecksum=
UDP6ZeroCheckSumTx=
IPDoNotFragment=
+Independent=
[VXCAN]
Peer=
[Bond]
diff --git a/test/test-network/conf/25-vxlan-independent.netdev b/test/test-network/conf/25-vxlan-independent.netdev
new file mode 100644
index 00000000000..13b6cc8e7ce
--- /dev/null
+++ b/test/test-network/conf/25-vxlan-independent.netdev
@@ -0,0 +1,17 @@
+[NetDev]
+Name=vxlan98
+Kind=vxlan
+
+[VXLAN]
+VNI=1000
+L2MissNotification=true
+L3MissNotification=true
+RouteShortCircuit=true
+UDPChecksum=true
+UDP6ZeroChecksumTx=true
+UDP6ZeroChecksumRx=true
+RemoteChecksumTx=true
+RemoteChecksumRx=true
+GroupPolicyExtension=true
+DestinationPort=5556
+Independent=yes
diff --git a/test/test-network/conf/netdev-link-local-addressing-yes.network b/test/test-network/conf/netdev-link-local-addressing-yes.network
index 4b96a8231ac..3384fde581b 100644
--- a/test/test-network/conf/netdev-link-local-addressing-yes.network
+++ b/test/test-network/conf/netdev-link-local-addressing-yes.network
@@ -14,6 +14,7 @@ Name=ifb99
Name=ipiptun99
Name=nlmon99
Name=xfrm99
+Name=vxlan98
Name=hogehogehogehogehogehoge
[Network]
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 12f91bf3c9e..21d95c7f667 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -785,6 +785,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
'vtitun98',
'vtitun99',
'vxcan99',
+ 'vxlan98',
'vxlan99',
'wg97',
'wg98',
@@ -870,6 +871,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
'25-vti-tunnel-remote-any.netdev',
'25-vti-tunnel.netdev',
'25-vxcan.netdev',
+ '25-vxlan-independent.netdev',
'25-vxlan.netdev',
'25-wireguard-23-peers.netdev',
'25-wireguard-23-peers.network',
@@ -1516,10 +1518,11 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
def test_vxlan(self):
copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
+ '25-vxlan-independent.netdev', 'netdev-link-local-addressing-yes.network',
'11-dummy.netdev', 'vxlan-test1.network')
start_networkd()
- self.wait_online(['test1:degraded', 'vxlan99:degraded'])
+ self.wait_online(['test1:degraded', 'vxlan99:degraded', 'vxlan98:degraded'])
output = check_output('ip -d link show vxlan99')
print(output)
@@ -1546,6 +1549,9 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'Destination Port: 5555')
self.assertRegex(output, 'Underlying Device: test1')
+ output = check_output('ip -d link show vxlan98')
+ print(output)
+
def test_macsec(self):
copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
'macsec.network', '12-dummy.netdev')