networkd: IP address equality

This commit is contained in:
Tom Gundersen 2014-05-16 00:27:56 +02:00
parent ac97653206
commit 9505d3c6de
3 changed files with 91 additions and 0 deletions

View file

@ -508,3 +508,46 @@ int config_parse_label(const char *unit,
return 0;
}
bool address_equal(Address *a1, Address *a2) {
/* same object */
if (a1 == a2)
return true;
/* one, but not both, is NULL */
if (!a1 || !a2)
return false;
if (a1->family != a2->family)
return false;
switch (a1->family) {
/* use the same notion of equality as the kernel does */
case AF_UNSPEC:
return true;
case AF_INET:
if (a1->prefixlen != a2->prefixlen)
return false;
else {
uint32_t b1, b2;
b1 = be32toh(a1->in_addr.in.s_addr);
b2 = be32toh(a2->in_addr.in.s_addr);
return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
}
case AF_INET6:
{
uint64_t *b1, *b2;
b1 = (uint64_t*)&a1->in_addr.in6;
b2 = (uint64_t*)&a2->in_addr.in6;
return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
}
default:
assert_not_reached("Invalid address family");
}
}

View file

@ -386,6 +386,7 @@ void address_free(Address *address);
int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
int address_update(Address *address, Link *link, sd_rtnl_message_handler_t callback);
int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback);
bool address_equal(Address *a1, Address *a2);
DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
#define _cleanup_address_free_ _cleanup_(address_freep)

View file

@ -42,11 +42,58 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) {
assert_se(!network);
}
static void test_address_equality(void) {
Address *a1, *a2;
assert_se(address_new_dynamic(&a1) >= 0);
assert_se(address_new_dynamic(&a2) >= 0);
assert_se(address_equal(NULL, NULL));
assert_se(!address_equal(a1, NULL));
assert_se(!address_equal(NULL, a2));
assert_se(address_equal(a1, a2));
a1->family = AF_INET;
assert_se(!address_equal(a1, a2));
a2->family = AF_INET;
assert_se(address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a1->in_addr.in));
assert_se(!address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a2->in_addr.in));
assert_se(address_equal(a1, a2));
a1->prefixlen = 10;
assert_se(!address_equal(a1, a2));
a2->prefixlen = 10;
assert_se(address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.10", &a2->in_addr.in));
assert_se(address_equal(a1, a2));
a1->family = AF_INET6;
assert_se(!address_equal(a1, a2));
a2->family = AF_INET6;
assert_se(inet_pton(AF_INET6, "2001:4ca0:4f01::2", &a1->in_addr.in6));
assert_se(inet_pton(AF_INET6, "2001:4ca0:4f01::2", &a2->in_addr.in6));
assert_se(address_equal(a1, a2));
a2->prefixlen = 8;
assert_se(address_equal(a1, a2));
assert_se(inet_pton(AF_INET6, "2001:4ca0:4f01::1", &a2->in_addr.in6));
assert_se(!address_equal(a1, a2));
}
int main(void) {
_cleanup_manager_free_ Manager *manager = NULL;
struct udev *udev;
struct udev_device *loopback;
test_address_equality();
assert_se(manager_new(&manager) >= 0);
test_load_config(manager);