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/libsystemd-network/sd-lldp-tx.c b/src/libsystemd-network/sd-lldp-tx.c index 2b822af01a..01c476ecde 100644 --- a/src/libsystemd-network/sd-lldp-tx.c +++ b/src/libsystemd-network/sd-lldp-tx.c @@ -590,6 +590,7 @@ int sd_lldp_tx_stop(sd_lldp_tx *lldp_tx) { return 1; } + int sd_lldp_tx_start(sd_lldp_tx *lldp_tx) { usec_t delay; int r; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index f48781ef8b..cc22fbf2d6 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -86,6 +86,36 @@ int link_lldp_tx_configure(Link *link) { return 0; } +int link_lldp_tx_update_capabilities(Link *link) { + int r; + + assert(link); + + if (!link->lldp_tx) + return 0; /* disabled, or not configured yet. */ + + r = sd_lldp_tx_set_capabilities(link->lldp_tx, + SD_LLDP_SYSTEM_CAPABILITIES_STATION | + SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE | + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER, + (link_get_ip_forwarding(link, AF_INET) > 0 || link_get_ip_forwarding(link, AF_INET6) > 0) ? + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER : SD_LLDP_SYSTEM_CAPABILITIES_STATION); + if (r < 0) + return r; + + if (sd_lldp_tx_is_running(link->lldp_tx)) { + r = sd_lldp_tx_stop(link->lldp_tx); + if (r < 0) + return r; + + r = sd_lldp_tx_start(link->lldp_tx); + if (r < 0) + return r; + } + + return 0; +} + static const char * const lldp_multicast_mode_table[_SD_LLDP_MULTICAST_MODE_MAX] = { [SD_LLDP_MULTICAST_MODE_NEAREST_BRIDGE] = "nearest-bridge", [SD_LLDP_MULTICAST_MODE_NON_TPMR_BRIDGE] = "non-tpmr-bridge", diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h index 73757f1725..346eb5cb1c 100644 --- a/src/network/networkd-lldp-tx.h +++ b/src/network/networkd-lldp-tx.h @@ -6,5 +6,6 @@ typedef struct Link Link; int link_lldp_tx_configure(Link *link); +int link_lldp_tx_update_capabilities(Link *link); CONFIG_PARSER_PROTOTYPE(config_parse_lldp_multicast_mode); 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); diff --git a/test/TEST-13-NSPAWN/test.sh b/test/TEST-13-NSPAWN/test.sh index 5c85b0c5dc..3ab52d0eee 100755 --- a/test/TEST-13-NSPAWN/test.sh +++ b/test/TEST-13-NSPAWN/test.sh @@ -17,6 +17,8 @@ test_append_files() { # For virtual wlan interface. instmods mac80211_hwsim + # for IPMasquerade= + instmods "=net/netfilter" generate_module_dependencies # Create a dummy container "template" with a minimal toolset, which we can diff --git a/test/test-functions b/test/test-functions index e41e5792a3..8f08d84ad8 100644 --- a/test/test-functions +++ b/test/test-functions @@ -1454,10 +1454,31 @@ install_missing_libraries() { [[ -e "$libgcc_s" ]] && inst_library "$libgcc_s" done < <(ldconfig -p | awk '/\/libgcc_s.so.1$/ { print $4 }') - local lib path + local lib path libs # A number of dependencies is now optional via dlopen, so the install # script will not pick them up, since it looks at linkage. - for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw xkbcommon p11-kit-1 libarchive libgcrypt libkmod; do + libs=( + libarchive + libbpf + libcryptsetup + libdw + libelf + libfido2 + libgcrypt + libidn + libidn2 + libip4tc + libkmod + libqrencode + p11-kit-1 + pwquality + tss2-esys + tss2-mu + tss2-rc + tss2-tcti-device + xkbcommon + ) + for lib in "${libs[@]}"; do ddebug "Searching for $lib via pkg-config" if pkg-config --exists "$lib"; then path="$(pkg-config --variable=libdir "$lib")" diff --git a/test/units/TEST-13-NSPAWN.nspawn.sh b/test/units/TEST-13-NSPAWN.nspawn.sh index 0c74d2e16e..2de9f9079f 100755 --- a/test/units/TEST-13-NSPAWN.nspawn.sh +++ b/test/units/TEST-13-NSPAWN.nspawn.sh @@ -943,6 +943,17 @@ matrix_run_one() { return 0 } +testcase_api_vfs() { + local api_vfs_writable + + for api_vfs_writable in yes no network; do + matrix_run_one no no $api_vfs_writable + matrix_run_one yes no $api_vfs_writable + matrix_run_one no yes $api_vfs_writable + matrix_run_one yes yes $api_vfs_writable + done +} + testcase_check_os_release() { # https://github.com/systemd/systemd/issues/29185 local base common_opts root @@ -1003,11 +1014,46 @@ EOF rm -fr "$root" } -run_testcases +testcase_ip_masquerade() { + local root -for api_vfs_writable in yes no network; do - matrix_run_one no no $api_vfs_writable - matrix_run_one yes no $api_vfs_writable - matrix_run_one no yes $api_vfs_writable - matrix_run_one yes yes $api_vfs_writable -done + if ! command -v networkctl >/dev/null; then + echo "This test requires systemd-networkd, skipping..." + return 0 + fi + + systemctl unmask systemd-networkd.service + systemctl edit --runtime --stdin systemd-networkd.service --drop-in=debug.conf <