Home | History | Annotate | Line # | Download | only in libnpftest
npf_table_test.c revision 1.9.14.1
      1 /*
      2  * NPF tableset tests.
      3  *
      4  * Public Domain.
      5  */
      6 
      7 #ifdef _KERNEL
      8 #include <sys/types.h>
      9 #include <sys/kmem.h>
     10 #endif
     11 
     12 #ifdef __linux__
     13 #include <endian.h>
     14 #else
     15 #include <sys/endian.h>
     16 #endif
     17 
     18 #include "npf_impl.h"
     19 #include "npf_test.h"
     20 
     21 static const char *ip_list[] = {
     22 	"192.168.1.1",
     23 	"10.0.0.1",
     24 	"192.168.2.1",
     25 	"10.1.0.1",
     26 	"192.168.100.253",
     27 	"10.0.5.1",
     28 	"192.168.128.127",
     29 	"10.0.0.2",
     30 };
     31 
     32 static const uint8_t ip6_list[][16] = {
     33 	{
     34 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     35 		0x02, 0xa0, 0xc0, 0xff, 0xfe, 0x10, 0x12, 0x34
     36 	},
     37 	{
     38 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     39 		0x02, 0xa0, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00,
     40 	},
     41 	{
     42 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     43 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     44 	},
     45 	{
     46 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     47 		0x02, 0xa0, 0xc0, 0xff, 0xfe, 0x10, 0x12, 0x30
     48 	}
     49 };
     50 
     51 #define	CHECK_TRUE(x)	\
     52     if (!(x)) { printf("FAIL: %s line %d\n", __func__, __LINE__); return 0; }
     53 
     54 #define	IPSET_TID		0
     55 #define	IPSET_NAME		"ipset-table"
     56 
     57 #define	LPM_TID			1
     58 #define	LPM_NAME		"lpm-table"
     59 
     60 #define	CDB_TID			2
     61 #define	CDB_NAME		"cdb-table"
     62 
     63 #define	IFADDR_TID		3
     64 #define	IFADDR_NAME		".ifaddr-eth0"
     65 
     66 ///////////////////////////////////////////////////////////////////////////
     67 
     68 static bool
     69 check_ip4(const npf_addr_t *addr, const char *ipstr)
     70 {
     71 	npf_addr_t addr_storage, *test_addr = &addr_storage;
     72 	const int alen = sizeof(struct in_addr);
     73 	test_addr->word32[0] = inet_addr(ipstr);
     74 	return memcmp(addr, test_addr, alen) == 0;
     75 }
     76 
     77 static bool
     78 ip4list_insert_lookup(npf_table_t *t, unsigned i)
     79 {
     80 	npf_addr_t addr_storage, *addr = &addr_storage;
     81 	const int alen = sizeof(struct in_addr);
     82 	int error;
     83 
     84 	addr->word32[0] = inet_addr(ip_list[i]);
     85 	error = npf_table_insert(t, alen, addr, NPF_NO_NETMASK);
     86 	CHECK_TRUE(error == 0);
     87 	error = npf_table_lookup(t, alen, addr);
     88 	CHECK_TRUE(error == 0);
     89 	return true;
     90 }
     91 
     92 static bool
     93 fill_with_ip4(npf_tableset_t *tblset)
     94 {
     95 	npf_addr_t addr_storage, *addr = &addr_storage;
     96 	const int alen = sizeof(struct in_addr);
     97 	const int nm = NPF_NO_NETMASK;
     98 
     99 	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
    100 		npf_table_t *t;
    101 		int error;
    102 
    103 		addr->word32[0] = inet_addr(ip_list[i]);
    104 
    105 		t = npf_tableset_getbyname(tblset, IPSET_NAME);
    106 		error = npf_table_insert(t, alen, addr, nm);
    107 		CHECK_TRUE(error == 0);
    108 		error = npf_table_insert(t, alen, addr, nm);
    109 		CHECK_TRUE(error != 0); // duplicate
    110 
    111 		t = npf_tableset_getbyname(tblset, LPM_NAME);
    112 		error = npf_table_insert(t, alen, addr, nm);
    113 		CHECK_TRUE(error == 0);
    114 		error = npf_table_insert(t, alen, addr, nm);
    115 		CHECK_TRUE(error != 0); // duplicate
    116 	}
    117 	return true;
    118 }
    119 
    120 static bool
    121 verify_ip4(npf_tableset_t *tblset)
    122 {
    123 	npf_addr_t addr_storage, *addr = &addr_storage;
    124 	const size_t alen = sizeof(struct in_addr);
    125 	const int nm = NPF_NO_NETMASK;
    126 	npf_table_t *t;
    127 	int error;
    128 
    129 	/* Attempt to add duplicates - should fail. */
    130 	addr->word32[0] = inet_addr(ip_list[0]);
    131 
    132 	t = npf_tableset_getbyname(tblset, IPSET_NAME);
    133 	error = npf_table_insert(t, alen, addr, nm);
    134 	CHECK_TRUE(error != 0);
    135 
    136 	t = npf_tableset_getbyname(tblset, LPM_NAME);
    137 	error = npf_table_insert(t, alen, addr, nm);
    138 	CHECK_TRUE(error != 0);
    139 
    140 	/* Match (validate) each IP entry. */
    141 	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
    142 		addr->word32[0] = inet_addr(ip_list[i]);
    143 
    144 		t = npf_tableset_getbyname(tblset, IPSET_NAME);
    145 		error = npf_table_lookup(t, alen, addr);
    146 		CHECK_TRUE(error == 0);
    147 
    148 		t = npf_tableset_getbyname(tblset, LPM_NAME);
    149 		error = npf_table_lookup(t, alen, addr);
    150 		CHECK_TRUE(error == 0);
    151 	}
    152 	return true;
    153 }
    154 
    155 static bool
    156 clear_ip4(npf_tableset_t *tblset)
    157 {
    158 	npf_addr_t addr_storage, *addr = &addr_storage;
    159 	const int alen = sizeof(struct in_addr);
    160 	const int nm = NPF_NO_NETMASK;
    161 
    162 	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
    163 		npf_table_t *t;
    164 		int error;
    165 
    166 		addr->word32[0] = inet_addr(ip_list[i]);
    167 
    168 		t = npf_tableset_getbyname(tblset, IPSET_NAME);
    169 		error = npf_table_remove(t, alen, addr, nm);
    170 		CHECK_TRUE(error == 0);
    171 
    172 		error = npf_table_remove(t, alen, addr, nm);
    173 		CHECK_TRUE(error != 0);
    174 
    175 		t = npf_tableset_getbyname(tblset, LPM_NAME);
    176 		error = npf_table_remove(t, alen, addr, nm);
    177 		CHECK_TRUE(error == 0);
    178 
    179 		error = npf_table_remove(t, alen, addr, nm);
    180 		CHECK_TRUE(error != 0);
    181 	}
    182 	return true;
    183 }
    184 
    185 ///////////////////////////////////////////////////////////////////////////
    186 
    187 static bool
    188 test_basic(npf_tableset_t *tblset)
    189 {
    190 	npf_addr_t addr_storage, *addr = &addr_storage;
    191 	const int alen = sizeof(struct in_addr);
    192 	npf_table_t *t;
    193 	int error;
    194 
    195 	/* Basic IP set. */
    196 	t = npf_table_create(IPSET_NAME, IPSET_TID, NPF_TABLE_IPSET, NULL, 0);
    197 	CHECK_TRUE(t != NULL);
    198 	error = npf_tableset_insert(tblset, t);
    199 	CHECK_TRUE(error == 0);
    200 
    201 	/* Check for double-insert. */
    202 	error = npf_tableset_insert(tblset, t);
    203 	CHECK_TRUE(error != 0);
    204 
    205 	/* Longest-prefix match (LPM). */
    206 	t = npf_table_create(LPM_NAME, LPM_TID, NPF_TABLE_LPM, NULL, 0);
    207 	CHECK_TRUE(t != NULL);
    208 	error = npf_tableset_insert(tblset, t);
    209 	CHECK_TRUE(error == 0);
    210 
    211 	/* Table for interface addresses. */
    212 	t = npf_table_create(IFADDR_NAME, IFADDR_TID, NPF_TABLE_IFADDR, NULL, 0);
    213 	CHECK_TRUE(t != NULL);
    214 	error = npf_tableset_insert(tblset, t);
    215 	CHECK_TRUE(error == 0);
    216 
    217 	/*
    218 	 * Attempt to match some non-existing entries - should fail.
    219 	 */
    220 	addr->word32[0] = inet_addr(ip_list[0]);
    221 
    222 	t = npf_tableset_getbyname(tblset, IPSET_NAME);
    223 	error = npf_table_lookup(t, alen, addr);
    224 	CHECK_TRUE(error != 0);
    225 
    226 	t = npf_tableset_getbyname(tblset, LPM_NAME);
    227 	error = npf_table_lookup(t, alen, addr);
    228 	CHECK_TRUE(error != 0);
    229 
    230 	return true;
    231 }
    232 
    233 static bool
    234 test_nocopy(npf_tableset_t *tblset)
    235 {
    236 	const int alen = sizeof(struct in_addr);
    237 	const char *tables[] = { IPSET_NAME, LPM_NAME, IFADDR_NAME };
    238 	npf_addr_t *addr, lookup_addr;
    239 
    240 	for (unsigned i = 0; i < __arraycount(tables); i++) {
    241 		npf_table_t *t;
    242 		int error;
    243 
    244 		addr = kmem_zalloc(sizeof(npf_addr_t), KM_SLEEP);
    245 		assert(addr != NULL);
    246 		addr->word32[0] = inet_addr("172.16.90.10");
    247 
    248 		t = npf_tableset_getbyname(tblset, tables[i]);
    249 		(void)npf_table_flush(t);
    250 
    251 		error = npf_table_insert(t, alen, addr, NPF_NO_NETMASK);
    252 		CHECK_TRUE(error == 0);
    253 
    254 		memcpy(&lookup_addr, addr, alen);
    255 		memset(addr, 0xa5, alen); // explicit memset
    256 
    257 		error = npf_table_lookup(t, alen, &lookup_addr);
    258 		CHECK_TRUE(error == 0);
    259 
    260 		CHECK_TRUE(*(volatile unsigned char *)addr == 0xa5);
    261 		kmem_free(addr, sizeof(npf_addr_t));
    262 	}
    263 	return true;
    264 }
    265 
    266 static bool
    267 test_ip6(npf_tableset_t *tblset)
    268 {
    269 	npf_addr_t addr_storage, *addr = &addr_storage;
    270 	const size_t alen = sizeof(struct in6_addr);
    271 	const int nm = NPF_NO_NETMASK;
    272 	npf_table_t *t;
    273 	int error;
    274 
    275 	/* IPv6 addresses. */
    276 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    277 
    278 	t = npf_tableset_getbyname(tblset, IPSET_NAME);
    279 	error = npf_table_insert(t, alen, addr, nm);
    280 	CHECK_TRUE(error == 0);
    281 	error = npf_table_lookup(t, alen, addr);
    282 	CHECK_TRUE(error == 0);
    283 	error = npf_table_remove(t, alen, addr, nm);
    284 	CHECK_TRUE(error == 0);
    285 
    286 	t = npf_tableset_getbyname(tblset, LPM_NAME);
    287 	error = npf_table_insert(t, alen, addr, nm);
    288 	CHECK_TRUE(error == 0);
    289 	error = npf_table_lookup(t, alen, addr);
    290 	CHECK_TRUE(error == 0);
    291 	error = npf_table_remove(t, alen, addr, nm);
    292 	CHECK_TRUE(error == 0);
    293 
    294 	return true;
    295 }
    296 
    297 static bool
    298 test_lpm_masks4(npf_tableset_t *tblset)
    299 {
    300 	npf_table_t *t = npf_tableset_getbyname(tblset, LPM_NAME);
    301 	npf_addr_t addr_storage, *addr = &addr_storage;
    302 	const size_t alen = sizeof(struct in_addr);
    303 	int error;
    304 
    305 	addr->word32[0] = inet_addr("172.16.90.0");
    306 	error = npf_table_insert(t, alen, addr, 25);
    307 	CHECK_TRUE(error == 0);
    308 
    309 	addr->word32[0] = inet_addr("172.16.90.126");
    310 	error = npf_table_lookup(t, alen, addr);
    311 	CHECK_TRUE(error == 0);
    312 
    313 	addr->word32[0] = inet_addr("172.16.90.128");
    314 	error = npf_table_lookup(t, alen, addr);
    315 	CHECK_TRUE(error != 0);
    316 
    317 	return true;
    318 }
    319 
    320 static bool
    321 test_lpm_masks6(npf_tableset_t *tblset)
    322 {
    323 	npf_table_t *t = npf_tableset_getbyname(tblset, LPM_NAME);
    324 	npf_addr_t addr_storage, *addr = &addr_storage;
    325 	const size_t alen = sizeof(struct in6_addr);
    326 	int error;
    327 
    328 	/*
    329 	 * 96
    330 	 */
    331 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
    332 	error = npf_table_insert(t, alen, addr, 96);
    333 	CHECK_TRUE(error == 0);
    334 
    335 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    336 	error = npf_table_lookup(t, alen, addr);
    337 	CHECK_TRUE(error == 0);
    338 
    339 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
    340 	error = npf_table_remove(t, alen, addr, 96);
    341 	CHECK_TRUE(error == 0);
    342 
    343 	/*
    344 	 * 32
    345 	 */
    346 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
    347 	error = npf_table_insert(t, alen, addr, 32);
    348 	CHECK_TRUE(error == 0);
    349 
    350 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    351 	error = npf_table_lookup(t, alen, addr);
    352 	CHECK_TRUE(error == 0);
    353 
    354 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
    355 	error = npf_table_remove(t, alen, addr, 32);
    356 	CHECK_TRUE(error == 0);
    357 
    358 	/*
    359 	 * 126
    360 	 */
    361 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
    362 	error = npf_table_insert(t, alen, addr, 126);
    363 	CHECK_TRUE(error == 0);
    364 
    365 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    366 	error = npf_table_lookup(t, alen, addr);
    367 	CHECK_TRUE(error != 0);
    368 
    369 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
    370 	error = npf_table_remove(t, alen, addr, 126);
    371 	CHECK_TRUE(error == 0);
    372 
    373 	return true;
    374 }
    375 
    376 static bool
    377 test_const_table(npf_tableset_t *tblset, void *blob, size_t size)
    378 {
    379 	npf_addr_t addr_storage, *addr = &addr_storage;
    380 	const int alen = sizeof(struct in_addr);
    381 	npf_table_t *t;
    382 	int error;
    383 
    384 	t = npf_table_create(CDB_NAME, CDB_TID, NPF_TABLE_CONST, blob, size);
    385 	CHECK_TRUE(t != NULL);
    386 
    387 	error = npf_tableset_insert(tblset, t);
    388 	CHECK_TRUE(error == 0);
    389 
    390 	addr->word32[0] = inet_addr(ip_list[0]);
    391 	error = npf_table_lookup(t, alen, addr);
    392 	CHECK_TRUE(error == 0);
    393 
    394 	for (unsigned i = 1; i < __arraycount(ip_list) - 1; i++) {
    395 		addr->word32[0] = inet_addr(ip_list[i]);
    396 		error = npf_table_lookup(t, alen, addr);
    397 		CHECK_TRUE(error != 0);
    398 	}
    399 	return true;
    400 }
    401 
    402 static bool
    403 test_ifaddr_table(npf_tableset_t *tblset)
    404 {
    405 	npf_addr_t addr_storage, *addr = &addr_storage;
    406 	npf_table_t *t = npf_tableset_getbyname(tblset, IFADDR_NAME);
    407 	int error;
    408 	bool ok;
    409 
    410 	/* Two IPv4 addresses. */
    411 	ok = ip4list_insert_lookup(t, 0);
    412 	CHECK_TRUE(ok);
    413 
    414 	ok = ip4list_insert_lookup(t, 1);
    415 	CHECK_TRUE(ok);
    416 
    417 	/* And one IPv6 address. */
    418 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    419 	error = npf_table_insert(t, sizeof(struct in6_addr), addr, NPF_NO_NETMASK);
    420 	CHECK_TRUE(error == 0);
    421 
    422 	/*
    423 	 * Get IPv4 addresses.
    424 	 */
    425 	addr = npf_table_getsome(t, sizeof(struct in_addr), 0);
    426 	ok = check_ip4(addr, "192.168.1.1");
    427 	CHECK_TRUE(ok);
    428 
    429 	addr = npf_table_getsome(t, sizeof(struct in_addr), 1);
    430 	ok = check_ip4(addr, "10.0.0.1");
    431 	CHECK_TRUE(ok);
    432 
    433 	addr = npf_table_getsome(t, sizeof(struct in_addr), 2);
    434 	ok = check_ip4(addr, "192.168.1.1");
    435 	CHECK_TRUE(ok);
    436 
    437 	return true;
    438 }
    439 
    440 static void
    441 test_ipset_gc(npf_tableset_t *tblset)
    442 {
    443 	npf_table_t *t = npf_tableset_getbyname(tblset, IPSET_NAME);
    444 	npf_t *npf = npf_getkernctx();
    445 
    446 	npf_config_enter(npf);
    447 	npf_table_gc(npf, t);
    448 	npf_table_flush(t);
    449 	npf_config_exit(npf);
    450 }
    451 
    452 bool
    453 npf_table_test(bool verbose, void *blob, size_t size)
    454 {
    455 	npf_tableset_t *tblset;
    456 	bool ok;
    457 
    458 	(void)verbose;
    459 
    460 	tblset = npf_tableset_create(4);
    461 	CHECK_TRUE(tblset != NULL);
    462 
    463 	ok = test_basic(tblset);
    464 	CHECK_TRUE(ok);
    465 
    466 	/*
    467 	 * Fill IPSET and LPM tables with IPv4 addresses.
    468 	 * Keep them in the table during the other tests.
    469 	 */
    470 	ok = fill_with_ip4(tblset);
    471 	CHECK_TRUE(ok);
    472 
    473 	ok = verify_ip4(tblset);
    474 	CHECK_TRUE(ok);
    475 
    476 	ok = test_ip6(tblset);
    477 	CHECK_TRUE(ok);
    478 
    479 	ok = test_lpm_masks4(tblset);
    480 	CHECK_TRUE(ok);
    481 
    482 	ok = test_lpm_masks6(tblset);
    483 	CHECK_TRUE(ok);
    484 
    485 	ok = test_const_table(tblset, blob, size);
    486 	CHECK_TRUE(ok);
    487 
    488 	ok = test_ifaddr_table(tblset);
    489 	CHECK_TRUE(ok);
    490 
    491 	/*
    492 	 * Remove the above IPv4 addresses -- they must have been untouched.
    493 	 */
    494 	ok = clear_ip4(tblset);
    495 	CHECK_TRUE(ok);
    496 
    497 	ok = test_nocopy(tblset);
    498 	CHECK_TRUE(ok);
    499 
    500 	test_ipset_gc(tblset);
    501 
    502 	npf_tableset_destroy(tblset);
    503 	return true;
    504 }
    505