]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-route.c
sd-netlink: add destroy_callback argument to sd_netlink_call_async()
[thirdparty/systemd.git] / src / network / networkd-route.c
index 163146da60105677fd4ae38222acb3cdaf6ac2a6..9ebbc4355e8f8a5aeab36fd0686c81c83f556259 100644 (file)
@@ -1,21 +1,4 @@
-/***
-  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>
 
@@ -61,7 +44,7 @@ static unsigned routes_max(void) {
 }
 
 int route_new(Route **ret) {
-        _cleanup_route_free_ Route *route = NULL;
+        _cleanup_(route_freep) Route *route = NULL;
 
         route = new0(Route, 1);
         if (!route)
@@ -73,16 +56,16 @@ int route_new(Route **ret) {
         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);
@@ -96,8 +79,7 @@ int route_new_static(Network *network, const char *filename, unsigned section_li
 
                 route = hashmap_get(network->routes_by_section, n);
                 if (route) {
-                        *ret = route;
-                        route = NULL;
+                        *ret = TAKE_PTR(route);
 
                         return 0;
                 }
@@ -113,8 +95,7 @@ int route_new_static(Network *network, const char *filename, unsigned section_li
         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)
@@ -125,8 +106,7 @@ int route_new_static(Network *network, const char *filename, unsigned section_li
         LIST_PREPEND(routes, network->static_routes, route);
         network->n_static_routes++;
 
-        *ret = route;
-        route = NULL;
+        *ret = TAKE_PTR(route);
 
         return 0;
 }
@@ -184,34 +164,30 @@ static void route_hash_func(const void *b, struct siphash *state) {
 
 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:
@@ -276,7 +252,7 @@ static int route_add_internal(
                 uint32_t table,
                 Route **ret) {
 
-        _cleanup_route_free_ Route *route = NULL;
+        _cleanup_(route_freep) Route *route = NULL;
         int r;
 
         assert(link);
@@ -325,8 +301,7 @@ int route_add_foreign(
         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,
@@ -367,33 +342,30 @@ int route_add(
         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;
 
@@ -467,7 +439,7 @@ int route_remove(Route *route, Link *link,
                         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");
 
@@ -617,6 +589,13 @@ int route_configure(
         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");
@@ -637,11 +616,29 @@ int route_configure(
                         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");
 
@@ -656,7 +653,7 @@ int route_configure(
         /* 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)
@@ -664,13 +661,13 @@ int route_configure(
         }
 
         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,
@@ -682,7 +679,7 @@ int config_parse_gateway(const char *unit,
                 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;
 
@@ -710,12 +707,13 @@ int config_parse_gateway(const char *unit,
 
         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,
@@ -727,7 +725,7 @@ int config_parse_preferred_src(const char *unit,
                 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;
 
@@ -750,12 +748,13 @@ int config_parse_preferred_src(const char *unit,
 
         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,
@@ -767,7 +766,7 @@ int config_parse_destination(const char *unit,
                 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;
@@ -805,24 +804,24 @@ int config_parse_destination(const char *unit,
         } 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);
@@ -835,31 +834,31 @@ int config_parse_route_priority(const char *unit,
         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);
@@ -883,24 +882,24 @@ int config_parse_route_scope(const char *unit,
                 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);
@@ -913,32 +912,31 @@ int config_parse_route_table(const char *unit,
         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);
@@ -959,23 +957,24 @@ int config_parse_gateway_onlink(const char *unit,
         }
 
         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);
@@ -993,23 +992,24 @@ int config_parse_ipv6_route_preference(const char *unit,
                 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);
@@ -1030,23 +1030,24 @@ int config_parse_route_protocol(const char *unit,
                 }
         }
 
-        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);
@@ -1066,7 +1067,124 @@ int config_parse_route_type(const char *unit,
                 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;
 }