Merge pull request #18632 from yuwata/network-nexthop-add-family
network: introduce Family= setting in [NextHop] section
This commit is contained in:
+14
-4
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user