diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index cac1d3b6e7..9daa1254b6 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -131,6 +131,12 @@ for more details about the sysctl options. Defaults to unset and the sysctl options will not be changed. + If an interface is configured with a .network file that enables IPMasquerade= + for IPv4 (that is, ipv4 or both), this setting is implied + unless explicitly specified. See IPMasquerade= in + systemd.network5 + for more details. + @@ -145,6 +151,12 @@ for more details about the sysctl options. Defaults to unset and the sysctl options will not be changed. + If an interface is configured with a .network file that enables IPMasquerade= + for IPv6 (that is, ipv6 or both), this setting is implied + unless explicitly specified. See IPMasquerade= in + systemd.network5 + for more details. + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index ebcb6d0481..0374dc7cdc 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -888,15 +888,15 @@ DuplicateAddressDetection=none ipv6, both, or no. Defaults to no. Note. Any positive boolean values such as yes or true are now deprecated. Please use one of the values above. Specifying - ipv4 or both implies IPv4Forwarding=, - unless it is explicitly specified. Similarly for IPv6Forwarding= when - ipv6 or both is specified. These implications are only on - this interface. Hence, to make the IP packet forwarding works, - IPv4Forwarding=/IPv6Forwarding= need to be enabled on an - upstream interface, or globally enabled by specifying them in - networkd.conf5. - See IPv4Forwarding=/IPv6Forwarding= in the above for more - details. + ipv4 or both implies IPv4Forwarding= + settings in both .network file for this interface and the global + networkd.conf5 + unless they are explicitly specified. Similarly for IPv6Forwarding= when + ipv6 or both is specified. See + IPv4Forwarding=/IPv6Forwarding= in the above for the per-link + settings, and + networkd.conf5 + for the global settings. diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index 68c23e0eb7..a454322fd0 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -7,7 +7,9 @@ #include "af-list.h" #include "missing_network.h" #include "networkd-link.h" +#include "networkd-lldp-tx.h" #include "networkd-manager.h" +#include "networkd-ndisc.h" #include "networkd-network.h" #include "networkd-sysctl.h" #include "socket-util.h" @@ -130,7 +132,7 @@ int link_get_ip_forwarding(Link *link, int family) { return link->manager->ip_forwarding[family == AF_INET6]; } -static int link_set_ip_forwarding(Link *link, int family) { +static int link_set_ip_forwarding_impl(Link *link, int family) { int r, t; assert(link); @@ -151,6 +153,65 @@ static int link_set_ip_forwarding(Link *link, int family) { return 0; } +static int link_reapply_ip_forwarding(Link *link, int family) { + int r, ret = 0; + + assert(link); + assert(IN_SET(family, AF_INET, AF_INET6)); + + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + return 0; + + (void) link_set_ip_forwarding_impl(link, family); + + r = link_lldp_tx_update_capabilities(link); + if (r < 0) + RET_GATHER(ret, log_link_warning_errno(link, r, "Could not update LLDP capabilities, ignoring: %m")); + + if (family == AF_INET6 && !link_ndisc_enabled(link)) { + r = ndisc_stop(link); + if (r < 0) + RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery, ignoring: %m")); + + ndisc_flush(link); + } + + return ret; +} + +static int link_set_ip_forwarding(Link *link, int family) { + int r; + + assert(link); + assert(link->manager); + assert(link->network); + assert(IN_SET(family, AF_INET, AF_INET6)); + + if (!link_is_configured_for_family(link, family)) + return 0; + + /* When IPMasquerade= is enabled and the global setting is unset, enable _global_ IP forwarding, and + * re-apply per-link setting for all links. */ + if (FLAGS_SET(link->network->ip_masquerade, family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6) && + link->manager->ip_forwarding[family == AF_INET6] < 0) { + + link->manager->ip_forwarding[family == AF_INET6] = true; + manager_set_ip_forwarding(link->manager, family); + + Link *other; + HASHMAP_FOREACH(other, link->manager->links_by_index) { + r = link_reapply_ip_forwarding(other, family); + if (r < 0) + link_enter_failed(other); + } + + return 0; + } + + /* Otherwise, apply per-link setting for _this_ link. */ + return link_set_ip_forwarding_impl(link, family); +} + static int link_set_ipv4_rp_filter(Link *link) { assert(link);