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