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:
commit
e19ebdd66d
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -60,6 +60,7 @@ Protocol=
|
||||
Table=
|
||||
Gateway=
|
||||
InitialAdvertisedReceiveWindow=
|
||||
GatewayOnLink=
|
||||
GatewayOnlink=
|
||||
Type=
|
||||
InitialCongestionWindow=
|
||||
|
@ -409,7 +409,7 @@ From=
|
||||
FwMark=
|
||||
GVRP=
|
||||
Gateway=
|
||||
GatewayOnlink=
|
||||
GatewayOnLink=
|
||||
GenericReceiveOffload=
|
||||
GenericSegmentationOffload=
|
||||
GratuitousARP=
|
||||
|
@ -10,4 +10,4 @@ Scope=link
|
||||
|
||||
[Route]
|
||||
Gateway=149.10.125.65
|
||||
GatewayOnlink=true
|
||||
GatewayOnLink=true
|
||||
|
@ -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
|
@ -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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user