Merge pull request #18632 from yuwata/network-nexthop-add-family

network: introduce Family= setting in [NextHop] section
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2021-02-17 15:02:50 +01:00
committed by GitHub
9 changed files with 143 additions and 11 deletions
+14 -4
View File
@@ -1321,15 +1321,25 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>Gateway=</varname></term>
<term><varname>Id=</varname></term>
<listitem>
<para>As in the [Network] section. This is mandatory.</para>
<para>The id of the next hop. Takes an unsigned integer in the range 1…4294967295. If left
unspecified, then automatically chosen by kernel.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Id=</varname></term>
<term><varname>Gateway=</varname></term>
<listitem>
<para>The id of the nexthop (an unsigned integer). If unspecified or '0' then automatically chosen by kernel.</para>
<para>As in the [Network] section.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Family=</varname></term>
<listitem>
<para>Takes one of the special values <literal>ipv4</literal> or <literal>ipv6</literal>.
By default, the family is determined by the address specified in
<varname>Gateway=</varname>. If <varname>Gateway=</varname> is not specified, then defaults
to <literal>ipv4</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
+1
View File
@@ -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)
+96 -6
View File
@@ -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)
@@ -440,8 +442,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;
}
@@ -470,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);
@@ -482,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;
}
@@ -519,6 +535,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,
@@ -529,3 +553,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;
}
+1
View File
@@ -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);
+6
View File
@@ -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");
+3
View File
@@ -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_;
@@ -349,6 +349,7 @@ SendVendorOption=
[NextHop]
Id=
Gateway=
Family=
[QDisc]
Parent=
Handle=
+16
View File
@@ -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
+5 -1
View File
@@ -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',