From e442e3881efad8b0b484763f87544facdc40cd7b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 14 Dec 2018 16:45:53 +0100 Subject: [PATCH] core: implement nm_utils_ip4_netmask_to_prefix() via __builtin_ctz() Taken from systemd's in4_addr_netmask_to_prefixlen(). Yes, this adds the requirement that "int" is 32 bits. But systemd already has the same requirement in u32ctz(), hence we anyway cannot build on other architectures. If that is ever necessary, it's easy to adjust. --- libnm-core/nm-utils.c | 29 +++++------------------ libnm-core/tests/test-general.c | 41 ++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 547c14185..b9d4b3d54 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -1389,30 +1389,13 @@ nm_utils_ip4_routes_from_variant (GVariant *value) guint32 nm_utils_ip4_netmask_to_prefix (guint32 netmask) { - guint32 prefix; - guint8 v; - const guint8 *p = (guint8 *) &netmask; + G_STATIC_ASSERT_EXPR (__SIZEOF_INT__ == 4); + G_STATIC_ASSERT_EXPR (sizeof (int) == 4); + G_STATIC_ASSERT_EXPR (sizeof (netmask) == 4); - if (p[3]) { - prefix = 24; - v = p[3]; - } else if (p[2]) { - prefix = 16; - v = p[2]; - } else if (p[1]) { - prefix = 8; - v = p[1]; - } else { - prefix = 0; - v = p[0]; - } - - while (v) { - prefix++; - v <<= 1; - } - - return prefix; + return ( (netmask != 0) + ? (32 - __builtin_ctz (ntohl (netmask))) + : 0); } /** diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 3ea7bbffa..03c923bef 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -3468,6 +3468,41 @@ test_connection_changed_cb (NMConnection *connection, gboolean *data) *data = TRUE; } +static guint32 +_netmask_to_prefix (guint32 netmask) +{ + guint32 prefix; + guint8 v; + const guint8 *p = (guint8 *) &netmask; + + if (p[3]) { + prefix = 24; + v = p[3]; + } else if (p[2]) { + prefix = 16; + v = p[2]; + } else if (p[1]) { + prefix = 8; + v = p[1]; + } else { + prefix = 0; + v = p[0]; + } + + while (v) { + prefix++; + v <<= 1; + } + + g_assert_cmpint (prefix, <=, 32); + + /* we re-implemented the netmask-to-prefix code differently. Check + * that they agree. */ + g_assert_cmpint (prefix, ==, nm_utils_ip4_netmask_to_prefix (netmask)); + + return prefix; +} + static void test_ip4_prefix_to_netmask (void) { @@ -3475,7 +3510,7 @@ test_ip4_prefix_to_netmask (void) for (i = 0; i<=32; i++) { guint32 netmask = _nm_utils_ip4_prefix_to_netmask (i); - int plen = nm_utils_ip4_netmask_to_prefix (netmask); + int plen = _netmask_to_prefix (netmask); g_assert_cmpint (i, ==, plen); { @@ -3505,7 +3540,7 @@ test_ip4_netmask_to_prefix (void) guint32 netmask = _nm_utils_ip4_prefix_to_netmask (i); guint32 netmask_lowest_bit = netmask & ~_nm_utils_ip4_prefix_to_netmask (i-1); - g_assert_cmpint (i, ==, nm_utils_ip4_netmask_to_prefix (netmask)); + g_assert_cmpint (i, ==, _netmask_to_prefix (netmask)); for (j = 0; j < 2*i; j++) { guint32 r = g_rand_int (rand); @@ -3519,7 +3554,7 @@ test_ip4_netmask_to_prefix (void) /* create an invalid netmask with holes and check that the function * returns the longest prefix. */ - prefix_holey = nm_utils_ip4_netmask_to_prefix (netmask_holey); + prefix_holey = _netmask_to_prefix (netmask_holey); g_assert_cmpint (i, ==, prefix_holey); }