#include "alloc-util.h"
#include "extract-word.h"
#include "netlink-util.h"
+#include "networkd-network.h"
#include "networkd-route.h"
#include "networkd-route-nexthop.h"
+#include "networkd-route-util.h"
#include "parse-util.h"
#include "string-util.h"
+int route_section_verify_nexthops(Route *route) {
+ assert(route);
+ assert(route->section);
+ assert(route->network);
+
+ if (route->gateway_from_dhcp_or_ra) {
+ if (route->gw_family == AF_UNSPEC)
+ /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
+ switch (route->family) {
+ case AF_UNSPEC:
+ log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
+ "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
+ route->section->filename, route->section->line);
+
+ route->gw_family = route->family = AF_INET;
+ break;
+ case AF_INET:
+ case AF_INET6:
+ log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
+ "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
+ route->section->filename, route->section->line, route->family == AF_INET ? "_dhcp4" : "_ipv6ra");
+
+ route->gw_family = route->family;
+ break;
+ default:
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: Invalid route family. Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+ }
+
+ if (route->gw_family == AF_INET && !FLAGS_SET(route->network->dhcp, ADDRESS_FAMILY_IPV4))
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+
+ if (route->gw_family == AF_INET6 && !route->network->ipv6_accept_ra)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+ }
+
+ /* When only Gateway= is specified, assume the route family based on the Gateway address. */
+ if (route->family == AF_UNSPEC)
+ route->family = route->gw_family;
+
+ if (route->family == AF_UNSPEC) {
+ assert(route->section);
+
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: Route section without Gateway=, Destination=, Source=, "
+ "or PreferredSource= field configured. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+ }
+
+ if (route->gateway_onlink < 0 && in_addr_is_set(route->gw_family, &route->gw) &&
+ ordered_hashmap_isempty(route->network->addresses_by_section)) {
+ /* If no address is configured, in most cases the gateway cannot be reachable.
+ * TODO: we may need to improve the condition above. */
+ log_warning("%s: Gateway= without static address configured. "
+ "Enabling GatewayOnLink= option.",
+ route->section->filename);
+ route->gateway_onlink = true;
+ }
+
+ if (route->gateway_onlink >= 0)
+ SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
+
+ if (route->family == AF_INET6) {
+ if (route->gw_family == AF_INET)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: IPv4 gateway is configured for IPv6 route. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+
+ MultipathRoute *m;
+ ORDERED_SET_FOREACH(m, route->multipath_routes)
+ if (m->gateway.family == AF_INET)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: IPv4 multipath route is specified for IPv6 route. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+ }
+
+ if (route->nexthop_id != 0 &&
+ (route->gateway_from_dhcp_or_ra ||
+ in_addr_is_set(route->gw_family, &route->gw) ||
+ !ordered_set_isempty(route->multipath_routes)))
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+
+ if (route_type_is_reject(route) &&
+ (route->gateway_from_dhcp_or_ra ||
+ in_addr_is_set(route->gw_family, &route->gw) ||
+ !ordered_set_isempty(route->multipath_routes)))
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: reject type route cannot be specified with Gateway= or MultiPathRoute=. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+
+ if ((route->gateway_from_dhcp_or_ra ||
+ in_addr_is_set(route->gw_family, &route->gw)) &&
+ !ordered_set_isempty(route->multipath_routes))
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: Gateway= cannot be specified with MultiPathRoute=. "
+ "Ignoring [Route] section from line %u.",
+ route->section->filename, route->section->line);
+
+ return 0;
+}
+
int config_parse_gateway(
const char *unit,
const char *filename,
return 0;
}
-static int route_section_verify(Route *route, Network *network) {
+static int route_section_verify(Route *route) {
+ int r;
+
+ assert(route);
+ assert(route->section);
+ assert(route->network);
+
if (section_is_invalid(route->section))
return -EINVAL;
/* Currently, we do not support static route with finite lifetime. */
assert(route->lifetime_usec == USEC_INFINITY);
- if (route->gateway_from_dhcp_or_ra) {
- if (route->gw_family == AF_UNSPEC) {
- /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
- switch (route->family) {
- case AF_UNSPEC:
- log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
- "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
- route->section->filename, route->section->line);
- route->family = AF_INET;
- break;
- case AF_INET:
- case AF_INET6:
- log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
- "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
- route->section->filename, route->section->line, route->family == AF_INET ? "_dhcp4" : "_ipv6ra");
- break;
- default:
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: Invalid route family. Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
- }
- route->gw_family = route->family;
- }
-
- if (route->gw_family == AF_INET && !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4))
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
- "Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
-
- if (route->gw_family == AF_INET6 && !network->ipv6_accept_ra)
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
- "Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
- }
-
- /* When only Gateway= is specified, assume the route family based on the Gateway address. */
- if (route->family == AF_UNSPEC)
- route->family = route->gw_family;
-
- if (route->family == AF_UNSPEC) {
- assert(route->section);
-
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: Route section without Gateway=, Destination=, Source=, "
- "or PreferredSource= field configured. "
- "Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
- }
-
- if (route->family == AF_INET6 && route->gw_family == AF_INET)
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: IPv4 gateway is configured for IPv6 route. "
- "Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
+ r = route_section_verify_nexthops(route);
+ if (r < 0)
+ return r;
- if (!route->table_set && network->vrf) {
- route->table = VRF(network->vrf)->table;
+ /* table */
+ if (!route->table_set && route->network->vrf) {
+ route->table = VRF(route->network->vrf)->table;
route->table_set = true;
}
if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
route->table = RT_TABLE_LOCAL;
- if (!route->scope_set && route->family != AF_INET6) {
+ /* scope */
+ if (!route->scope_set && route->family == AF_INET) {
if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
route->scope = RT_SCOPE_HOST;
else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
route->scope = RT_SCOPE_LINK;
}
- if (route->scope != RT_SCOPE_UNIVERSE && route->family == AF_INET6) {
- log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
- route->scope = RT_SCOPE_UNIVERSE;
- }
-
- if (route->family == AF_INET6 && route->priority == 0)
- route->priority = IP6_RT_PRIO_USER;
-
- if (route->gateway_onlink < 0 && in_addr_is_set(route->gw_family, &route->gw) &&
- ordered_hashmap_isempty(network->addresses_by_section)) {
- /* If no address is configured, in most cases the gateway cannot be reachable.
- * TODO: we may need to improve the condition above. */
- log_warning("%s: Gateway= without static address configured. "
- "Enabling GatewayOnLink= option.",
- network->filename);
- route->gateway_onlink = true;
- }
-
- if (route->gateway_onlink >= 0)
- SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
-
+ /* IPv6 route */
if (route->family == AF_INET6) {
- MultipathRoute *m;
+ if (route->scope != RT_SCOPE_UNIVERSE) {
+ log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
+ route->scope = RT_SCOPE_UNIVERSE;
+ }
- ORDERED_SET_FOREACH(m, route->multipath_routes)
- if (m->gateway.family == AF_INET)
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: IPv4 multipath route is specified for IPv6 route. "
- "Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
- }
-
- if ((route->gateway_from_dhcp_or_ra ||
- in_addr_is_set(route->gw_family, &route->gw)) &&
- !ordered_set_isempty(route->multipath_routes))
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: Gateway= cannot be specified with MultiPathRoute=. "
- "Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
-
- if (route->nexthop_id > 0 &&
- (route->gateway_from_dhcp_or_ra ||
- in_addr_is_set(route->gw_family, &route->gw) ||
- !ordered_set_isempty(route->multipath_routes)))
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
- "Ignoring [Route] section from line %u.",
- route->section->filename, route->section->line);
+ if (route->priority == 0)
+ route->priority = IP6_RT_PRIO_USER;
+ }
return 0;
}
assert(network);
HASHMAP_FOREACH(route, network->routes_by_section)
- if (route_section_verify(route, network) < 0)
+ if (route_section_verify(route) < 0)
route_free(route);
}