]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-route.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / network / networkd-route.c
index ee1ddd81fe84c6983986e2a1ed94a9dce688199f..fcca6790936d194fd3febbb39716308c655a0019 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
 #include "conf-parser.h"
+#include "in-addr-util.h"
 #include "netlink-util.h"
-
 #include "networkd.h"
+#include "string-util.h"
+#include "util.h"
 #include "networkd-route.h"
 
+int route_new(Route **ret) {
+        _cleanup_route_free_ Route *route = NULL;
+
+        route = new0(Route, 1);
+        if (!route)
+                return -ENOMEM;
+
+        route->family = AF_UNSPEC;
+        route->scope = RT_SCOPE_UNIVERSE;
+        route->protocol = RTPROT_UNSPEC;
+        route->table = RT_TABLE_DEFAULT;
+
+        *ret = route;
+        route = NULL;
+
+        return 0;
+}
+
 int route_new_static(Network *network, unsigned section, Route **ret) {
         _cleanup_route_free_ Route *route = NULL;
+        int r;
 
         if (section) {
                 route = hashmap_get(network->routes_by_section,
@@ -40,14 +60,11 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
                 }
         }
 
-        route = new0(Route, 1);
-        if (!route)
-                return -ENOMEM;
+        r = route_new(&route);
+        if (r < 0)
+                return r;
 
-        route->family = AF_UNSPEC;
-        route->scope = RT_SCOPE_UNIVERSE;
         route->protocol = RTPROT_STATIC;
-
         route->network = network;
 
         LIST_PREPEND(routes, network->static_routes, route);
@@ -64,23 +81,6 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
         return 0;
 }
 
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
-        _cleanup_route_free_ Route *route = NULL;
-
-        route = new0(Route, 1);
-        if (!route)
-                return -ENOMEM;
-
-        route->family = AF_UNSPEC;
-        route->scope = RT_SCOPE_UNIVERSE;
-        route->protocol = rtm_protocol;
-
-        *ret = route;
-        route = NULL;
-
-        return 0;
-}
-
 void route_free(Route *route) {
         if (!route)
                 return;
@@ -96,7 +96,76 @@ void route_free(Route *route) {
         free(route);
 }
 
-int route_drop(Route *route, Link *link,
+static void route_hash_func(const void *b, struct siphash *state) {
+        const Route *route = b;
+
+        assert(route);
+
+        siphash24_compress(&route->family, sizeof(route->family), state);
+
+        switch (route->family) {
+        case AF_INET:
+        case AF_INET6:
+                /* Equality of routes are given by the 4-touple
+                   (dst_prefix,dst_prefixlen,tos,priority,table) */
+                siphash24_compress(&route->dst_addr, FAMILY_ADDRESS_SIZE(route->family), state);
+                siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
+                siphash24_compress(&route->tos, sizeof(route->tos), state);
+                siphash24_compress(&route->priority, sizeof(route->priority), state);
+                siphash24_compress(&route->table, sizeof(route->table), state);
+
+                break;
+        default:
+                /* treat any other address family as AF_UNSPEC */
+                break;
+        }
+}
+
+static int route_compare_func(const void *_a, const void *_b) {
+        const Route *a = _a, *b = _b;
+
+        if (a->family < b->family)
+                return -1;
+        if (a->family > b->family)
+                return 1;
+
+        switch (a->family) {
+        case AF_INET:
+        case AF_INET6:
+                //TODO: check IPv6 routes
+                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;
+
+                return memcmp(&a->dst_addr, &b->dst_addr, FAMILY_ADDRESS_SIZE(a->family));
+        default:
+                /* treat any other address family as AF_UNSPEC */
+                return 0;
+        }
+}
+
+static const struct hash_ops route_hash_ops = {
+        .hash = route_hash_func,
+        .compare = route_compare_func
+};
+
+int route_remove(Route *route, Link *link,
                sd_netlink_message_handler_t callback) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;