diff --git a/src/network/meson.build b/src/network/meson.build index 5f06948752..2708b3a5bf 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -67,8 +67,10 @@ sources = files( 'networkd-nexthop.c', 'networkd-queue.c', 'networkd-radv.c', - 'networkd-route-util.c', 'networkd-route.c', + 'networkd-route-metric.c', + 'networkd-route-nexthop.c', + 'networkd-route-util.c', 'networkd-routing-policy-rule.c', 'networkd-setlink.c', 'networkd-speed-meter.c', diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index ab11047f7e..fd1f26c798 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -192,23 +192,23 @@ Route.Metric, config_parse_route_priority, Route.Scope, config_parse_route_scope, 0, 0 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_route_boolean, 0, 0 -Route.GatewayOnlink, config_parse_route_boolean, 0, 0 +Route.GatewayOnLink, config_parse_route_gateway_onlink, 0, 0 +Route.GatewayOnlink, config_parse_route_gateway_onlink, 0, 0 Route.IPv6Preference, config_parse_ipv6_route_preference, 0, 0 Route.Protocol, config_parse_route_protocol, 0, 0 Route.Type, config_parse_route_type, 0, 0 -Route.TCPRetransmissionTimeoutSec, config_parse_route_tcp_rto, 0, 0 -Route.HopLimit, config_parse_route_hop_limit, 0, 0 -Route.InitialCongestionWindow, config_parse_route_tcp_window, 0, 0 -Route.InitialAdvertisedReceiveWindow, config_parse_route_tcp_window, 0, 0 -Route.TCPAdvertisedMaximumSegmentSize, config_parse_tcp_advmss, 0, 0 -Route.TCPCongestionControlAlgorithm, config_parse_tcp_congestion, 0, 0 -Route.QuickAck, config_parse_route_boolean, 0, 0 -Route.FastOpenNoCookie, config_parse_route_boolean, 0, 0 -Route.TTLPropagate, config_parse_warn_compat, DISABLED_LEGACY, 0 Route.MultiPathRoute, config_parse_multipath_route, 0, 0 Route.NextHop, config_parse_route_nexthop, 0, 0 +Route.MTUBytes, config_parse_route_metric_mtu, RTAX_MTU, 0 +Route.TCPAdvertisedMaximumSegmentSize, config_parse_route_metric_advmss, RTAX_ADVMSS, 0 +Route.HopLimit, config_parse_route_metric_hop_limit, RTAX_HOPLIMIT, 0 +Route.InitialCongestionWindow, config_parse_route_metric_tcp_window, RTAX_INITCWND, 0 +Route.TCPRetransmissionTimeoutSec, config_parse_route_metric_tcp_rto, RTAX_RTO_MIN, 0 +Route.InitialAdvertisedReceiveWindow, config_parse_route_metric_tcp_window, RTAX_INITRWND, 0 +Route.QuickAck, config_parse_route_metric_boolean, RTAX_QUICKACK, 0 +Route.TCPCongestionControlAlgorithm, config_parse_route_metric_tcp_congestion, RTAX_CC_ALGO, 0 +Route.FastOpenNoCookie, config_parse_route_metric_boolean, RTAX_FASTOPEN_NO_COOKIE, 0 +Route.TTLPropagate, config_parse_warn_compat, DISABLED_LEGACY, 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 diff --git a/src/network/networkd-route-metric.c b/src/network/networkd-route-metric.c new file mode 100644 index 0000000000..a0fb40fd26 --- /dev/null +++ b/src/network/networkd-route-metric.c @@ -0,0 +1,384 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "networkd-route.h" +#include "networkd-route-metric.h" +#include "parse-util.h" +#include "string-util.h" + +int config_parse_route_metric_mtu( + 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) { + + Network *network = userdata; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, AF_UNSPEC, rvalue, &route->mtu, userdata); + if (r <= 0) + return r; + + TAKE_PTR(route); + return 0; +} + +int config_parse_route_metric_advmss( + 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_(route_free_or_set_invalidp) Route *route = NULL; + Network *network = userdata; + uint64_t u; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + if (isempty(rvalue)) { + route->advmss = 0; + TAKE_PTR(route); + return 0; + } + + r = parse_size(rvalue, 1024, &u); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Could not parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (u == 0 || u > UINT32_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + route->advmss = u; + + TAKE_PTR(route); + return 0; +} + +int config_parse_route_metric_hop_limit( + 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_(route_free_or_set_invalidp) Route *route = NULL; + Network *network = userdata; + uint32_t k; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + if (isempty(rvalue)) { + route->hop_limit = 0; + TAKE_PTR(route); + return 0; + } + + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Could not parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + if (k == 0 || k > 255) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + route->hop_limit = k; + + TAKE_PTR(route); + return 0; +} + +int config_parse_tcp_window( + 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) { + + uint32_t *window = ASSERT_PTR(data); + uint32_t k; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Could not parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + if (k == 0 || k >= 1024) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + *window = k; + return 0; +} + +int config_parse_route_metric_tcp_window( + 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_(route_free_or_set_invalidp) Route *route = NULL; + Network *network = userdata; + uint32_t *d; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + if (streq(lvalue, "InitialCongestionWindow")) + d = &route->initcwnd; + else if (streq(lvalue, "InitialAdvertisedReceiveWindow")) + d = &route->initrwnd; + else + assert_not_reached(); + + r = config_parse_tcp_window(unit, filename, line, section, section_line, lvalue, ltype, rvalue, d, userdata); + if (r < 0) + return r; + + TAKE_PTR(route); + return 0; +} + +int config_parse_route_metric_tcp_rto( + 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) { + + Network *network = userdata; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; + usec_t usec; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (!timestamp_is_set(usec) || + DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + route->tcp_rto_usec = usec; + + TAKE_PTR(route); + return 0; +} + +int config_parse_route_metric_boolean( + 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) { + + Network *network = userdata; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Could not parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (streq(lvalue, "QuickAck")) + route->quickack = r; + else if (streq(lvalue, "FastOpenNoCookie")) + route->fast_open_no_cookie = r; + else + assert_not_reached(); + + TAKE_PTR(route); + return 0; +} + +int config_parse_route_metric_tcp_congestion( + 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) { + + Network *network = userdata; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + r = config_parse_string(unit, filename, line, section, section_line, lvalue, 0, + rvalue, &route->tcp_congestion_control_algo, userdata); + if (r < 0) + return r; + + TAKE_PTR(route); + return 0; +} diff --git a/src/network/networkd-route-metric.h b/src/network/networkd-route-metric.h new file mode 100644 index 0000000000..ba8b7bb6c8 --- /dev/null +++ b/src/network/networkd-route-metric.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "conf-parser.h" + +CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_mtu); +CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_advmss); +CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_hop_limit); +CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_tcp_window); +CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_tcp_rto); +CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_boolean); +CONFIG_PARSER_PROTOTYPE(config_parse_route_metric_tcp_congestion); +CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window); diff --git a/src/network/networkd-route-nexthop.c b/src/network/networkd-route-nexthop.c new file mode 100644 index 0000000000..fbb8ee2d68 --- /dev/null +++ b/src/network/networkd-route-nexthop.c @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "alloc-util.h" +#include "extract-word.h" +#include "netlink-util.h" +#include "networkd-route.h" +#include "networkd-route-nexthop.h" +#include "parse-util.h" +#include "string-util.h" + +int config_parse_route_nexthop( + 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) { + + Network *network = userdata; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; + uint32_t id; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + if (isempty(rvalue)) { + route->nexthop_id = 0; + TAKE_PTR(route); + return 0; + } + + r = safe_atou32(rvalue, &id); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue); + return 0; + } + if (id == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue); + return 0; + } + + route->nexthop_id = id; + TAKE_PTR(route); + return 0; +} + +int config_parse_multipath_route( + 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_(multipath_route_freep) MultipathRoute *m = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; + _cleanup_free_ char *word = NULL; + Network *network = userdata; + union in_addr_union a; + int family, r; + const char *p; + char *dev; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &route); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + if (isempty(rvalue)) { + route->multipath_routes = ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free); + TAKE_PTR(route); + return 0; + } + + m = new0(MultipathRoute, 1); + if (!m) + return log_oom(); + + p = rvalue; + r = extract_first_word(&p, &word, NULL, 0); + if (r == -ENOMEM) + return log_oom(); + if (r <= 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid multipath route option, ignoring assignment: %s", rvalue); + return 0; + } + + dev = strchr(word, '@'); + if (dev) { + *dev++ = '\0'; + + r = parse_ifindex(dev); + if (r > 0) + m->ifindex = r; + else { + if (!ifname_valid_full(dev, IFNAME_VALID_ALTERNATIVE)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid interface name '%s' in %s=, ignoring: %s", dev, lvalue, rvalue); + return 0; + } + + m->ifname = strdup(dev); + if (!m->ifname) + return log_oom(); + } + } + + r = in_addr_from_string_auto(word, &family, &a); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue); + return 0; + } + m->gateway.address = a; + m->gateway.family = family; + + if (!isempty(p)) { + r = safe_atou32(p, &m->weight); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid multipath route weight, ignoring assignment: %s", p); + return 0; + } + /* ip command takes weight in the range 1…255, while kernel takes the value in the + * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip + * command uses, then networkd decreases by one and stores it to match the range which + * kernel uses. */ + if (m->weight == 0 || m->weight > 256) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid multipath route weight, ignoring assignment: %s", p); + return 0; + } + m->weight--; + } + + r = ordered_set_ensure_put(&route->multipath_routes, NULL, m); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to store multipath route, ignoring assignment: %m"); + return 0; + } + + TAKE_PTR(m); + TAKE_PTR(route); + return 0; +} diff --git a/src/network/networkd-route-nexthop.h b/src/network/networkd-route-nexthop.h new file mode 100644 index 0000000000..ae07696e5a --- /dev/null +++ b/src/network/networkd-route-nexthop.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "conf-parser.h" + +CONFIG_PARSER_PROTOTYPE(config_parse_route_nexthop); +CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route); diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index abaea4e6c3..b8f1041dbd 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -45,7 +45,7 @@ int route_new(Route **ret) { return 0; } -static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) { +int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) { _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(route_freep) Route *route = NULL; int r; @@ -1930,7 +1930,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma } int network_add_ipv4ll_route(Network *network) { - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; unsigned section_line; int r; @@ -1944,28 +1944,28 @@ int network_add_ipv4ll_route(Network *network) { return r; /* IPv4LLRoute= is in [Network] section. */ - r = route_new_static(network, network->filename, section_line, &n); + r = route_new_static(network, network->filename, section_line, &route); if (r < 0) return r; - r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst); + r = in_addr_from_string(AF_INET, "169.254.0.0", &route->dst); if (r < 0) return r; - n->family = AF_INET; - n->dst_prefixlen = 16; - n->scope = RT_SCOPE_LINK; - n->scope_set = true; - n->table_set = true; - n->priority = IPV4LL_ROUTE_METRIC; - n->protocol = RTPROT_STATIC; + route->family = AF_INET; + route->dst_prefixlen = 16; + route->scope = RT_SCOPE_LINK; + route->scope_set = true; + route->table_set = true; + route->priority = IPV4LL_ROUTE_METRIC; + route->protocol = RTPROT_STATIC; - TAKE_PTR(n); + TAKE_PTR(route); return 0; } int network_add_default_route_on_device(Network *network) { - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; unsigned section_line; int r; @@ -1979,16 +1979,16 @@ int network_add_default_route_on_device(Network *network) { return r; /* DefaultRouteOnDevice= is in [Network] section. */ - r = route_new_static(network, network->filename, section_line, &n); + r = route_new_static(network, network->filename, section_line, &route); if (r < 0) return r; - n->family = AF_INET; - n->scope = RT_SCOPE_LINK; - n->scope_set = true; - n->protocol = RTPROT_STATIC; + route->family = AF_INET; + route->scope = RT_SCOPE_LINK; + route->scope_set = true; + route->protocol = RTPROT_STATIC; - TAKE_PTR(n); + TAKE_PTR(route); return 0; } @@ -2005,7 +2005,7 @@ int config_parse_gateway( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int r; assert(filename); @@ -2016,7 +2016,7 @@ int config_parse_gateway( if (streq(section, "Network")) { /* we are not in an Route section, so use line number instead */ - r = route_new_static(network, filename, line, &n); + r = route_new_static(network, filename, line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2025,7 +2025,7 @@ int config_parse_gateway( return 0; } } else { - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2035,43 +2035,43 @@ int config_parse_gateway( } if (isempty(rvalue)) { - n->gateway_from_dhcp_or_ra = false; - n->gw_family = AF_UNSPEC; - n->gw = IN_ADDR_NULL; - TAKE_PTR(n); + route->gateway_from_dhcp_or_ra = false; + route->gw_family = AF_UNSPEC; + route->gw = IN_ADDR_NULL; + TAKE_PTR(route); return 0; } if (streq(rvalue, "_dhcp")) { - n->gateway_from_dhcp_or_ra = true; - TAKE_PTR(n); + route->gateway_from_dhcp_or_ra = true; + TAKE_PTR(route); return 0; } if (streq(rvalue, "_dhcp4")) { - n->gw_family = AF_INET; - n->gateway_from_dhcp_or_ra = true; - TAKE_PTR(n); + route->gw_family = AF_INET; + route->gateway_from_dhcp_or_ra = true; + TAKE_PTR(route); return 0; } if (streq(rvalue, "_ipv6ra")) { - n->gw_family = AF_INET6; - n->gateway_from_dhcp_or_ra = true; - TAKE_PTR(n); + route->gw_family = AF_INET6; + route->gateway_from_dhcp_or_ra = true; + TAKE_PTR(route); return 0; } } - r = in_addr_from_string_auto(rvalue, &n->gw_family, &n->gw); + r = in_addr_from_string_auto(rvalue, &route->gw_family, &route->gw); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue); return 0; } - n->gateway_from_dhcp_or_ra = false; - TAKE_PTR(n); + route->gateway_from_dhcp_or_ra = false; + TAKE_PTR(route); return 0; } @@ -2088,7 +2088,7 @@ int config_parse_preferred_src( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int r; assert(filename); @@ -2097,7 +2097,7 @@ int config_parse_preferred_src( assert(rvalue); assert(data); - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2106,17 +2106,17 @@ int config_parse_preferred_src( return 0; } - if (n->family == AF_UNSPEC) - r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc); + if (route->family == AF_UNSPEC) + r = in_addr_from_string_auto(rvalue, &route->family, &route->prefsrc); else - r = in_addr_from_string(n->family, rvalue, &n->prefsrc); + r = in_addr_from_string(route->family, rvalue, &route->prefsrc); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue); return 0; } - TAKE_PTR(n); + TAKE_PTR(route); return 0; } @@ -2133,7 +2133,7 @@ int config_parse_destination( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; union in_addr_union *buffer; unsigned char *prefixlen; int r; @@ -2144,7 +2144,7 @@ int config_parse_destination( assert(rvalue); assert(data); - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2154,27 +2154,27 @@ int config_parse_destination( } if (streq(lvalue, "Destination")) { - buffer = &n->dst; - prefixlen = &n->dst_prefixlen; + buffer = &route->dst; + prefixlen = &route->dst_prefixlen; } else if (streq(lvalue, "Source")) { - buffer = &n->src; - prefixlen = &n->src_prefixlen; + buffer = &route->src; + prefixlen = &route->src_prefixlen; } else assert_not_reached(); - if (n->family == AF_UNSPEC) - r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen); + if (route->family == AF_UNSPEC) + r = in_addr_prefix_from_string_auto(rvalue, &route->family, buffer, prefixlen); else - r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen); + r = in_addr_prefix_from_string(rvalue, route->family, buffer, prefixlen); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue); return 0; } - (void) in_addr_mask(n->family, buffer, *prefixlen); + (void) in_addr_mask(route->family, buffer, *prefixlen); - TAKE_PTR(n); + TAKE_PTR(route); return 0; } @@ -2191,7 +2191,7 @@ int config_parse_route_priority( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int r; assert(filename); @@ -2200,7 +2200,7 @@ int config_parse_route_priority( assert(rvalue); assert(data); - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2209,15 +2209,15 @@ int config_parse_route_priority( return 0; } - r = safe_atou32(rvalue, &n->priority); + r = safe_atou32(rvalue, &route->priority); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue); return 0; } - n->priority_set = true; - TAKE_PTR(n); + route->priority_set = true; + TAKE_PTR(route); return 0; } @@ -2234,7 +2234,7 @@ int config_parse_route_scope( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int r; assert(filename); @@ -2243,7 +2243,7 @@ int config_parse_route_scope( assert(rvalue); assert(data); - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2258,62 +2258,9 @@ int config_parse_route_scope( return 0; } - n->scope = r; - n->scope_set = true; - TAKE_PTR(n); - return 0; -} - -int config_parse_route_nexthop( - 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) { - - Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; - uint32_t id; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - if (isempty(rvalue)) { - n->nexthop_id = 0; - TAKE_PTR(n); - return 0; - } - - r = safe_atou32(rvalue, &id); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue); - return 0; - } - if (id == 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue); - return 0; - } - - n->nexthop_id = id; - TAKE_PTR(n); + route->scope = r; + route->scope_set = true; + TAKE_PTR(route); return 0; } @@ -2329,7 +2276,7 @@ int config_parse_route_table( void *data, void *userdata) { - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; Network *network = userdata; int r; @@ -2339,7 +2286,7 @@ int config_parse_route_table( assert(rvalue); assert(data); - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2348,19 +2295,19 @@ int config_parse_route_table( return 0; } - r = manager_get_route_table_from_string(network->manager, rvalue, &n->table); + r = manager_get_route_table_from_string(network->manager, rvalue, &route->table); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Could not parse route table \"%s\", ignoring assignment: %m", rvalue); return 0; } - n->table_set = true; - TAKE_PTR(n); + route->table_set = true; + TAKE_PTR(route); return 0; } -int config_parse_route_boolean( +int config_parse_route_gateway_onlink( const char *unit, const char *filename, unsigned line, @@ -2373,7 +2320,7 @@ int config_parse_route_boolean( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int r; assert(filename); @@ -2382,7 +2329,7 @@ int config_parse_route_boolean( assert(rvalue); assert(data); - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2398,16 +2345,9 @@ int config_parse_route_boolean( return 0; } - if (STR_IN_SET(lvalue, "GatewayOnLink", "GatewayOnlink")) - n->gateway_onlink = r; - else if (streq(lvalue, "QuickAck")) - n->quickack = r; - else if (streq(lvalue, "FastOpenNoCookie")) - n->fast_open_no_cookie = r; - else - assert_not_reached(); + route->gateway_onlink = r; - TAKE_PTR(n); + TAKE_PTR(route); return 0; } @@ -2424,10 +2364,10 @@ int config_parse_ipv6_route_preference( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int r; - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2437,18 +2377,18 @@ int config_parse_ipv6_route_preference( } if (streq(rvalue, "low")) - n->pref = ICMPV6_ROUTER_PREF_LOW; + route->pref = ICMPV6_ROUTER_PREF_LOW; else if (streq(rvalue, "medium")) - n->pref = ICMPV6_ROUTER_PREF_MEDIUM; + route->pref = ICMPV6_ROUTER_PREF_MEDIUM; else if (streq(rvalue, "high")) - n->pref = ICMPV6_ROUTER_PREF_HIGH; + route->pref = ICMPV6_ROUTER_PREF_HIGH; else { log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route preference: %s", rvalue); return 0; } - n->pref_set = true; - TAKE_PTR(n); + route->pref_set = true; + TAKE_PTR(route); return 0; } @@ -2465,10 +2405,10 @@ int config_parse_route_protocol( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int r; - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2484,9 +2424,9 @@ int config_parse_route_protocol( return 0; } - n->protocol = r; + route->protocol = r; - TAKE_PTR(n); + TAKE_PTR(route); return 0; } @@ -2503,10 +2443,10 @@ int config_parse_route_type( void *userdata) { Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + _cleanup_(route_free_or_set_invalidp) Route *route = NULL; int t, r; - r = route_new_static(network, filename, section_line, &n); + r = route_new_static(network, filename, section_line, &route); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -2522,465 +2462,9 @@ int config_parse_route_type( return 0; } - n->type = (unsigned char) t; + route->type = (unsigned char) t; - TAKE_PTR(n); - return 0; -} - -int config_parse_route_hop_limit( - 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_(route_free_or_set_invalidp) Route *n = NULL; - Network *network = userdata; - uint32_t k; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - if (isempty(rvalue)) { - n->hop_limit = 0; - TAKE_PTR(n); - return 0; - } - - r = safe_atou32(rvalue, &k); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Could not parse per route hop limit, ignoring assignment: %s", rvalue); - return 0; - } - if (k > 255) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Specified per route hop limit \"%s\" is too large, ignoring assignment: %m", rvalue); - return 0; - } - if (k == 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Invalid per route hop limit \"%s\", ignoring assignment: %m", rvalue); - return 0; - } - - n->hop_limit = k; - - TAKE_PTR(n); - return 0; -} - -int config_parse_tcp_congestion( - 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) { - - Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, - rvalue, &n->tcp_congestion_control_algo, userdata); - if (r < 0) - return r; - - TAKE_PTR(n); - return 0; -} - -int config_parse_tcp_advmss( - 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_(route_free_or_set_invalidp) Route *n = NULL; - Network *network = userdata; - uint64_t u; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - if (isempty(rvalue)) { - n->advmss = 0; - TAKE_PTR(n); - return 0; - } - - r = parse_size(rvalue, 1024, &u); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue); - return 0; - } - - if (u == 0 || u > UINT32_MAX) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue); - return 0; - } - - n->advmss = u; - - TAKE_PTR(n); - return 0; -} - -int config_parse_tcp_window( - 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) { - - uint32_t *window = ASSERT_PTR(data); - uint32_t k; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = safe_atou32(rvalue, &k); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue); - return 0; - } - if (k >= 1024) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue); - return 0; - } - if (k == 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue); - return 0; - } - - *window = k; - return 0; -} - -int config_parse_route_tcp_window( - 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_(route_free_or_set_invalidp) Route *n = NULL; - Network *network = userdata; - uint32_t *d; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - if (streq(lvalue, "InitialCongestionWindow")) - d = &n->initcwnd; - else if (streq(lvalue, "InitialAdvertisedReceiveWindow")) - d = &n->initrwnd; - else - assert_not_reached(); - - r = config_parse_tcp_window(unit, filename, line, section, section_line, lvalue, ltype, rvalue, d, userdata); - if (r < 0) - return r; - - TAKE_PTR(n); - return 0; -} - -int config_parse_route_mtu( - 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) { - - Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata); - if (r <= 0) - return r; - - TAKE_PTR(n); - return 0; -} - -int config_parse_route_tcp_rto( - 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) { - - Network *network = userdata; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; - usec_t usec; - int r; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - r = parse_sec(rvalue, &usec); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse route TCP retransmission timeout (RTO), ignoring assignment: %s", rvalue); - return 0; - } - - if (!timestamp_is_set(usec) || - DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Route TCP retransmission timeout (RTO) must be in the range 0…%"PRIu32"ms, ignoring assignment: %s", UINT32_MAX, rvalue); - return 0; - } - - n->tcp_rto_usec = usec; - - TAKE_PTR(n); - return 0; -} - -int config_parse_multipath_route( - 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_(multipath_route_freep) MultipathRoute *m = NULL; - _cleanup_(route_free_or_set_invalidp) Route *n = NULL; - _cleanup_free_ char *word = NULL; - Network *network = userdata; - union in_addr_union a; - int family, r; - const char *p; - char *dev; - - assert(filename); - assert(section); - assert(lvalue); - assert(rvalue); - assert(data); - - r = route_new_static(network, filename, section_line, &n); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to allocate route, ignoring assignment: %m"); - return 0; - } - - if (isempty(rvalue)) { - n->multipath_routes = ordered_set_free_with_destructor(n->multipath_routes, multipath_route_free); - return 0; - } - - m = new0(MultipathRoute, 1); - if (!m) - return log_oom(); - - p = rvalue; - r = extract_first_word(&p, &word, NULL, 0); - if (r == -ENOMEM) - return log_oom(); - if (r <= 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Invalid multipath route option, ignoring assignment: %s", rvalue); - return 0; - } - - dev = strchr(word, '@'); - if (dev) { - *dev++ = '\0'; - - r = parse_ifindex(dev); - if (r > 0) - m->ifindex = r; - else { - if (!ifname_valid_full(dev, IFNAME_VALID_ALTERNATIVE)) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Invalid interface name '%s' in %s=, ignoring: %s", dev, lvalue, rvalue); - return 0; - } - - m->ifname = strdup(dev); - if (!m->ifname) - return log_oom(); - } - } - - r = in_addr_from_string_auto(word, &family, &a); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue); - return 0; - } - m->gateway.address = a; - m->gateway.family = family; - - if (!isempty(p)) { - r = safe_atou32(p, &m->weight); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Invalid multipath route weight, ignoring assignment: %s", p); - return 0; - } - /* ip command takes weight in the range 1…255, while kernel takes the value in the - * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip - * command uses, then networkd decreases by one and stores it to match the range which - * kernel uses. */ - if (m->weight == 0 || m->weight > 256) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Invalid multipath route weight, ignoring assignment: %s", p); - return 0; - } - m->weight--; - } - - r = ordered_set_ensure_put(&n->multipath_routes, NULL, m); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to store multipath route, ignoring assignment: %m"); - return 0; - } - - TAKE_PTR(m); - TAKE_PTR(n); + TAKE_PTR(route); return 0; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 2e7f629063..5075398967 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -9,6 +9,8 @@ #include "conf-parser.h" #include "in-addr-util.h" #include "networkd-link.h" +#include "networkd-route-metric.h" +#include "networkd-route-nexthop.h" #include "networkd-util.h" typedef struct Manager Manager; @@ -80,6 +82,7 @@ struct Route { extern const struct hash_ops route_hash_ops; int route_new(Route **ret); +int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret); Route *route_free(Route *route); DEFINE_SECTION_CLEANUP_FUNCTIONS(Route, route_free); int route_dup(const Route *src, Route **ret); @@ -119,16 +122,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_destination); CONFIG_PARSER_PROTOTYPE(config_parse_route_priority); CONFIG_PARSER_PROTOTYPE(config_parse_route_scope); CONFIG_PARSER_PROTOTYPE(config_parse_route_table); -CONFIG_PARSER_PROTOTYPE(config_parse_route_boolean); +CONFIG_PARSER_PROTOTYPE(config_parse_route_gateway_onlink); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_route_preference); CONFIG_PARSER_PROTOTYPE(config_parse_route_protocol); CONFIG_PARSER_PROTOTYPE(config_parse_route_type); -CONFIG_PARSER_PROTOTYPE(config_parse_route_tcp_window); -CONFIG_PARSER_PROTOTYPE(config_parse_route_hop_limit); -CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window); -CONFIG_PARSER_PROTOTYPE(config_parse_route_tcp_rto); -CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu); -CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route); -CONFIG_PARSER_PROTOTYPE(config_parse_tcp_congestion); -CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss); -CONFIG_PARSER_PROTOTYPE(config_parse_route_nexthop);