diff options
-rw-r--r-- | src/network/networkd-route.c | 73 | ||||
-rw-r--r-- | src/network/networkd-route.h | 3 |
2 files changed, 75 insertions, 1 deletions
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 66b165f661..aa4ec230ab 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -19,9 +19,10 @@ 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 "util.h" #include "networkd.h" #include "networkd-route.h" @@ -36,6 +37,7 @@ int route_new(Route **ret) { route->family = AF_UNSPEC; route->scope = RT_SCOPE_UNIVERSE; route->protocol = RTPROT_UNSPEC; + route->table = RT_TABLE_DEFAULT; *ret = route; route = NULL; @@ -94,6 +96,75 @@ void route_free(Route *route) { free(route); } +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; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 7f2d7f37f4..c9972e4933 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -36,6 +36,9 @@ struct Route { unsigned char scope; uint32_t metrics; unsigned char protocol; /* RTPROT_* */ + unsigned char tos; + unsigned char priority; + unsigned char table; union in_addr_union in_addr; union in_addr_union dst_addr; |