1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-22 22:03:43 +03:00

Merge pull request #11840 from yuwata/network-route-onlink

network: enable GatewayOnLink= if no static address is configured
This commit is contained in:
Lennart Poettering 2019-02-28 12:02:08 +01:00 committed by GitHub
commit e19ebdd66d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 133 additions and 63 deletions

View File

@ -1081,7 +1081,7 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>GatewayOnlink=</varname></term>
<term><varname>GatewayOnLink=</varname></term>
<listitem>
<para>Takes a boolean. If set to true, the kernel does not have
to check if the gateway is reachable directly by the current machine (i.e., the kernel does

View File

@ -690,13 +690,15 @@ int config_parse_broadcast(
return r;
if (n->family == AF_INET6) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, 0,
"Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
return 0;
}
r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r,
"Broadcast is invalid, ignoring assignment: %s", rvalue);
return 0;
}
@ -802,7 +804,8 @@ int config_parse_label(
return r;
if (!address_label_valid(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, 0,
"Interface label is too long or invalid, ignoring assignment: %s", rvalue);
return 0;
}
@ -811,7 +814,6 @@ int config_parse_label(
return log_oom();
n = NULL;
return 0;
}
@ -840,26 +842,20 @@ int config_parse_lifetime(const char *unit,
if (r < 0)
return r;
if (STR_IN_SET(rvalue, "forever", "infinity")) {
n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
n = NULL;
return 0;
}
r = safe_atou(rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
return 0;
}
if (k != 0)
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
/* We accept only "forever", "infinity", or "0". */
if (STR_IN_SET(rvalue, "forever", "infinity"))
k = CACHE_INFO_INFINITY_LIFE_TIME;
else if (streq(rvalue, "0"))
k = 0;
else {
n->cinfo.ifa_prefered = k;
n = NULL;
log_syntax(unit, LOG_ERR, filename, line, 0,
"Invalid PreferredLifetime= value, ignoring: %s", rvalue);
return 0;
}
n->cinfo.ifa_prefered = k;
n = NULL;
return 0;
}
@ -889,7 +885,8 @@ int config_parse_address_flags(const char *unit,
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse address flag, ignoring: %s", rvalue);
return 0;
}
@ -903,7 +900,10 @@ int config_parse_address_flags(const char *unit,
n->prefix_route = r;
else if (streq(lvalue, "AutoJoin"))
n->autojoin = r;
else
assert_not_reached("Invalid address flag type.");
n = NULL;
return 0;
}
@ -940,13 +940,13 @@ int config_parse_address_scope(const char *unit,
else {
r = safe_atou8(rvalue , &n->scope);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r,
"Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
}
n = NULL;
return 0;
}

View File

@ -117,6 +117,7 @@ Route.Scope, config_parse_route_scope,
Route.PreferredSource, config_parse_preferred_src, 0, 0
Route.Table, config_parse_route_table, 0, 0
Route.MTUBytes, config_parse_route_mtu, AF_UNSPEC, 0
Route.GatewayOnLink, config_parse_gateway_onlink, 0, 0
Route.GatewayOnlink, config_parse_gateway_onlink, 0, 0
Route.IPv6Preference, config_parse_ipv6_route_preference, 0, 0
Route.Protocol, config_parse_route_protocol, 0, 0

View File

@ -196,8 +196,8 @@ static uint32_t network_get_stacked_netdevs_mtu(Network *network) {
}
static int network_verify(Network *network) {
Address *address;
Route *route;
Address *address, *address_next;
Route *route, *route_next;
uint32_t mtu;
assert(network);
@ -284,19 +284,35 @@ static int network_verify(Network *network) {
network->dhcp_use_mtu = false;
}
LIST_FOREACH(routes, route, network->static_routes)
if (!route->family)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Route section without Gateway field configured. "
"Ignoring %s.",
network->filename, network->filename);
LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
if (address->family == AF_UNSPEC) {
log_warning("%s: Address section without Address= field configured. "
"Ignoring [Address] section from line %u.",
network->filename, address->section->line);
LIST_FOREACH(addresses, address, network->static_addresses)
if (!address->family)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Address section without Address field configured. "
"Ignoring %s.",
network->filename, network->filename);
address_free(address);
}
LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes) {
if (route->family == AF_UNSPEC) {
log_warning("%s: Route section without Gateway=, Destination=, Source=, "
"or PreferredSource= field configured. "
"Ignoring [Route] section from line %u.",
network->filename, route->section->line);
route_free(route);
continue;
}
if (network->n_static_addresses == 0 &&
in_addr_is_null(route->family, &route->gw) == 0 &&
route->gateway_onlink < 0) {
log_warning("%s: Gateway= without static address configured. "
"Enabling GatewayOnLink= option.",
network->filename);
route->gateway_onlink = true;
}
}
return 0;
}

View File

@ -59,6 +59,7 @@ int route_new(Route **ret) {
.table = RT_TABLE_MAIN,
.lifetime = USEC_INFINITY,
.quickack = -1,
.gateway_onlink = -1,
};
*ret = TAKE_PTR(route);
@ -565,6 +566,9 @@ int route_configure(
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
if (route->gateway_onlink >= 0)
SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
r = sd_rtnl_message_route_set_flags(req, route->flags);
if (r < 0)
return log_error_errno(r, "Could not set flags: %m");
@ -700,18 +704,20 @@ int config_parse_gateway(
r = route_new_static(network, NULL, 0, &n);
} else
r = route_new_static(network, filename, section_line, &n);
if (r < 0)
return r;
r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
if (n->family == AF_UNSPEC)
r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
else
r = in_addr_from_string(n->family, rvalue, &n->gw);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r,
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
@ -741,15 +747,17 @@ int config_parse_preferred_src(
if (r < 0)
return r;
r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
if (n->family == AF_UNSPEC)
r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
else
r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Preferred source is invalid, ignoring assignment: %s", rvalue);
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
@ -790,11 +798,13 @@ int config_parse_destination(
} else
assert_not_reached(lvalue);
r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
if (n->family == AF_UNSPEC)
r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
else
r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Route %s= prefix is invalid, ignoring assignment: %s",
lvalue, rvalue);
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
@ -946,11 +956,12 @@ int config_parse_gateway_onlink(
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Could not parse gateway onlink \"%s\", ignoring assignment: %m", rvalue);
"Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
return 0;
}
SET_FLAG(n->flags, RTNH_F_ONLINK, r);
n->gateway_onlink = r;
TAKE_PTR(n);
return 0;
}
@ -1019,7 +1030,8 @@ int config_parse_route_protocol(
else {
r = safe_atou8(rvalue , &n->protocol);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r,
"Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
}
@ -1059,7 +1071,8 @@ int config_parse_route_type(
else if (streq(rvalue, "throw"))
n->type = RTN_THROW;
else {
log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r,
"Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
@ -1095,9 +1108,14 @@ int config_parse_tcp_window(
return r;
r = parse_size(rvalue, 1024, &k);
if (r < 0 || k > UINT32_MAX) {
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Could not parse TCP %s \"%s\" bytes, ignoring assignment: %m", rvalue, lvalue);
"Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
return 0;
}
if (k > UINT32_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
return 0;
}
@ -1105,10 +1123,8 @@ int config_parse_tcp_window(
n->initcwnd = k;
else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
n->initrwnd = k;
else {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse TCP %s: %s", lvalue, rvalue);
return 0;
}
else
assert_not_reached("Invalid TCP window type.");
TAKE_PTR(n);
return 0;
@ -1142,7 +1158,8 @@ int config_parse_quickack(
k = parse_boolean(rvalue);
if (k < 0) {
log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse TCP quickack, ignoring: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, k,
"Failed to parse TCP quickack, ignoring: %s", rvalue);
return 0;
}

View File

@ -30,6 +30,7 @@ struct Route {
uint32_t initrwnd;
unsigned char pref;
unsigned flags;
int gateway_onlink;
union in_addr_union gw;
union in_addr_union dst;

View File

@ -60,6 +60,7 @@ Protocol=
Table=
Gateway=
InitialAdvertisedReceiveWindow=
GatewayOnLink=
GatewayOnlink=
Type=
InitialCongestionWindow=

View File

@ -409,7 +409,7 @@ From=
FwMark=
GVRP=
Gateway=
GatewayOnlink=
GatewayOnLink=
GenericReceiveOffload=
GenericSegmentationOffload=
GratuitousARP=

View File

@ -10,4 +10,4 @@ Scope=link
[Route]
Gateway=149.10.125.65
GatewayOnlink=true
GatewayOnLink=true

View File

@ -0,0 +1,13 @@
[Match]
Name=veth99
[Network]
DHCP=ipv4
[Route]
Gateway=192.168.0.1
Destination=10.0.0.0/8
[Route]
Gateway=192.168.0.1
Destination=192.168.100.0/24

View File

@ -1491,6 +1491,7 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
'25-vrf.network',
'dhcp-client-anonymize.network',
'dhcp-client-critical-connection.network',
'dhcp-client-gateway-onlink-implicit.network',
'dhcp-client-ipv4-dhcp-settings.network',
'dhcp-client-ipv4-only-ipv6-disabled.network',
'dhcp-client-ipv4-only.network',
@ -1776,6 +1777,26 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, 'State: routable \(configured\)')
def test_dhcp_client_gateway_onlink_implicit(self):
self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
'dhcp-client-gateway-onlink-implicit.network')
self.start_networkd()
self.assertTrue(self.link_exits('veth99'))
self.start_dnsmasq()
output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
print(output)
self.assertRegex(output, '192.168.5')
output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8']).rstrip().decode('utf-8')
print(output)
self.assertRegex(output, 'onlink')
output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24']).rstrip().decode('utf-8')
print(output)
self.assertRegex(output, 'onlink')
if __name__ == '__main__':
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
verbosity=3))