-/***
- This file is part of systemd.
-
- Copyright 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+/* SPDX-License-Identifier: LGPL-2.1+ */
#include <linux/icmpv6.h>
}
int route_new(Route **ret) {
- _cleanup_route_free_ Route *route = NULL;
+ _cleanup_(route_freep) Route *route = NULL;
route = new0(Route, 1);
if (!route)
route->type = RTN_UNICAST;
route->table = RT_TABLE_MAIN;
route->lifetime = USEC_INFINITY;
+ route->quickack = -1;
- *ret = route;
- route = NULL;
+ *ret = TAKE_PTR(route);
return 0;
}
int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
- _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
- _cleanup_route_free_ Route *route = NULL;
+ _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(route_freep) Route *route = NULL;
int r;
assert(network);
route = hashmap_get(network->routes_by_section, n);
if (route) {
- *ret = route;
- route = NULL;
+ *ret = TAKE_PTR(route);
return 0;
}
route->protocol = RTPROT_STATIC;
if (filename) {
- route->section = n;
- n = NULL;
+ route->section = TAKE_PTR(n);
r = hashmap_put(network->routes_by_section, route->section, route);
if (r < 0)
LIST_PREPEND(routes, network->static_routes, route);
network->n_static_routes++;
- *ret = route;
- route = NULL;
+ *ret = TAKE_PTR(route);
return 0;
}
static int route_compare_func(const void *_a, const void *_b) {
const Route *a = _a, *b = _b;
+ int r;
- if (a->family < b->family)
- return -1;
- if (a->family > b->family)
- return 1;
+ r = CMP(a->family, b->family);
+ if (r != 0)
+ return r;
switch (a->family) {
case AF_INET:
case AF_INET6:
- if (a->dst_prefixlen < b->dst_prefixlen)
- return -1;
- if (a->dst_prefixlen > b->dst_prefixlen)
- return 1;
-
- if (a->tos < b->tos)
- return -1;
- if (a->tos > b->tos)
- return 1;
-
- if (a->priority < b->priority)
- return -1;
- if (a->priority > b->priority)
- return 1;
-
- if (a->table < b->table)
- return -1;
- if (a->table > b->table)
- return 1;
+ r = CMP(a->dst_prefixlen, b->dst_prefixlen);
+ if (r != 0)
+ return r;
+
+ r = CMP(a->tos, b->tos);
+ if (r != 0)
+ return r;
+
+ r = CMP(a->priority, b->priority);
+ if (r != 0)
+ return r;
+
+ r = CMP(a->table, b->table);
+ if (r != 0)
+ return r;
return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
default:
uint32_t table,
Route **ret) {
- _cleanup_route_free_ Route *route = NULL;
+ _cleanup_(route_freep) Route *route = NULL;
int r;
assert(link);
return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
}
-int route_add(
- Link *link,
+int route_add(Link *link,
int family,
const union in_addr_union *dst,
unsigned char dst_prefixlen,
return 0;
}
-int route_update(Route *route,
- const union in_addr_union *src,
- unsigned char src_prefixlen,
- const union in_addr_union *gw,
- const union in_addr_union *prefsrc,
- unsigned char scope,
- unsigned char protocol,
- unsigned char type) {
+void route_update(Route *route,
+ const union in_addr_union *src,
+ unsigned char src_prefixlen,
+ const union in_addr_union *gw,
+ const union in_addr_union *prefsrc,
+ unsigned char scope,
+ unsigned char protocol,
+ unsigned char type) {
assert(route);
- assert(src);
- assert(gw);
- assert(prefsrc);
+ assert(src || src_prefixlen == 0);
- route->src = *src;
+ route->src = src ? *src : (union in_addr_union) {};
route->src_prefixlen = src_prefixlen;
- route->gw = *gw;
- route->prefsrc = *prefsrc;
+ route->gw = gw ? *gw : (union in_addr_union) {};
+ route->prefsrc = prefsrc ? *prefsrc : (union in_addr_union) {};
route->scope = scope;
route->protocol = protocol;
route->type = type;
-
- return 0;
}
int route_remove(Route *route, Link *link,
- sd_netlink_message_handler_t callback) {
+ sd_netlink_message_handler_t callback) {
+
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
}
- r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+ r = sd_netlink_call_async(link->manager->rtnl, req, callback, NULL, link, 0, NULL);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
if (r < 0)
return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
+ if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
+ r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
+ DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_EXPIRES attribute: %m");
+ }
+
r = sd_rtnl_message_route_set_type(req, route->type);
if (r < 0)
return log_error_errno(r, "Could not set route type: %m");
return log_error_errno(r, "Could not append RTAX_MTU attribute: %m");
}
+ if (route->initcwnd > 0) {
+ r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTAX_INITCWND attribute: %m");
+ }
+
+ if (route->initrwnd > 0) {
+ r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTAX_INITRWND attribute: %m");
+ }
+
+ if (route->quickack != -1) {
+ r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTAX_QUICKACK attribute: %m");
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
- r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+ r = sd_netlink_call_async(link->manager->rtnl, req, callback, NULL, link, 0, NULL);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
/* TODO: drop expiration handling once it can be pushed into the kernel */
route->lifetime = lifetime;
- if (route->lifetime != USEC_INFINITY) {
+ if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
route->lifetime, 0, route_expire_handler, route);
if (r < 0)
}
sd_event_source_unref(route->expire);
- route->expire = expire;
- expire = NULL;
+ route->expire = TAKE_PTR(expire);
return 0;
}
-int config_parse_gateway(const char *unit,
+int config_parse_gateway(
+ const char *unit,
const char *filename,
unsigned line,
const char *section,
void *userdata) {
Network *network = userdata;
- _cleanup_route_free_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
union in_addr_union buffer;
int r, f;
n->family = f;
n->gw = buffer;
- n = NULL;
+ TAKE_PTR(n);
return 0;
}
-int config_parse_preferred_src(const char *unit,
+int config_parse_preferred_src(
+ const char *unit,
const char *filename,
unsigned line,
const char *section,
void *userdata) {
Network *network = userdata;
- _cleanup_route_free_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
union in_addr_union buffer;
int r, f;
n->family = f;
n->prefsrc = buffer;
- n = NULL;
+ TAKE_PTR(n);
return 0;
}
-int config_parse_destination(const char *unit,
+int config_parse_destination(
+ const char *unit,
const char *filename,
unsigned line,
const char *section,
void *userdata) {
Network *network = userdata;
- _cleanup_route_free_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
union in_addr_union buffer;
unsigned char prefixlen;
int r;
} else
assert_not_reached(lvalue);
- n = NULL;
-
+ TAKE_PTR(n);
return 0;
}
-int config_parse_route_priority(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) {
+int config_parse_route_priority(
+ 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_ Route *n = NULL;
- uint32_t k;
+ _cleanup_(route_freep) Route *n = NULL;
int r;
assert(filename);
if (r < 0)
return r;
- r = safe_atou32(rvalue, &k);
+ r = safe_atou32(rvalue, &n->priority);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
- n->priority = k;
- n = NULL;
-
+ TAKE_PTR(n);
return 0;
}
-int config_parse_route_scope(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) {
+int config_parse_route_scope(
+ 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_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
int r;
assert(filename);
return 0;
}
- n = NULL;
-
+ TAKE_PTR(n);
return 0;
}
-int config_parse_route_table(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_ Route *n = NULL;
+int config_parse_route_table(
+ 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_freep) Route *n = NULL;
Network *network = userdata;
- uint32_t k;
int r;
assert(filename);
if (r < 0)
return r;
- r = safe_atou32(rvalue, &k);
+ r = safe_atou32(rvalue, &n->table);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
- n->table = k;
-
- n = NULL;
-
+ TAKE_PTR(n);
return 0;
}
-int config_parse_gateway_onlink(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) {
+int config_parse_gateway_onlink(
+ 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_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
int r;
assert(filename);
}
SET_FLAG(n->flags, RTNH_F_ONLINK, r);
- n = NULL;
-
+ TAKE_PTR(n);
return 0;
}
-int config_parse_ipv6_route_preference(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) {
+int config_parse_ipv6_route_preference(
+ 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_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
int r;
r = route_new_static(network, filename, section_line, &n);
return 0;
}
- n = NULL;
-
+ TAKE_PTR(n);
return 0;
}
-int config_parse_route_protocol(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) {
+int config_parse_route_protocol(
+ 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_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
int r;
r = route_new_static(network, filename, section_line, &n);
}
}
- n = NULL;
-
+ TAKE_PTR(n);
return 0;
}
-int config_parse_route_type(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) {
+int config_parse_route_type(
+ 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_ Route *n = NULL;
+ _cleanup_(route_freep) Route *n = NULL;
int r;
r = route_new_static(network, filename, section_line, &n);
return 0;
}
- n = NULL;
+ 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) {
+
+ _cleanup_(route_freep) Route *n = NULL;
+ Network *network = userdata;
+ uint64_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 < 0)
+ return r;
+
+ r = parse_size(rvalue, 1024, &k);
+ if (r < 0 || k > UINT32_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Could not parse TCP %s \"%s\" bytes, ignoring assignment: %m", rvalue, lvalue);
+ return 0;
+ }
+
+ if (streq(lvalue, "InitialCongestionWindow"))
+ 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;
+ }
+
+ TAKE_PTR(n);
+ return 0;
+}
+
+int config_parse_quickack(
+ 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_freep) Route *n = NULL;
+ Network *network = userdata;
+ int k, r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = route_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ k = parse_boolean(rvalue);
+ if (k < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse TCP quickack, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ n->quickack = !!k;
+ 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_freep) 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 < 0)
+ return r;
+
+ 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;
}