[MERGED] osmo-ggsn[master]: lib/in46a: Introduce in46a_netmasklen API

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Pau Espin Pedrol gerrit-no-reply at lists.osmocom.org
Wed Oct 18 10:56:52 UTC 2017


Pau Espin Pedrol has submitted this change and it was merged.

Change subject: lib/in46a: Introduce in46a_netmasklen API
......................................................................


lib/in46a: Introduce in46a_netmasklen API

Change-Id: I06e3e038afd8f7afaec2a3fa67b1616500c8db80
---
M lib/in46_addr.c
M lib/in46_addr.h
M tests/lib/in46a_test.c
M tests/lib/in46a_test.ok
4 files changed, 120 insertions(+), 0 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/lib/in46_addr.c b/lib/in46_addr.c
index 32e0f8d..36ad6af 100644
--- a/lib/in46_addr.c
+++ b/lib/in46_addr.c
@@ -195,6 +195,64 @@
 	}
 }
 
+static unsigned int ipv4_netmasklen(const struct in_addr *netmask)
+{
+	uint32_t bits = netmask->s_addr;
+	uint8_t *b = (uint8_t*) &bits;
+	unsigned int i, prefix = 0;
+
+	for (i = 0; i < 4; i++) {
+		while (b[i] & 0x80) {
+			prefix++;
+			b[i] = b[i] << 1;
+		}
+	}
+	return prefix;
+}
+
+static unsigned int ipv6_netmasklen(const struct in6_addr *netmask)
+{
+	#if defined(__linux__)
+		#define ADDRFIELD(i) s6_addr32[i]
+	#else
+		#define ADDRFIELD(i) __u6_addr.__u6_addr32[i]
+	#endif
+
+	unsigned int i, j, prefix = 0;
+
+	for (j = 0; j < 4; j++) {
+		uint32_t bits = netmask->ADDRFIELD(j);
+		uint8_t *b = (uint8_t*) &bits;
+		for (i = 0; i < 4; i++) {
+			while (b[i] & 0x80) {
+				prefix++;
+				b[i] = b[i] << 1;
+			}
+		}
+	}
+
+	#undef ADDRFIELD
+
+	return prefix;
+}
+
+/*! Convert netmask to prefix length representation
+ *  \param[in] netmask in46_addr containing a netmask (consecutive list of 1-bit followed by consecutive list of 0-bit)
+ *  \returns prefix length representation of the netmask (count of 1-bit from the start of the netmask)
+ */
+unsigned int in46a_netmasklen(const struct in46_addr *netmask)
+{
+	switch (netmask->len) {
+	case 4:
+		return ipv4_netmasklen(&netmask->v4);
+	case 16:
+		return ipv6_netmasklen(&netmask->v6);
+	default:
+		OSMO_ASSERT(0);
+		return 0;
+	}
+}
+
 /*! Convert given PDP End User Address to in46_addr
  *  \returns 0 on success; negative on error */
 int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua)
diff --git a/lib/in46_addr.h b/lib/in46_addr.h
index ce2df14..ff26521 100644
--- a/lib/in46_addr.h
+++ b/lib/in46_addr.h
@@ -27,6 +27,7 @@
 extern int in46a_equal(const struct in46_addr *a, const struct in46_addr *b);
 extern int in46a_prefix_equal(const struct in46_addr *a, const struct in46_addr *b);
 extern int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen);
+unsigned int in46a_netmasklen(const struct in46_addr *netmask);
 
 int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua);
 int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst);
diff --git a/tests/lib/in46a_test.c b/tests/lib/in46a_test.c
index d6215e7..42a1768 100644
--- a/tests/lib/in46a_test.c
+++ b/tests/lib/in46a_test.c
@@ -246,6 +246,64 @@
 	OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len));
 }
 
+static void test_in46a_netmasklen(void)
+{
+	struct in46_addr netmask;
+	unsigned int len;
+
+	printf("Testing in46a_netmasklen() with IPv4 addresses\n");
+	netmask.len = 4;
+
+	netmask.v4.s_addr = 0xffffffff;
+	len = in46a_netmasklen(&netmask);
+	OSMO_ASSERT(len == 32);
+
+	netmask.v4.s_addr = 0x00ffffff;
+	len = in46a_netmasklen(&netmask);
+	OSMO_ASSERT(len == 24);
+
+	netmask.v4.s_addr = 0x00f0ffff;
+	len = in46a_netmasklen(&netmask);
+	OSMO_ASSERT(len == 20);
+
+	netmask.v4.s_addr = 0x000000fe;
+	len = in46a_netmasklen(&netmask);
+	OSMO_ASSERT(len == 7);
+
+	netmask.v4.s_addr = 0x00000000;
+	len = in46a_netmasklen(&netmask);
+	OSMO_ASSERT(len == 0);
+
+	printf("Testing in46a_netmasklen() with IPv6 addresses\n");
+	const struct in46_addr netmaskA = {
+		.len = 16,
+		.v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
+	};
+	len = in46a_netmasklen(&netmaskA);
+	OSMO_ASSERT(len == 128);
+
+	const struct in46_addr netmaskB = {
+		.len = 16,
+		.v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00},
+	};
+	len = in46a_netmasklen(&netmaskB);
+	OSMO_ASSERT(len == 104);
+
+	const struct in46_addr netmaskC = {
+		.len = 16,
+		.v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00},
+	};
+	len = in46a_netmasklen(&netmaskC);
+	OSMO_ASSERT(len == 103);
+
+	const struct in46_addr netmaskD = {
+		.len = 16,
+		.v6.s6_addr = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+	};
+	len = in46a_netmasklen(&netmaskD);
+	OSMO_ASSERT(len == 0);
+}
+
 int main(int argc, char **argv)
 {
 	osmo_init_logging(&log_info);
@@ -262,4 +320,5 @@
 	test_in46a_within_mask();
 	test_in46a_to_eua();
 	test_in46a_from_eua();
+	test_in46a_netmasklen();
 }
diff --git a/tests/lib/in46a_test.ok b/tests/lib/in46a_test.ok
index b115444..9a0ff7a 100644
--- a/tests/lib/in46a_test.ok
+++ b/tests/lib/in46a_test.ok
@@ -15,3 +15,5 @@
 in46a_within_mask(10.11.12.14, 10.11.12.12, 30) = 1
 testing in46a_to_eua()
 Testing in46a_from_eua()
+Testing in46a_netmasklen() with IPv4 addresses
+Testing in46a_netmasklen() with IPv6 addresses

-- 
To view, visit https://gerrit.osmocom.org/4290
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I06e3e038afd8f7afaec2a3fa67b1616500c8db80
Gerrit-PatchSet: 2
Gerrit-Project: osmo-ggsn
Gerrit-Branch: master
Gerrit-Owner: Pau Espin Pedrol <pespin at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Pau Espin Pedrol <pespin at sysmocom.de>



More information about the gerrit-log mailing list