]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: delay resolving interface specifier in MultiPathRoute=
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 6 May 2021 19:29:52 +0000 (04:29 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 12 May 2021 01:37:17 +0000 (10:37 +0900)
The interface may not exist when .network files are loaded.

src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/network/networkd-route.c

index 448c50d4ab44e0b9e5c2124ae6eecc5f04d4df60..4ab3b1020c7371f479c881ee2d8936c8ea8e0c71 100644 (file)
@@ -409,6 +409,15 @@ int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void
         return 0;
 }
 
+MultipathRoute *multipath_route_free(MultipathRoute *m) {
+        if (!m)
+                return NULL;
+
+        free(m->ifname);
+
+        return mfree(m);
+}
+
 int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret) {
         _cleanup_ordered_set_free_free_ OrderedSet *set = NULL;
         int r;
@@ -420,7 +429,7 @@ int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, O
                 return -EBADMSG;
 
         for (; size >= sizeof(struct rtnexthop); ) {
-                _cleanup_free_ MultipathRoute *m = NULL;
+                _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
 
                 if (NLMSG_ALIGN(rtnh->rtnh_len) > size)
                         return -EBADMSG;
index a3a3951ff7942e79908b0899aeb9cfec55da07a1..394c821ffba051323d8075b72be0564b70410c6f 100644 (file)
@@ -19,10 +19,14 @@ typedef struct RouteVia {
 
 typedef struct MultipathRoute {
         RouteVia gateway;
-        int ifindex;
         uint32_t weight;
+        int ifindex;
+        char *ifname;
 } MultipathRoute;
 
+MultipathRoute *multipath_route_free(MultipathRoute *m);
+DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
+
 int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret);
 uint32_t rtnl_message_get_serial(sd_netlink_message *m);
 void rtnl_message_seal(sd_netlink_message *m);
index 8f3d84129a840f8908f89b8d5864b6923a9f8305..b5ea14089a5f8165cd642030b8838c06d3f4f54c 100644 (file)
@@ -288,7 +288,7 @@ Route *route_free(Route *route) {
                 set_remove(route->manager->routes_foreign, route);
         }
 
-        ordered_set_free_free(route->multipath_routes);
+        ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free);
 
         sd_event_source_unref(route->expire);
 
@@ -1299,20 +1299,41 @@ static bool route_has_gateway(const Route *route) {
 }
 
 static int link_set_routes_internal(Link *link, bool with_gateway) {
-        Route *rt;
+        Route *route;
         int r;
 
         assert(link);
         assert(link->network);
 
-        HASHMAP_FOREACH(rt, link->network->routes_by_section) {
-                if (rt->gateway_from_dhcp_or_ra)
+        HASHMAP_FOREACH(route, link->network->routes_by_section) {
+                bool multipath_ok = true;
+                MultipathRoute *m;
+
+                if (route->gateway_from_dhcp_or_ra)
+                        continue;
+
+                if (route_has_gateway(route) != with_gateway)
                         continue;
 
-                if (route_has_gateway(rt) != with_gateway)
+                ORDERED_SET_FOREACH(m, route->multipath_routes) {
+                        if (isempty(m->ifname))
+                                continue;
+
+                        r = resolve_interface(&link->manager->rtnl, m->ifname);
+                        if (r < 0) {
+                                log_link_debug_errno(link, r,
+                                                     "Failed to resolve interface name '%s' for multipath route, "
+                                                     "ignoring the route: %m", m->ifname);
+                                multipath_ok = false;
+                                break;
+                        }
+
+                        m->ifindex = r;
+                }
+                if (!multipath_ok)
                         continue;
 
-                r = route_configure(rt, link, with_gateway ? route_handler_with_gateway : route_handler_without_gateway, NULL);
+                r = route_configure(route, link, with_gateway ? route_handler_with_gateway : route_handler_without_gateway, NULL);
                 if (r < 0)
                         return log_link_warning_errno(link, r, "Could not set routes: %m");
 
@@ -2460,13 +2481,14 @@ int config_parse_multipath_route(
                 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, *buf = NULL;
-        _cleanup_free_ MultipathRoute *m = NULL;
+        _cleanup_free_ char *word = NULL;
         Network *network = userdata;
-        const char *p, *ip, *dev;
         union in_addr_union a;
         int family, r;
+        const char *p;
+        char *dev;
 
         assert(filename);
         assert(section);
@@ -2484,7 +2506,7 @@ int config_parse_multipath_route(
         }
 
         if (isempty(rvalue)) {
-                n->multipath_routes = ordered_set_free_free(n->multipath_routes);
+                n->multipath_routes = ordered_set_free_with_destructor(n->multipath_routes, multipath_route_free);
                 return 0;
         }
 
@@ -2504,15 +2526,14 @@ int config_parse_multipath_route(
 
         dev = strchr(word, '@');
         if (dev) {
-                buf = strndup(word, dev - word);
-                if (!buf)
+                *dev++ = '\0';
+
+                m->ifname = strdup(dev);
+                if (!m->ifname)
                         return log_oom();
-                ip = buf;
-                dev++;
-        } else
-                ip = word;
+        }
 
-        r = in_addr_from_string_auto(ip, &family, &a);
+        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);
@@ -2521,16 +2542,6 @@ int config_parse_multipath_route(
         m->gateway.address = a;
         m->gateway.family = family;
 
-        if (dev) {
-                r = resolve_interface(NULL, dev);
-                if (r < 0) {
-                        log_syntax(unit, LOG_WARNING, filename, line, r,
-                                   "Invalid interface name or index, ignoring assignment: %s", dev);
-                        return 0;
-                }
-                m->ifindex = r;
-        }
-
         if (!isempty(p)) {
                 r = safe_atou32(p, &m->weight);
                 if (r < 0) {