]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/route-nexthop: split out netlink message handling for route nexthops
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 9 Jan 2024 06:04:04 +0000 (15:04 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 13 Jan 2024 21:04:23 +0000 (06:04 +0900)
No functional change, just refactoring and preparation for later
commits.

src/network/networkd-route-nexthop.c
src/network/networkd-route-nexthop.h
src/network/networkd-route.c

index a8fddeb6c0462c072cc7fd4600e86ef98af1467b..bccb73684c283ad86b569ed8c7697b197a1b81f1 100644 (file)
 #include "parse-util.h"
 #include "string-util.h"
 
+static int append_nexthop_one(Link *link, const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
+        struct rtnexthop *rtnh;
+        struct rtattr *new_rta;
+        int r;
+
+        assert(route);
+        assert(IN_SET(route->family, AF_INET, AF_INET6));
+        assert(m);
+        assert(rta);
+        assert(*rta);
+        assert(m->ifindex > 0 || link);
+
+        new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
+        if (!new_rta)
+                return -ENOMEM;
+        *rta = new_rta;
+
+        rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
+        *rtnh = (struct rtnexthop) {
+                .rtnh_len = sizeof(*rtnh),
+                .rtnh_ifindex = m->ifindex > 0 ? m->ifindex : link->ifindex,
+                .rtnh_hops = m->weight,
+        };
+
+        (*rta)->rta_len += sizeof(struct rtnexthop);
+
+        if (m->gateway.family == route->family) {
+                r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
+                if (r < 0)
+                        goto clear;
+
+                rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
+                rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
+
+        } else if (m->gateway.family == AF_INET6) {
+                assert(route->family == AF_INET);
+
+                r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, sizeof(RouteVia));
+                if (r < 0)
+                        goto clear;
+
+                rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
+                rtnh->rtnh_len += RTA_SPACE(sizeof(RouteVia));
+
+        } else if (m->gateway.family == AF_INET)
+                assert_not_reached();
+
+        return 0;
+
+clear:
+        (*rta)->rta_len -= sizeof(struct rtnexthop);
+        return r;
+}
+
+static int netlink_message_append_multipath_route(Link *link, const Route *route, sd_netlink_message *message) {
+        _cleanup_free_ struct rtattr *rta = NULL;
+        size_t offset;
+        int r;
+
+        assert(route);
+        assert(message);
+
+        if (ordered_set_isempty(route->multipath_routes))
+                return 0;
+
+        rta = new(struct rtattr, 1);
+        if (!rta)
+                return -ENOMEM;
+
+        *rta = (struct rtattr) {
+                .rta_type = RTA_MULTIPATH,
+                .rta_len = RTA_LENGTH(0),
+        };
+        offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
+
+        MultipathRoute *m;
+        ORDERED_SET_FOREACH(m, route->multipath_routes) {
+                struct rtnexthop *rtnh;
+
+                r = append_nexthop_one(link, route, m, &rta, offset);
+                if (r < 0)
+                        return r;
+
+                rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
+                offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
+        }
+
+        return sd_netlink_message_append_data(message, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
+}
+
+int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlink_message *message) {
+        int r;
+
+        assert(route);
+        assert(IN_SET(route->family, AF_INET, AF_INET6));
+        assert(message);
+
+        if (route->nexthop_id != 0)
+                return sd_netlink_message_append_u32(message, RTA_NH_ID, route->nexthop_id);
+
+        if (route_type_is_reject(route))
+                return 0;
+
+        if (ordered_set_isempty(route->multipath_routes)) {
+
+                if (in_addr_is_set(route->gw_family, &route->gw)) {
+                        if (route->gw_family == route->family)
+                                r = netlink_message_append_in_addr_union(message, RTA_GATEWAY, route->gw_family, &route->gw);
+                        else {
+                                assert(route->family == AF_INET);
+                                r = sd_netlink_message_append_data(message, RTA_VIA,
+                                                                   &(const RouteVia) {
+                                                                           .family = route->gw_family,
+                                                                           .address = route->gw,
+                                                                   }, sizeof(RouteVia));
+                        }
+                        if (r < 0)
+                                return r;
+                }
+
+                assert(link);
+                return sd_netlink_message_append_u32(message, RTA_OIF, link->ifindex);
+        }
+
+        return netlink_message_append_multipath_route(link, route, message);
+}
+
+int route_nexthops_read_netlink_message(Route *route, sd_netlink_message *message) {
+        int r;
+
+        assert(route);
+        assert(message);
+
+        r = sd_netlink_message_read_u32(message, RTA_NH_ID, &route->nexthop_id);
+        if (r < 0 && r != -ENODATA)
+                return log_warning_errno(r, "rtnl: received route message with invalid nexthop id, ignoring: %m");
+
+        if (route->nexthop_id != 0 || route_type_is_reject(route))
+                /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
+                 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to make it consistent with IPv4
+                 * routes. Hence, skip reading of RTA_OIF. */
+                return 0;
+
+        uint32_t ifindex = 0;
+        r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
+        if (r < 0 && r != -ENODATA)
+                return log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
+
+        if (ifindex > 0) {
+                r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, route->family, &route->gw);
+                if (r >= 0) {
+                        route->gw_family = route->family;
+                        return 0;
+                }
+                if (r != -ENODATA)
+                        return log_warning_errno(r, "rtnl: received route message without valid gateway, ignoring: %m");
+
+                if (route->family != AF_INET)
+                        return 0;
+
+                RouteVia via;
+                r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
+                if (r >= 0) {
+                        route->gw_family = via.family;
+                        route->gw = via.address;
+                        return 0;
+                }
+                if (r != -ENODATA)
+                        return log_warning_errno(r, "rtnl: received route message without valid gateway, ignoring: %m");
+
+                return 0;
+        }
+
+        size_t rta_len;
+        _cleanup_free_ void *rta = NULL;
+        r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta);
+        if (r == -ENODATA)
+                return 0;
+        if (r < 0)
+                return log_warning_errno(r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
+
+        r = rtattr_read_nexthop(rta, rta_len, route->family, &route->multipath_routes);
+        if (r < 0)
+                return log_warning_errno(r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
+
+        return 0;
+}
+
 int route_section_verify_nexthops(Route *route) {
         assert(route);
         assert(route->section);
index fb935749865322babb2b8de4aeb97851db53fa1b..bd3e70c6ea5c79f159f2c830a4c8cd39c05e0c18 100644 (file)
@@ -5,6 +5,9 @@
 
 typedef struct Route Route;
 
+int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlink_message *message);
+int route_nexthops_read_netlink_message(Route *route, sd_netlink_message *message);
+
 int route_section_verify_nexthops(Route *route);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
index dfbbefdbd668acab3d1b801f989a78943b68abf2..d96934c5df5eddab04f81309f28871f5a29d7aa4 100644 (file)
@@ -600,23 +600,6 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req
 
         /* link may be NULL */
 
-        if (in_addr_is_set(route->gw_family, &route->gw) && route->nexthop_id == 0) {
-                if (route->gw_family == route->family) {
-                        r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw);
-                        if (r < 0)
-                                return r;
-                } else {
-                        RouteVia rtvia = {
-                                .family = route->gw_family,
-                                .address = route->gw,
-                        };
-
-                        r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
-                        if (r < 0)
-                                return r;
-                }
-        }
-
         if (route->dst_prefixlen > 0) {
                 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
                 if (r < 0)
@@ -666,22 +649,6 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req
                         return r;
         }
 
-        if (!route_type_is_reject(route) &&
-            route->nexthop_id == 0 &&
-            ordered_set_isempty(route->multipath_routes)) {
-                assert(link); /* Those routes must be attached to a specific link */
-
-                r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
-                if (r < 0)
-                        return r;
-        }
-
-        if (route->nexthop_id > 0) {
-                r = sd_netlink_message_append_u32(req, RTA_NH_ID, route->nexthop_id);
-                if (r < 0)
-                        return r;
-        }
-
         r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
         if (r < 0)
                 return r;
@@ -690,6 +657,11 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req
         if (r < 0)
                 return r;
 
+        /* nexthops */
+        r = route_nexthops_set_netlink_message(link, route, req);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 
@@ -1035,91 +1007,6 @@ static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo
         return 1;
 }
 
-static int append_nexthop_one(const Link *link, const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
-        struct rtnexthop *rtnh;
-        struct rtattr *new_rta;
-        int r;
-
-        assert(route);
-        assert(m);
-        assert(rta);
-        assert(*rta);
-
-        new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
-        if (!new_rta)
-                return -ENOMEM;
-        *rta = new_rta;
-
-        rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
-        *rtnh = (struct rtnexthop) {
-                .rtnh_len = sizeof(*rtnh),
-                .rtnh_ifindex = m->ifindex > 0 ? m->ifindex : link->ifindex,
-                .rtnh_hops = m->weight,
-        };
-
-        (*rta)->rta_len += sizeof(struct rtnexthop);
-
-        if (route->family == m->gateway.family) {
-                r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
-                if (r < 0)
-                        goto clear;
-                rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
-                rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
-        } else {
-                r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
-                if (r < 0)
-                        goto clear;
-                rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
-                rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
-        }
-
-        return 0;
-
-clear:
-        (*rta)->rta_len -= sizeof(struct rtnexthop);
-        return r;
-}
-
-static int append_nexthops(const Link *link, const Route *route, sd_netlink_message *req) {
-        _cleanup_free_ struct rtattr *rta = NULL;
-        struct rtnexthop *rtnh;
-        MultipathRoute *m;
-        size_t offset;
-        int r;
-
-        assert(link);
-        assert(route);
-        assert(req);
-
-        if (ordered_set_isempty(route->multipath_routes))
-                return 0;
-
-        rta = new(struct rtattr, 1);
-        if (!rta)
-                return -ENOMEM;
-
-        *rta = (struct rtattr) {
-                .rta_type = RTA_MULTIPATH,
-                .rta_len = RTA_LENGTH(0),
-        };
-        offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
-
-        ORDERED_SET_FOREACH(m, route->multipath_routes) {
-                r = append_nexthop_one(link, route, m, &rta, offset);
-                if (r < 0)
-                        return r;
-
-                rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
-                offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
-        }
-
-        r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
 int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, Route *route, const char *error_msg) {
         int r;
 
@@ -1186,15 +1073,6 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link
         if (r < 0)
                 return r;
 
-        if (!ordered_set_isempty(route->multipath_routes)) {
-                assert(route->nexthop_id == 0);
-                assert(!in_addr_is_set(route->gw_family, &route->gw));
-
-                r = append_nexthops(link, route, m);
-                if (r < 0)
-                        return r;
-        }
-
         return request_call_netlink_async(link->manager->rtnl, m, req);
 }
 
@@ -1610,13 +1488,11 @@ static int process_route_one(
 int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
         _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
         _cleanup_(route_freep) Route *tmp = NULL;
-        _cleanup_free_ void *rta_multipath = NULL;
         struct rta_cacheinfo cacheinfo;
         bool has_cacheinfo;
         Link *link = NULL;
         uint32_t ifindex;
         uint16_t type;
-        size_t rta_len;
         int r;
 
         assert(rtnl);
@@ -1691,25 +1567,6 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
                 return 0;
         }
 
-        r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, tmp->family, &tmp->gw);
-        if (r < 0 && r != -ENODATA) {
-                log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
-                return 0;
-        } else if (r >= 0)
-                tmp->gw_family = tmp->family;
-        else if (tmp->family == AF_INET) {
-                RouteVia via;
-
-                r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
-                if (r < 0 && r != -ENODATA) {
-                        log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
-                        return 0;
-                } else if (r >= 0) {
-                        tmp->gw_family = via.family;
-                        tmp->gw = via.address;
-                }
-        }
-
         r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
         if (r < 0 && r != -ENODATA) {
                 log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
@@ -1771,28 +1628,14 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
                 return 0;
         }
 
-        r = sd_netlink_message_read_u32(message, RTA_NH_ID, &tmp->nexthop_id);
-        if (r < 0 && r != -ENODATA) {
-                log_link_warning_errno(link, r, "rtnl: received route message with invalid nexthop id, ignoring: %m");
+        /* nexthops */
+        if (route_nexthops_read_netlink_message(tmp, message) < 0)
                 return 0;
-        }
 
         /* metrics */
         if (route_metric_read_netlink_message(&tmp->metric, message) < 0)
                 return 0;
 
-        r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta_multipath);
-        if (r < 0 && r != -ENODATA) {
-                log_link_warning_errno(link, r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
-                return 0;
-        } else if (r >= 0) {
-                r = rtattr_read_nexthop(rta_multipath, rta_len, tmp->family, &tmp->multipath_routes);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
-                        return 0;
-                }
-        }
-
         r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
         if (r < 0 && r != -ENODATA) {
                 log_link_warning_errno(link, r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");