]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-route.c
networkd: route - support unicast,blackhole,unreachable and prohibited (#6861)
[thirdparty/systemd.git] / src / network / networkd-route.c
index ff93fe4a044672a5f9fc0d74249484becb0c5c2b..5b4874795a7dfd78a1cba054779756fda8c43000 100644 (file)
@@ -70,6 +70,7 @@ int route_new(Route **ret) {
         route->family = AF_UNSPEC;
         route->scope = RT_SCOPE_UNIVERSE;
         route->protocol = RTPROT_UNSPEC;
+        route->type = RTN_UNICAST;
         route->table = RT_TABLE_MAIN;
         route->lifetime = USEC_INFINITY;
 
@@ -230,7 +231,7 @@ int route_get(Link *link,
               unsigned char dst_prefixlen,
               unsigned char tos,
               uint32_t priority,
-              unsigned char table,
+              uint32_t table,
               Route **ret) {
 
         Route route, *existing;
@@ -272,7 +273,7 @@ static int route_add_internal(
                 unsigned char dst_prefixlen,
                 unsigned char tos,
                 uint32_t priority,
-                unsigned char table,
+                uint32_t table,
                 Route **ret) {
 
         _cleanup_route_free_ Route *route = NULL;
@@ -318,7 +319,7 @@ int route_add_foreign(
                 unsigned char dst_prefixlen,
                 unsigned char tos,
                 uint32_t priority,
-                unsigned char table,
+                uint32_t table,
                 Route **ret) {
 
         return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
@@ -331,7 +332,7 @@ int route_add(
               unsigned char dst_prefixlen,
               unsigned char tos,
               uint32_t priority,
-              unsigned char table,
+              uint32_t table,
               Route **ret) {
 
         Route *route;
@@ -372,7 +373,8 @@ int route_update(Route *route,
                  const union in_addr_union *gw,
                  const union in_addr_union *prefsrc,
                  unsigned char scope,
-                 unsigned char protocol) {
+                 unsigned char protocol,
+                 unsigned char type) {
 
         assert(route);
         assert(src);
@@ -385,6 +387,7 @@ int route_update(Route *route,
         route->prefsrc = *prefsrc;
         route->scope = scope;
         route->protocol = protocol;
+        route->type = type;
 
         return 0;
 }
@@ -458,9 +461,15 @@ int route_remove(Route *route, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
 
-        r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+        r = sd_rtnl_message_route_set_type(req, route->type);
         if (r < 0)
-                return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+                return log_error_errno(r, "Could not set route type: %m");
+
+        if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
+                r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+                if (r < 0)
+                        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);
         if (r < 0)
@@ -612,9 +621,15 @@ int route_configure(
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
 
-        r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+        r = sd_rtnl_message_route_set_type(req, route->type);
         if (r < 0)
-                return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+                return log_error_errno(r, "Could not set route type: %m");
+
+        if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
+                r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+                if (r < 0)
+                        return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+        }
 
         r = sd_netlink_message_open_container(req, RTA_METRICS);
         if (r < 0)
@@ -757,10 +772,9 @@ int config_parse_destination(const char *unit,
 
         Network *network = userdata;
         _cleanup_route_free_ Route *n = NULL;
-        const char *address, *e;
         union in_addr_union buffer;
         unsigned char prefixlen;
-        int r, f;
+        int r;
 
         assert(filename);
         assert(section);
@@ -772,45 +786,20 @@ int config_parse_destination(const char *unit,
         if (r < 0)
                 return r;
 
-        /* Destination|Source=address/prefixlen */
-
-        /* address */
-        e = strchr(rvalue, '/');
-        if (e)
-                address = strndupa(rvalue, e - rvalue);
-        else
-                address = rvalue;
-
-        r = in_addr_from_string_auto(address, &f, &buffer);
+        r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Destination is invalid, ignoring assignment: %s", address);
-                return 0;
-        }
-
-        if (f != AF_INET && f != AF_INET6) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown address family, ignoring assignment: %s", address);
-                return 0;
-        }
-
-        /* prefixlen */
-        if (e) {
-                r = safe_atou8(e + 1, &prefixlen);
+                r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Route %s= prefix is invalid, ignoring assignment: %s",
+                                   lvalue, rvalue);
                         return 0;
                 }
-        } else {
-                switch (f) {
-                        case AF_INET:
-                                prefixlen = 32;
-                                break;
-                        case AF_INET6:
-                                prefixlen = 128;
-                                break;
-                }
-        }
 
-        n->family = f;
+                n->family = AF_INET6;
+        } else
+                n->family = AF_INET;
+
         if (streq(lvalue, "Destination")) {
                 n->dst = buffer;
                 n->dst_prefixlen = prefixlen;
@@ -1012,3 +1001,76 @@ int config_parse_ipv6_route_preference(const char *unit,
 
         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) {
+        Network *network = userdata;
+        _cleanup_route_free_ Route *n = NULL;
+        int r;
+
+        r = route_new_static(network, filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        if (streq(rvalue, "kernel"))
+                n->protocol = RTPROT_KERNEL;
+        else if (streq(rvalue, "boot"))
+                n->protocol = RTPROT_BOOT;
+        else if (streq(rvalue, "static"))
+                n->protocol = RTPROT_STATIC;
+        else {
+                r = safe_atou8(rvalue , &n->protocol);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
+                        return 0;
+                }
+        }
+
+        n = NULL;
+
+        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) {
+        Network *network = userdata;
+        _cleanup_route_free_ Route *n = NULL;
+        int r;
+
+        r = route_new_static(network, filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        if (streq(rvalue, "unicast"))
+                n->type = RTN_UNICAST;
+        else if (streq(rvalue, "blackhole"))
+                n->type = RTN_BLACKHOLE;
+        else if (streq(rvalue, "unreachable"))
+                n->type = RTN_UNREACHABLE;
+        else if (streq(rvalue, "prohibit"))
+                n->type = RTN_PROHIBIT;
+        else {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
+                return 0;
+        }
+
+        n = NULL;
+
+        return 0;
+}