From dcd333168e0e5737b2f72472dc5ed1dd75ae08d4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 7 Dec 2024 05:03:56 +0900 Subject: [PATCH 1/3] sysctl-util: support AF_MPLS To support writing/reading e.g. /proc/sys/net/mpls/conf/eth0/input . --- src/basic/sysctl-util.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/basic/sysctl-util.c b/src/basic/sysctl-util.c index 2feb4917d7..da6e4c58d4 100644 --- a/src/basic/sysctl-util.c +++ b/src/basic/sysctl-util.c @@ -115,22 +115,29 @@ int sysctl_writef(const char *property, const char *format, ...) { return sysctl_write(property, v); } +static const char* af_to_sysctl_dir(int af) { + if (af == AF_MPLS) + return "mpls"; + + return af_to_ipv4_ipv6(af); +} + int sysctl_write_ip_property(int af, const char *ifname, const char *property, const char *value, Hashmap **shadow) { const char *p; assert(property); assert(value); - if (!IN_SET(af, AF_INET, AF_INET6)) + if (!IN_SET(af, AF_INET, AF_INET6, AF_MPLS)) return -EAFNOSUPPORT; if (ifname) { if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL)) return -EINVAL; - p = strjoina("net/", af_to_ipv4_ipv6(af), "/conf/", ifname, "/", property); + p = strjoina("net/", af_to_sysctl_dir(af), "/conf/", ifname, "/", property); } else - p = strjoina("net/", af_to_ipv4_ipv6(af), "/", property); + p = strjoina("net/", af_to_sysctl_dir(af), "/", property); return sysctl_write_full(p, value, shadow); } @@ -181,16 +188,16 @@ int sysctl_read_ip_property(int af, const char *ifname, const char *property, ch assert(property); - if (!IN_SET(af, AF_INET, AF_INET6)) + if (!IN_SET(af, AF_INET, AF_INET6, AF_MPLS)) return -EAFNOSUPPORT; if (ifname) { if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL)) return -EINVAL; - p = strjoina("net/", af_to_ipv4_ipv6(af), "/conf/", ifname, "/", property); + p = strjoina("net/", af_to_sysctl_dir(af), "/conf/", ifname, "/", property); } else - p = strjoina("net/", af_to_ipv4_ipv6(af), "/", property); + p = strjoina("net/", af_to_sysctl_dir(af), "/", property); return sysctl_read(p, ret); } From 10a768443a4ca0293d7902f1f0884ea2cba7e114 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 7 Dec 2024 05:46:13 +0900 Subject: [PATCH 2/3] network: introduce MPLSRouting= to enable MPLS routing Closing #35487. --- man/systemd.network.xml | 18 ++++++++++++++++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 1 + src/network/networkd-sysctl.c | 19 ++++++++++++++++++- 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 32cfb207e0..e2d698285e 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1148,6 +1148,24 @@ DuplicateAddressDetection=none + + MPLSRouting= + + Control whether Multi-protocol Label Switching (MPLS) routing is enabled on this interface. + This configures /proc/sys/net/mpls/conf/INTERFACE/input. + Takes a boolean. Defaults to unset, and the kernel's default will be used. + + Note, systemd-networkd does not load any required + kernel modules for MPLS. To enable the feature, mpls_router kernel module must + be loaded before systemd-networkd.service is started. Consider adding the + kernel module to + modules-load.d5. + + + + + + KeepMaster= diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index ab7f2553ec..dc462b690c 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -151,6 +151,7 @@ Network.ProxyARP, config_parse_tristate, Network.IPv6ProxyNDPAddress, config_parse_ipv6_proxy_ndp_address, 0, 0 Network.IPv4ReversePathFilter, config_parse_ip_reverse_path_filter, 0, offsetof(Network, ipv4_rp_filter) Network.MulticastIGMPVersion, config_parse_ipv4_force_igmp_version, 0, offsetof(Network, ipv4_force_igmp_version) +Network.MPLSRouting, config_parse_tristate, 0, offsetof(Network, mpls_input) Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) Network.ConfigureWithoutCarrier, config_parse_bool, 0, offsetof(Network, configure_without_carrier) Network.IgnoreCarrierLoss, config_parse_ignore_carrier_loss, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 89dcf4f6c4..3ecddff129 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -482,6 +482,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .proxy_arp_pvlan = -1, .ipv4_rp_filter = _IP_REVERSE_PATH_FILTER_INVALID, .ipv4_force_igmp_version = _IPV4_FORCE_IGMP_VERSION_INVALID, + .mpls_input = -1, .ndisc = -1, .ndisc_use_redirect = true, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 03e3108623..b61914ea7a 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -343,6 +343,7 @@ struct Network { IPv4ForceIgmpVersion ipv4_force_igmp_version; int ipv6_proxy_ndp; Set *ipv6_proxy_ndp_addresses; + int mpls_input; /* NDisc support */ int ndisc; diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index 10a35bc44b..fb2864eb4f 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -243,7 +243,7 @@ static bool link_is_configured_for_family(Link *link, int family) { /* CAN devices do not support IP layer. Most of the functions below are never called for CAN devices, * but link_set_ipv6_mtu() may be called after setting interface MTU, and warn about the failure. For * safety, let's unconditionally check if the interface is not a CAN device. */ - if (IN_SET(family, AF_INET, AF_INET6) && link->iftype == ARPHRD_CAN) + if (IN_SET(family, AF_INET, AF_INET6, AF_MPLS) && link->iftype == ARPHRD_CAN) return false; if (family == AF_INET6 && !socket_ipv6_is_supported()) @@ -671,6 +671,19 @@ static int link_set_ipv4_promote_secondaries(Link *link) { return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true, manager_get_sysctl_shadow(link->manager)); } +static int link_set_mpls_input(Link *link) { + assert(link); + assert(link->manager); + + if (!link_is_configured_for_family(link, AF_MPLS)) + return 0; + + if (link->network->mpls_input < 0) + return 0; + + return sysctl_write_ip_property_boolean(AF_MPLS, link->ifname, "input", link->network->mpls_input > 0, manager_get_sysctl_shadow(link->manager)); +} + int link_set_sysctl(Link *link) { int r; @@ -743,6 +756,10 @@ int link_set_sysctl(Link *link) { if (r < 0) log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m"); + r = link_set_mpls_input(link); + if (r < 0) + log_link_warning_errno(link, r, "Cannot set MPLS input, ignoring: %m"); + return 0; } From af44a16ec7c4eb73ab90767fc5bc1c146e56bc9b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 7 Dec 2024 05:47:07 +0900 Subject: [PATCH 3/3] test-network: add test case for MPLSRouting=yes --- test/test-network/conf/25-sysctl-mpls.network | 7 +++++++ test/test-network/systemd-networkd-tests.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 test/test-network/conf/25-sysctl-mpls.network diff --git a/test/test-network/conf/25-sysctl-mpls.network b/test/test-network/conf/25-sysctl-mpls.network new file mode 100644 index 0000000000..9494efd009 --- /dev/null +++ b/test/test-network/conf/25-sysctl-mpls.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=dummy98 + +[Network] +IPv6AcceptRA=no +MPLSRouting=yes diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 000645c916..136a6ed744 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -732,6 +732,9 @@ def read_ipv6_neigh_sysctl_attr(link, attribute): def read_ipv4_sysctl_attr(link, attribute): return read_ip_sysctl_attr(link, attribute, 'ipv4') +def read_mpls_sysctl_attr(link, attribute): + return read_ip_sysctl_attr(link, attribute, 'mpls') + def stop_by_pid_file(pid_file): if not os.path.exists(pid_file): return @@ -1117,6 +1120,9 @@ class Utilities(): def check_ipv6_neigh_sysctl_attr(self, link, attribute, expected): self.assertEqual(read_ipv6_neigh_sysctl_attr(link, attribute), expected) + def check_mpls_sysctl_attr(self, link, attribute, expected): + self.assertEqual(read_mpls_sysctl_attr(link, attribute), expected) + def wait_links(self, *links, trial=40): for _ in range(trial): if link_exists(*links): @@ -4568,6 +4574,15 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff') + @expectedFailureIfModuleIsNotAvailable('mpls_router') + def test_sysctl_mpls(self): + check_output('modprobe mpls_router') + copy_network_unit('25-sysctl-mpls.network', '12-dummy.netdev') + start_networkd() + self.wait_online('dummy98:degraded') + + self.check_mpls_sysctl_attr('dummy98', 'input', '1') + def test_bind_carrier(self): copy_network_unit('25-bind-carrier.network', '11-dummy.netdev') start_networkd()