X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fnetwork%2Fnetworkd-route.c;h=fcca6790936d194fd3febbb39716308c655a0019;hb=07630cea1f3a845c09309f197ac7c4f11edd3b62;hp=ee1ddd81fe84c6983986e2a1ed94a9dce688199f;hpb=dc545f8331333476ba3b08c677e44b565ad1c738;p=thirdparty%2Fsystemd.git diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index ee1ddd81fe8..fcca6790936 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -19,15 +19,35 @@ along with systemd; If not, see . ***/ -#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;