From 0008b5aee22e32c60f2df5ce925ddf7e25f83bd8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 3 Feb 2021 16:58:29 +0900 Subject: [PATCH 1/6] network: nexthop: unset gateway when an empty string is assigned --- src/network/networkd-nexthop.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index 6143de11f3..a05026db40 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -519,6 +519,14 @@ int config_parse_nexthop_gateway( if (r < 0) return log_oom(); + if (isempty(rvalue)) { + n->family = AF_UNSPEC; + n->gw = IN_ADDR_NULL; + + TAKE_PTR(n); + return 0; + } + r = in_addr_from_string_auto(rvalue, &n->family, &n->gw); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, From e9c4253d4713235be834d205fb8564c1c0418e2b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 3 Feb 2021 17:07:24 +0900 Subject: [PATCH 2/6] network: allow to configure nexthop with null address Closes #18446. --- src/network/networkd-nexthop.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index a05026db40..fcbb25ba15 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -440,8 +440,9 @@ static int nexthop_section_verify(NextHop *nh) { if (section_is_invalid(nh->section)) return -EINVAL; - if (in_addr_is_null(nh->family, &nh->gw) < 0) - return -EINVAL; + if (nh->family == AF_UNSPEC) + /* When no Gateway= is specified, assume IPv4. */ + nh->family = AF_INET; return 0; } From f1923efccbb8d03ca16e6ee48aedea309ede2c75 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 3 Feb 2021 16:59:26 +0900 Subject: [PATCH 3/6] network: nexthop: introduce Family= setting in [NextHop] section This is an alias of `Gateway=0.0.0.0` or `Gateway=::`. --- src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-nexthop.c | 66 +++++++++++++++++++ src/network/networkd-nexthop.h | 1 + src/network/networkd-util.c | 6 ++ src/network/networkd-util.h | 3 + .../fuzz-network-parser/directives.network | 1 + 6 files changed, 78 insertions(+) diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 44d8641572..f7dd21b73d 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -186,6 +186,7 @@ Route.TTLPropagate, config_parse_route_boolean, Route.MultiPathRoute, config_parse_multipath_route, 0, 0 NextHop.Id, config_parse_nexthop_id, 0, 0 NextHop.Gateway, config_parse_nexthop_gateway, 0, 0 +NextHop.Family, config_parse_nexthop_family, 0, 0 DHCPv4.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) DHCPv4.UseDNS, config_parse_dhcp_use_dns, 0, 0 DHCPv4.RoutesToDNS, config_parse_bool, 0, offsetof(Network, dhcp_routes_to_dns) diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index fcbb25ba15..bdbb9babe7 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -538,3 +538,69 @@ int config_parse_nexthop_gateway( TAKE_PTR(n); return 0; } + +int config_parse_nexthop_family( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(nexthop_free_or_set_invalidp) NextHop *n = NULL; + Network *network = userdata; + AddressFamily a; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = nexthop_new_static(network, filename, section_line, &n); + if (r < 0) + return log_oom(); + + if (isempty(rvalue) && + in_addr_is_null(n->family, &n->gw) != 0) { + /* Accept an empty string only when Gateway= is null or not specified. */ + n->family = AF_UNSPEC; + TAKE_PTR(n); + return 0; + } + + a = nexthop_address_family_from_string(rvalue); + if (a < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue); + return 0; + } + + if (in_addr_is_null(n->family, &n->gw) == 0 && + ((a == ADDRESS_FAMILY_IPV4 && n->family == AF_INET6) || + (a == ADDRESS_FAMILY_IPV6 && n->family == AF_INET))) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Specified family '%s' conflicts with the family of the previously specified Gateway=, " + "ignoring assignment.", rvalue); + return 0; + } + + switch(a) { + case ADDRESS_FAMILY_IPV4: + n->family = AF_INET; + break; + case ADDRESS_FAMILY_IPV6: + n->family = AF_INET6; + break; + default: + assert_not_reached("Invalid family."); + } + + TAKE_PTR(n); + return 0; +} diff --git a/src/network/networkd-nexthop.h b/src/network/networkd-nexthop.h index 75714e7ef5..3e5fbf028f 100644 --- a/src/network/networkd-nexthop.h +++ b/src/network/networkd-nexthop.h @@ -39,3 +39,4 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id); CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway); +CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_family); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index 494b23f9f4..e9fe87ea63 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -21,6 +21,11 @@ static const char* const routing_policy_rule_address_family_table[_ADDRESS_FAMIL [ADDRESS_FAMILY_IPV6] = "ipv6", }; +static const char* const nexthop_address_family_table[_ADDRESS_FAMILY_MAX] = { + [ADDRESS_FAMILY_IPV4] = "ipv4", + [ADDRESS_FAMILY_IPV6] = "ipv6", +}; + static const char* const duplicate_address_detection_address_family_table[_ADDRESS_FAMILY_MAX] = { [ADDRESS_FAMILY_NO] = "none", [ADDRESS_FAMILY_YES] = "both", @@ -55,6 +60,7 @@ AddressFamily link_local_address_family_from_string(const char *s) { } DEFINE_STRING_TABLE_LOOKUP(routing_policy_rule_address_family, AddressFamily); +DEFINE_STRING_TABLE_LOOKUP(nexthop_address_family, AddressFamily); DEFINE_STRING_TABLE_LOOKUP(duplicate_address_detection_address_family, AddressFamily); DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family, AddressFamily, "Failed to parse option"); diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h index 1b842a9a4e..fa46c3a3ec 100644 --- a/src/network/networkd-util.h +++ b/src/network/networkd-util.h @@ -38,6 +38,9 @@ AddressFamily link_local_address_family_from_string(const char *s) _pure_; const char *routing_policy_rule_address_family_to_string(AddressFamily b) _const_; AddressFamily routing_policy_rule_address_family_from_string(const char *s) _pure_; +const char *nexthop_address_family_to_string(AddressFamily b) _const_; +AddressFamily nexthop_address_family_from_string(const char *s) _pure_; + const char *duplicate_address_detection_address_family_to_string(AddressFamily b) _const_; AddressFamily duplicate_address_detection_address_family_from_string(const char *s) _pure_; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 51dd56ade9..6039e74795 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -349,6 +349,7 @@ SendVendorOption= [NextHop] Id= Gateway= +Family= [QDisc] Parent= Handle= From acfd8491fb7dc0bdb0508ef1d6c462491d26ed84 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 4 Feb 2021 23:22:27 +0900 Subject: [PATCH 4/6] network: nexthop: refuse 0 id We usually do not accept values which will be handled as unspecified. Instead, this makes config_parse_nexthop_id() accept an empty string. --- src/network/networkd-nexthop.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index bdbb9babe7..629fd78226 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -269,9 +269,11 @@ static int nexthop_configure(NextHop *nexthop, Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not create RTM_NEWNEXTHOP message: %m"); - r = sd_netlink_message_append_u32(req, NHA_ID, nexthop->id); - if (r < 0) - return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m"); + if (nexthop->id > 0) { + r = sd_netlink_message_append_u32(req, NHA_ID, nexthop->id); + if (r < 0) + return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m"); + } r = sd_netlink_message_append_u32(req, NHA_OIF, link->ifindex); if (r < 0) @@ -471,6 +473,7 @@ int config_parse_nexthop_id( _cleanup_(nexthop_free_or_set_invalidp) NextHop *n = NULL; Network *network = userdata; + uint32_t id; int r; assert(filename); @@ -483,13 +486,25 @@ int config_parse_nexthop_id( if (r < 0) return log_oom(); - r = safe_atou32(rvalue, &n->id); + if (isempty(rvalue)) { + n->id = 0; + TAKE_PTR(n); + return 0; + } + + r = safe_atou32(rvalue, &id); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Could not parse nexthop id \"%s\", ignoring assignment: %m", rvalue); return 0; } + if (id == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid nexthop id \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + n->id = id; TAKE_PTR(n); return 0; } From 26ff450550657a7dac71139ab394947fea6ed3ee Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 9 Feb 2021 15:42:51 +0900 Subject: [PATCH 5/6] man: update explanations of settings in [NextHop] section --- man/systemd.network.xml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 74ec6a29f1..bf6aa80bd2 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1321,15 +1321,25 @@ IPv6Token=prefixstable:2002:da8:1:: - Gateway= + Id= - As in the [Network] section. This is mandatory. + The id of the next hop. Takes an unsigned integer in the range 1…4294967295. If left + unspecified, then automatically chosen by kernel. - Id= + Gateway= - The id of the nexthop (an unsigned integer). If unspecified or '0' then automatically chosen by kernel. + As in the [Network] section. + + + + Family= + + Takes one of the special values ipv4 or ipv6. + By default, the family is determined by the address specified in + Gateway=. If Gateway= is not specified, then defaults + to ipv4. From 6cd8f9b5f2844040898efa0ebbbb30498e548f62 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 3 Feb 2021 17:19:04 +0900 Subject: [PATCH 6/6] test-network: add tests for Family= in [NextHop] --- test/test-network/conf/25-nexthop.network | 16 ++++++++++++++++ test/test-network/systemd-networkd-tests.py | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/test/test-network/conf/25-nexthop.network b/test/test-network/conf/25-nexthop.network index 3eea077345..f32cc1a2db 100644 --- a/test/test-network/conf/25-nexthop.network +++ b/test/test-network/conf/25-nexthop.network @@ -3,9 +3,25 @@ Name=veth99 [Network] IPv6AcceptRA=no +Address=2001:1234:5:8f63::1/120 Address=192.168.5.10/24 Gateway=192.168.5.1 [NextHop] Id=1 Gateway=192.168.5.1 + +[NextHop] +Id=2 +Gateway=2001:1234:5:8f63::2 + +[NextHop] +Id=3 +Family=ipv6 + +[NextHop] +Id=4 +Family=ipv4 + +[NextHop] +Gateway=192.168.5.2 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 0740003ed3..e9dc185345 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2799,7 +2799,11 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): output = check_output('ip nexthop list dev veth99') print(output) - self.assertRegex(output, '192.168.5.1') + self.assertIn('id 1 via 192.168.5.1 dev veth99', output) + self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output) + self.assertIn('id 3 dev veth99', output) + self.assertIn('id 4 dev veth99', output) + self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99') def test_qdisc(self): copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',