]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/route-nexthop: introduce route_adjust_nexthops() and route_nexthops_needs_adj...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 14 Jan 2024 05:50:19 +0000 (14:50 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 19 Jan 2024 01:23:14 +0000 (10:23 +0900)
These are not used in this commit, but will be used later.
Preparation for later commits.

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

index 6ea68afdc8a4e0bb505e91a53cf73458f2930519..9e14c695be12bed795be1a0b519ec71d034fa44c 100644 (file)
@@ -200,6 +200,117 @@ int route_nexthops_copy(const Route *src, const RouteNextHop *nh, Route *dest) {
         return 0;
 }
 
+static bool multipath_routes_needs_adjust(const Route *route) {
+        assert(route);
+
+        RouteNextHop *nh;
+        ORDERED_SET_FOREACH(nh, route->nexthops)
+                if (route->nexthop.ifindex == 0)
+                        return true;
+
+        return false;
+}
+
+bool route_nexthops_needs_adjust(const Route *route) {
+        assert(route);
+
+        if (route->nexthop_id != 0)
+                /* At this stage, the nexthop may not be configured, or may be under reconfiguring.
+                 * Hence, we cannot know if the nexthop is blackhole or not. */
+                return route->type != RTN_BLACKHOLE;
+
+        if (route_type_is_reject(route))
+                return false;
+
+        if (ordered_set_isempty(route->nexthops))
+                return route->nexthop.ifindex == 0;
+
+        return multipath_routes_needs_adjust(route);
+}
+
+static bool route_nexthop_set_ifindex(RouteNextHop *nh, Link *link) {
+        assert(nh);
+        assert(link);
+        assert(link->manager);
+
+        if (nh->ifindex > 0) {
+                nh->ifname = mfree(nh->ifname);
+                return false;
+        }
+
+        /* If an interface name is specified, use it. Otherwise, use the interface that requests this route. */
+        if (nh->ifname && link_get_by_name(link->manager, nh->ifname, &link) < 0)
+                return false;
+
+        nh->ifindex = link->ifindex;
+        nh->ifname = mfree(nh->ifname);
+        return true; /* updated */
+}
+
+int route_adjust_nexthops(Route *route, Link *link) {
+        int r;
+
+        assert(route);
+        assert(link);
+        assert(link->manager);
+
+        /* When an IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel sends
+         * RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type fib_rt_info::type
+         * may not be blackhole. Thus, we cannot know the internal value. Moreover, on route removal, the
+         * matching is done with the hidden value if we set non-zero type in RTM_DELROUTE message. So,
+         * here let's set route type to BLACKHOLE when the nexthop is blackhole. */
+        if (route->nexthop_id != 0) {
+                NextHop *nexthop;
+
+                r = nexthop_is_ready(link->manager, route->nexthop_id, &nexthop);
+                if (r <= 0)
+                        return r; /* r == 0 means the nexthop is under (re-)configuring.
+                                   * We cannot use the currently remembered information. */
+
+                if (!nexthop->blackhole)
+                        return false;
+
+                if (route->type == RTN_BLACKHOLE)
+                        return false;
+
+                route->type = RTN_BLACKHOLE;
+                return true; /* updated */
+        }
+
+        if (route_type_is_reject(route))
+                return false;
+
+        if (ordered_set_isempty(route->nexthops))
+                return route_nexthop_set_ifindex(&route->nexthop, link);
+
+        if (!multipath_routes_needs_adjust(route))
+                return false;
+
+        _cleanup_ordered_set_free_ OrderedSet *nexthops = NULL;
+        for (;;) {
+                _cleanup_(route_nexthop_freep) RouteNextHop *nh = NULL;
+
+                nh = ordered_set_steal_first(route->nexthops);
+                if (!nh)
+                        break;
+
+                (void) route_nexthop_set_ifindex(nh, link);
+
+                r = ordered_set_ensure_put(&nexthops, &route_nexthop_hash_ops, nh);
+                if (r == -EEXIST)
+                        continue; /* Duplicated? Let's drop the nexthop. */
+                if (r < 0)
+                        return r;
+                assert(r > 0);
+
+                TAKE_PTR(nh);
+        }
+
+        ordered_set_free(route->nexthops);
+        route->nexthops = TAKE_PTR(nexthops);
+        return true; /* updated */
+}
+
 int route_nexthop_get_link(Manager *manager, Link *link, const RouteNextHop *nh, Link **ret) {
         assert(manager);
         assert(nh);
index 0d305c7231c3a0e7c7818dabebba3b0ec4e7b3af..a63409c9e288e98e065b79d0c178e9753eafc629 100644 (file)
@@ -35,6 +35,8 @@ void route_nexthops_hash_func(const Route *route, struct siphash *state);
 int route_nexthops_compare_func(const Route *a, const Route *b);
 
 int route_nexthops_copy(const Route *src, const RouteNextHop *nh, Route *dest);
+bool route_nexthops_needs_adjust(const Route *route);
+int route_adjust_nexthops(Route *route, Link *link);
 
 int route_nexthop_get_link(Manager *manager, Link *link, const RouteNextHop *nh, Link **ret);
 int route_nexthops_is_ready_to_configure(const Route *route, Link *link);