diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 4c777ef4e0..554d8da8ef 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1086,6 +1086,19 @@ DuplicateAddressDetection=none
+
+ IPv4SrcValidMark=
+
+ Takes a boolean. When enabled, the packet's firewall mark (fwmark) is included in the
+ reverse path filter route lookup for source address validation on this interface. This is
+ particularly useful for policy routing setups where packets may arrive with source addresses
+ that are only valid in routing tables selected by their fwmark. When unset, the kernel's
+ default will be used.
+
+
+
+
+
IPv4ProxyARP=
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index f1049cc7cc..aaf974e312 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -168,6 +168,7 @@ Network.IPv6ProxyNDP, config_parse_tristate,
Network.IPv6MTUBytes, config_parse_mtu, AF_INET6, offsetof(Network, ipv6_mtu)
Network.IPv4AcceptLocal, config_parse_tristate, 0, offsetof(Network, ipv4_accept_local)
Network.IPv4RouteLocalnet, config_parse_tristate, 0, offsetof(Network, ipv4_route_localnet)
+Network.IPv4SrcValidMark, config_parse_tristate, 0, offsetof(Network, ipv4_src_valid_mark)
Network.ActiveSlave, config_parse_bool, 0, offsetof(Network, active_slave)
Network.PrimarySlave, config_parse_bool, 0, offsetof(Network, primary_slave)
Network.IPv4ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 1e159fa310..3ffe1640e7 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -479,6 +479,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.ip_forwarding = { -1, -1, },
.ipv4_accept_local = -1,
.ipv4_route_localnet = -1,
+ .ipv4_src_valid_mark = -1,
.ipv6_privacy_extensions = _IPV6_PRIVACY_EXTENSIONS_INVALID,
.ipv6_dad_transmits = -1,
.ipv6_proxy_ndp = -1,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 923828b2ea..9a36c312f8 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -332,6 +332,7 @@ typedef struct Network {
int ip_forwarding[2];
int ipv4_accept_local;
int ipv4_route_localnet;
+ int ipv4_src_valid_mark;
int ipv6_dad_transmits;
uint8_t ipv6_hop_limit;
usec_t ipv6_retransmission_time;
diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c
index 914fbccd09..e5f5c07ff1 100644
--- a/src/network/networkd-sysctl.c
+++ b/src/network/networkd-sysctl.c
@@ -662,6 +662,20 @@ static int link_set_ipv4_route_localnet(Link *link) {
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0, manager_get_sysctl_shadow(link->manager));
}
+static int link_set_ipv4_src_valid_mark(Link *link) {
+ assert(link);
+ assert(link->manager);
+ assert(link->network);
+
+ if (!link_is_configured_for_family(link, AF_INET))
+ return 0;
+
+ if (link->network->ipv4_src_valid_mark < 0)
+ return 0;
+
+ return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "src_valid_mark", link->network->ipv4_src_valid_mark > 0, manager_get_sysctl_shadow(link->manager));
+}
+
static int link_set_ipv4_promote_secondaries(Link *link) {
assert(link);
assert(link->manager);
@@ -750,6 +764,10 @@ int link_set_sysctl(Link *link) {
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
+ r = link_set_ipv4_src_valid_mark(link);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot set IPv4 src_valid_mark flag for interface, ignoring: %m");
+
r = link_set_ipv4_rp_filter(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
diff --git a/test/test-network/conf/25-sysctl.network b/test/test-network/conf/25-sysctl.network
index dcc4f0d293..c0c709c32c 100644
--- a/test/test-network/conf/25-sysctl.network
+++ b/test/test-network/conf/25-sysctl.network
@@ -12,5 +12,6 @@ IPv4ProxyARPPrivateVLAN=yes
IPv6ProxyNDP=yes
IPv6AcceptRA=no
IPv4AcceptLocal=yes
+IPv4SrcValidMark=yes
IPv4ReversePathFilter=no
MulticastIGMPVersion=v1
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 91d97383e7..0db4830848 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -5003,6 +5003,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '1')
self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp_pvlan', '1')
self.check_ipv4_sysctl_attr('dummy98', 'accept_local', '1')
+ self.check_ipv4_sysctl_attr('dummy98', 'src_valid_mark', '1')
self.check_ipv4_sysctl_attr('dummy98', 'rp_filter', '0')
self.check_ipv4_sysctl_attr('dummy98', 'force_igmp_version', '1')