diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/.gitignore | 33 | ||||
-rw-r--r-- | tests/check-addr.c | 214 | ||||
-rw-r--r-- | tests/check-all.c | 17 | ||||
-rw-r--r-- | tests/check-attr.c | 90 | ||||
-rw-r--r-- | tests/check-direct.c | 69 | ||||
-rw-r--r-- | tests/cksuite-all-addr.c | 227 | ||||
-rw-r--r-- | tests/cksuite-all-attr.c | 157 | ||||
-rw-r--r-- | tests/cksuite-all-ematch-tree-clone.c (renamed from tests/check-ematch-tree-clone.c) | 47 | ||||
-rw-r--r-- | tests/cksuite-all-netns.c | 319 | ||||
-rw-r--r-- | tests/cksuite-all.h | 12 | ||||
-rw-r--r-- | tests/nl-test-util.c | 657 | ||||
-rw-r--r-- | tests/nl-test-util.h | 400 | ||||
-rw-r--r-- | tests/test-complex-HTB-with-hash-filters.c | 8 | ||||
-rw-r--r-- | tests/test-u32-filter-with-actions.c | 10 | ||||
-rw-r--r-- | tests/util.h | 10 |
15 files changed, 1871 insertions, 399 deletions
diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index 90af67ad..00000000 --- a/tests/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -/check-all -/check-all.log -/check-all.trs -/test-*.log -/test-*.trs -/test-cache-mngr -/test-complex-HTB-with-hash-filters -/test-create-bond -/test-create-bridge -/test-create-geneve -/test-create-ifb -/test-create-ip6tnl -/test-create-ipgre -/test-create-ipgretap -/test-create-ipip -/test-create-ipvlan -/test-create-ipvti -/test-create-macsec -/test-create-macvlan -/test-create-macvtap -/test-create-sit -/test-create-veth -/test-create-vlan -/test-create-vrf -/test-create-vxlan -/test-create-xfrmi -/test-delete-link -/test-genl -/test-loopback-up-down -/test-nf-cache-mngr -/test-socket-creation -/test-suite.log -/test-u32-filter-with-actions diff --git a/tests/check-addr.c b/tests/check-addr.c deleted file mode 100644 index 48a2d931..00000000 --- a/tests/check-addr.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * tests/check-addr.c nl_addr unit tests - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2013 Thomas Graf <tgraf@suug.ch> - */ - -#include <check.h> -#include <netlink/addr.h> - -#include "util.h" - -START_TEST(addr_alloc) -{ - struct nl_addr *addr; - - addr = nl_addr_alloc(16); - fail_if(addr == NULL, - "Allocation should not return NULL"); - - fail_if(nl_addr_iszero(addr) == 0, - "New empty address should be all zeros"); - - fail_if(nl_addr_get_family(addr) != AF_UNSPEC, - "New empty address should have family AF_UNSPEC"); - - fail_if(nl_addr_get_prefixlen(addr) != 0, - "New empty address should have prefix length 0"); - - fail_if(nl_addr_shared(addr), - "New empty address should not be shared"); - - fail_if(nl_addr_get(addr) != addr, - "nl_addr_get() should return pointer to address"); - - fail_if(nl_addr_shared(addr) == 0, - "Address should be shared after call to nl_addr_get()"); - - nl_addr_put(addr); - - fail_if(nl_addr_shared(addr), - "Address should not be shared after call to nl_addr_put()"); - - fail_if(nl_addr_fill_sockaddr(addr, NULL, 0) == 0, - "Socket address filling should fail for empty address"); - - nl_addr_put(addr); -} -END_TEST - -START_TEST(addr_binary_addr) -{ - struct nl_addr *addr, *addr2; - char baddr[4] = { 0x1, 0x2, 0x3, 0x4 }; - char baddr2[6] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }; - - addr = nl_addr_alloc(4); - fail_if(addr == NULL, - "Allocation should not return NULL"); - - fail_if(nl_addr_set_binary_addr(addr, baddr, 4) < 0, - "Valid binary address should be settable"); - - fail_if(nl_addr_get_prefixlen(addr) != 0, - "Prefix length should be unchanged after nl_addr_set_binary_addr()"); - - fail_if(nl_addr_get_len(addr) != 4, - "Address length should be 4"); - - fail_if(nl_addr_set_binary_addr(addr, baddr2, 6) == 0, - "Should not be able to set binary address exceeding maximum length"); - - fail_if(nl_addr_get_len(addr) != 4, - "Address length should still be 4"); - - fail_if(nl_addr_guess_family(addr) != AF_INET, - "Binary address of length 4 should be guessed as AF_INET"); - - fail_if(memcmp(baddr, nl_addr_get_binary_addr(addr), 4) != 0, - "Binary address mismatches"); - - addr2 = nl_addr_build(AF_UNSPEC, baddr, 4); - fail_if(addr2 == NULL, - "Building of address should not fail"); - - nl_addr_set_prefixlen(addr, 32); - fail_if(nl_addr_get_prefixlen(addr) != 32, - "Prefix length should be successful changed after nl_addr_set_prefixlen()"); - - fail_if(nl_addr_cmp(addr, addr2), - "Addresses built from same binary address should match"); - - nl_addr_put(addr); - nl_addr_put(addr2); -} -END_TEST - -START_TEST(addr_parse4) -{ - struct nl_addr *addr4, *clone; - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - char *addr_str = "10.0.0.1/16"; - char buf[128]; - - fail_if(nl_addr_parse(addr_str, AF_INET6, &addr4) == 0, - "Should not be able to parse IPv4 address in IPv6 mode"); - - fail_if(nl_addr_parse(addr_str, AF_UNSPEC, &addr4) != 0, - "Should be able to parse \"%s\"", addr_str); - - fail_if(nl_addr_get_family(addr4) != AF_INET, - "Address family should be AF_INET"); - - fail_if(nl_addr_get_prefixlen(addr4) != 16, - "Prefix length should be 16"); - - fail_if(nl_addr_iszero(addr4), - "Address should not be all zeroes"); - - clone = nl_addr_clone(addr4); - fail_if(clone == NULL, - "Cloned address should not be NULL"); - - fail_if(nl_addr_cmp(addr4, clone) != 0, - "Cloned address should not mismatch original"); - - fail_if(nl_addr_fill_sockaddr(addr4, (struct sockaddr *) &sin, &len) != 0, - "Should be able to fill socketaddr"); - - fail_if(strcmp(nl_addr2str(addr4, buf, sizeof(buf)), addr_str), - "Address translated back to string does not match original"); - - nl_addr_put(addr4); - nl_addr_put(clone); -} -END_TEST - -START_TEST(addr_parse6) -{ - struct nl_addr *addr6, *clone; - struct sockaddr_in6 sin; - socklen_t len = sizeof(sin); - char *addr_str = "2001:1:2::3/64"; - char buf[128]; - - fail_if(nl_addr_parse(addr_str, AF_INET, &addr6) == 0, - "Should not be able to parse IPv6 address in IPv4 mode"); - - fail_if(nl_addr_parse(addr_str, AF_UNSPEC, &addr6) != 0, - "Should be able to parse \"%s\"", addr_str); - - fail_if(nl_addr_get_family(addr6) != AF_INET6, - "Address family should be AF_INET6"); - - fail_if(nl_addr_get_prefixlen(addr6) != 64, - "Prefix length should be 64"); - - fail_if(nl_addr_iszero(addr6), - "Address should not be all zeroes"); - - clone = nl_addr_clone(addr6); - fail_if(clone == NULL, - "Cloned address should not be NULL"); - - fail_if(nl_addr_cmp(addr6, clone) != 0, - "Cloned address should not mismatch original"); - - fail_if(nl_addr_fill_sockaddr(addr6, (struct sockaddr *) &sin, &len) != 0, - "Should be able to fill socketaddr"); - - fail_if(strcmp(nl_addr2str(addr6, buf, sizeof(buf)), addr_str), - "Address translated back to string does not match original"); - - nl_addr_put(addr6); - nl_addr_put(clone); -} -END_TEST - -START_TEST(addr_info) -{ - struct nl_addr *addr; - char *addr_str = "127.0.0.1"; - struct addrinfo *result; - - fail_if(nl_addr_parse(addr_str, AF_UNSPEC, &addr) != 0, - "Parsing of valid address should not fail"); - - fail_if(nl_addr_info(addr, &result) != 0, - "getaddrinfo() on loopback address should work"); - - freeaddrinfo(result); - nl_addr_put(addr); -} -END_TEST - -Suite *make_nl_addr_suite(void) -{ - Suite *suite = suite_create("Abstract addresses"); - - TCase *tc_addr = tcase_create("Core"); - tcase_add_test(tc_addr, addr_alloc); - tcase_add_test(tc_addr, addr_binary_addr); - tcase_add_test(tc_addr, addr_parse4); - tcase_add_test(tc_addr, addr_parse6); - tcase_add_test(tc_addr, addr_info); - suite_add_tcase(suite, tc_addr); - - return suite; -} diff --git a/tests/check-all.c b/tests/check-all.c index 7b738daa..aff16cbb 100644 --- a/tests/check-all.c +++ b/tests/check-all.c @@ -1,17 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * tests/check-all.c overall unit test program - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2013 Thomas Graf <tgraf@suug.ch> */ #include <check.h> -#include "util.h" +#include "cksuite-all.h" static Suite *main_suite(void) { @@ -24,16 +18,13 @@ int main(int argc, char *argv[]) { SRunner *runner; int nfailed; - - runner = srunner_create(main_suite()); - /* Add testsuites below */ + runner = srunner_create(main_suite()); srunner_add_suite(runner, make_nl_addr_suite()); srunner_add_suite(runner, make_nl_attr_suite()); srunner_add_suite(runner, make_nl_ematch_tree_clone_suite()); - - /* Do not add testsuites below this line */ + srunner_add_suite(runner, make_nl_netns_suite()); srunner_run_all(runner, CK_ENV); diff --git a/tests/check-attr.c b/tests/check-attr.c deleted file mode 100644 index 0390997c..00000000 --- a/tests/check-attr.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * tests/check-attr.c nla_attr unit tests - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2013 Thomas Graf <tgraf@suug.ch> - */ - -#include "util.h" -#include <netlink/attr.h> -#include <netlink/msg.h> - -#include <linux/netlink.h> - -START_TEST(attr_size) -{ - fail_if(nla_attr_size(0) != NLA_HDRLEN, - "Length of empty attribute should match header size"); - fail_if(nla_attr_size(1) != NLA_HDRLEN + 1, - "Length of 1 bytes payload should be NLA_HDRLEN + 1"); - fail_if(nla_attr_size(2) != NLA_HDRLEN + 2, - "Length of 2 bytes payload should be NLA_HDRLEN + 2"); - fail_if(nla_attr_size(3) != NLA_HDRLEN + 3, - "Length of 3 bytes payload should be NLA_HDRLEN + 3"); - fail_if(nla_attr_size(4) != NLA_HDRLEN + 4, - "Length of 4 bytes payload should be NLA_HDRLEN + 4"); - - fail_if(nla_total_size(1) != NLA_HDRLEN + 4, - "Total size of 1 bytes payload should result in 8 bytes"); - fail_if(nla_total_size(2) != NLA_HDRLEN + 4, - "Total size of 2 bytes payload should result in 8 bytes"); - fail_if(nla_total_size(3) != NLA_HDRLEN + 4, - "Total size of 3 bytes payload should result in 8 bytes"); - fail_if(nla_total_size(4) != NLA_HDRLEN + 4, - "Total size of 4 bytes payload should result in 8 bytes"); - - fail_if(nla_padlen(1) != 3, - "2 bytes of payload should result in 3 padding bytes"); - fail_if(nla_padlen(2) != 2, - "2 bytes of payload should result in 2 padding bytes"); - fail_if(nla_padlen(3) != 1, - "3 bytes of payload should result in 1 padding bytes"); - fail_if(nla_padlen(4) != 0, - "4 bytes of payload should result in 0 padding bytes"); - fail_if(nla_padlen(5) != 3, - "5 bytes of payload should result in 3 padding bytes"); -} -END_TEST - -START_TEST(msg_construct) -{ - struct nl_msg *msg; - struct nlmsghdr *nlh; - struct nlattr *a; - int i, rem; - - msg = nlmsg_alloc(); - fail_if(!msg, "Unable to allocate netlink message"); - - for (i = 1; i < 256; i++) { - fail_if(nla_put_u32(msg, i, i+1) != 0, - "Unable to add attribute %d", i); - } - - nlh = nlmsg_hdr(msg); - i = 1; - nlmsg_for_each_attr(a, nlh, 0, rem) { - fail_if(nla_type(a) != i, "Expected attribute %d", i); - i++; - fail_if(nla_get_u32(a) != i, "Expected attribute value %d", i); - } - - nlmsg_free(msg); -} -END_TEST - -Suite *make_nl_attr_suite(void) -{ - Suite *suite = suite_create("Netlink attributes"); - - TCase *nl_attr = tcase_create("Core"); - tcase_add_test(nl_attr, attr_size); - tcase_add_test(nl_attr, msg_construct); - suite_add_tcase(suite, nl_attr); - - return suite; -} diff --git a/tests/check-direct.c b/tests/check-direct.c new file mode 100644 index 00000000..f40bcee9 --- /dev/null +++ b/tests/check-direct.c @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ + +#include <check.h> + +#include "linux/snmp.h" +#include "netlink-private/utils.h" +#include "netlink-private/route/utils.h" + +#include "netlink/route/link.h" + +START_TEST(static_checks) +{ + int i, j; + char strbuf[100]; + + _NL_STATIC_ASSERT(RTNL_LINK_RX_PACKETS == 0); + assert(_nltst_map_stat_id_from_IPSTATS_MIB_v2[0] == + RTNL_LINK_RX_PACKETS); + for (i = 1; i < __IPSTATS_MIB_MAX; i++) { + assert(_nltst_map_stat_id_from_IPSTATS_MIB_v2[i] > 0); + assert(_nltst_map_stat_id_from_IPSTATS_MIB_v2[i] < + __RTNL_LINK_STATS_MAX); + for (j = 1; j < i; j++) + assert(_nltst_map_stat_id_from_IPSTATS_MIB_v2[i] != + _nltst_map_stat_id_from_IPSTATS_MIB_v2[j]); + } + + for (i = 0; i <= RTNL_LINK_STATS_MAX + 1; i++) { + const char *s; + + s = rtnl_link_stat2str(i, strbuf, sizeof(strbuf)); + assert(s); + assert(s == strbuf); + assert(strlen(s) < sizeof(strbuf)); + if (strncmp(s, "0x", 2) == 0) { + assert(i == RTNL_LINK_STATS_MAX + 1); + ck_assert_int_eq(strtoll(&s[2], NULL, 16), i); + } else + ck_assert_int_le(i, RTNL_LINK_STATS_MAX); + ck_assert_int_eq(i, rtnl_link_str2stat(s)); + } +} +END_TEST + +static Suite *make_suite(void) +{ + Suite *suite = suite_create("Direct"); + TCase *tc = tcase_create("Core"); + + tcase_add_test(tc, static_checks); + suite_add_tcase(suite, tc); + return suite; +} + +int main(int argc, char *argv[]) +{ + SRunner *runner; + int nfailed; + + runner = srunner_create(suite_create("main")); + + srunner_add_suite(runner, make_suite()); + + srunner_run_all(runner, CK_ENV); + + nfailed = srunner_ntests_failed(runner); + srunner_free(runner); + return nfailed != 0; +} diff --git a/tests/cksuite-all-addr.c b/tests/cksuite-all-addr.c new file mode 100644 index 00000000..f395351b --- /dev/null +++ b/tests/cksuite-all-addr.c @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/* + * Copyright (c) 2013 Thomas Graf <tgraf@suug.ch> + */ + +#include <check.h> +#include <netlink/addr.h> +#include <netlink/route/addr.h> + +#include "cksuite-all.h" + +START_TEST(addr_alloc) +{ + struct nl_addr *addr; + + addr = nl_addr_alloc(16); + ck_assert_msg(addr, "Allocation should not return NULL"); + + ck_assert_msg(nl_addr_iszero(addr) != 0, + "New empty address should be all zeros"); + + ck_assert_msg(nl_addr_get_family(addr) == AF_UNSPEC, + "New empty address should have family AF_UNSPEC"); + + ck_assert_msg(nl_addr_get_prefixlen(addr) == 0, + "New empty address should have prefix length 0"); + + ck_assert_msg(!nl_addr_shared(addr), + "New empty address should not be shared"); + + ck_assert_msg(nl_addr_get(addr) == addr, + "nl_addr_get() should return pointer to address"); + + ck_assert_msg(nl_addr_shared(addr) != 0, + "Address should be shared after call to nl_addr_get()"); + + nl_addr_put(addr); + + ck_assert_msg( + !nl_addr_shared(addr), + "Address should not be shared after call to nl_addr_put()"); + + ck_assert_msg(nl_addr_fill_sockaddr(addr, NULL, 0) != 0, + "Socket address filling should fail for empty address"); + + nl_addr_put(addr); +} +END_TEST + +START_TEST(addr_binary_addr) +{ + struct nl_addr *addr, *addr2; + char baddr[4] = { 0x1, 0x2, 0x3, 0x4 }; + char baddr2[6] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }; + + addr = nl_addr_alloc(4); + ck_assert_msg(addr != NULL, "Allocation should not return NULL"); + + ck_assert_msg(nl_addr_set_binary_addr(addr, baddr, 4) >= 0, + "Valid binary address should be settable"); + + ck_assert_msg( + nl_addr_get_prefixlen(addr) == 0, + "Prefix length should be unchanged after nl_addr_set_binary_addr()"); + + ck_assert_msg(nl_addr_get_len(addr) == 4, "Address length should be 4"); + + ck_assert_msg( + nl_addr_set_binary_addr(addr, baddr2, 6) != 0, + "Should not be able to set binary address exceeding maximum length"); + + ck_assert_msg(nl_addr_get_len(addr) == 4, + "Address length should still be 4"); + + ck_assert_msg( + nl_addr_guess_family(addr) == AF_INET, + "Binary address of length 4 should be guessed as AF_INET"); + + ck_assert_msg(memcmp(baddr, nl_addr_get_binary_addr(addr), 4) == 0, + "Binary address mismatches"); + + addr2 = nl_addr_build(AF_UNSPEC, baddr, 4); + ck_assert_msg(addr2 != NULL, "Building of address should not fail"); + + nl_addr_set_prefixlen(addr, 32); + ck_assert_msg( + nl_addr_get_prefixlen(addr) == 32, + "Prefix length should be successful changed after nl_addr_set_prefixlen()"); + + ck_assert_msg(!nl_addr_cmp(addr, addr2), + "Addresses built from same binary address should match"); + + nl_addr_put(addr); + nl_addr_put(addr2); +} +END_TEST + +START_TEST(addr_parse4) +{ + struct nl_addr *addr4, *clone; + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + char *addr_str = "10.0.0.1/16"; + char buf[128]; + + ck_assert_msg(nl_addr_parse(addr_str, AF_INET6, &addr4) != 0, + "Should not be able to parse IPv4 address in IPv6 mode"); + + ck_assert_msg(nl_addr_parse(addr_str, AF_UNSPEC, &addr4) == 0, + "Should be able to parse \"%s\"", addr_str); + + ck_assert_msg(nl_addr_get_family(addr4) == AF_INET, + "Address family should be AF_INET"); + + ck_assert_msg(nl_addr_get_prefixlen(addr4) == 16, + "Prefix length should be 16"); + + ck_assert_msg(!nl_addr_iszero(addr4), + "Address should not be all zeroes"); + + clone = nl_addr_clone(addr4); + ck_assert_msg(clone != NULL, "Cloned address should not be NULL"); + + ck_assert_msg(nl_addr_cmp(addr4, clone) == 0, + "Cloned address should not mismatch original"); + + ck_assert_msg(nl_addr_fill_sockaddr(addr4, (struct sockaddr *)&sin, + &len) == 0, + "Should be able to fill socketaddr"); + + ck_assert_msg( + !strcmp(nl_addr2str(addr4, buf, sizeof(buf)), addr_str), + "Address translated back to string does not match original"); + + nl_addr_put(addr4); + nl_addr_put(clone); +} +END_TEST + +START_TEST(addr_parse6) +{ + struct nl_addr *addr6, *clone; + struct sockaddr_in6 sin; + socklen_t len = sizeof(sin); + char *addr_str = "2001:1:2::3/64"; + char buf[128]; + + ck_assert_msg(nl_addr_parse(addr_str, AF_INET, &addr6) != 0, + "Should not be able to parse IPv6 address in IPv4 mode"); + + ck_assert_msg(nl_addr_parse(addr_str, AF_UNSPEC, &addr6) == 0, + "Should be able to parse \"%s\"", addr_str); + + ck_assert_msg(nl_addr_get_family(addr6) == AF_INET6, + "Address family should be AF_INET6"); + + ck_assert_msg(nl_addr_get_prefixlen(addr6) == 64, + "Prefix length should be 64"); + + ck_assert_msg(!nl_addr_iszero(addr6), + "Address should not be all zeroes"); + + clone = nl_addr_clone(addr6); + ck_assert_msg(clone != NULL, "Cloned address should not be NULL"); + + ck_assert_msg(nl_addr_cmp(addr6, clone) == 0, + "Cloned address should not mismatch original"); + + ck_assert_msg(nl_addr_fill_sockaddr(addr6, (struct sockaddr *)&sin, + &len) == 0, + "Should be able to fill socketaddr"); + + ck_assert_msg( + !strcmp(nl_addr2str(addr6, buf, sizeof(buf)), addr_str), + "Address translated back to string does not match original"); + + nl_addr_put(addr6); + nl_addr_put(clone); +} +END_TEST + +START_TEST(addr_info) +{ + struct nl_addr *addr; + char *addr_str = "127.0.0.1"; + struct addrinfo *result; + + ck_assert_msg(nl_addr_parse(addr_str, AF_UNSPEC, &addr) == 0, + "Parsing of valid address should not fail"); + + ck_assert_msg(nl_addr_info(addr, &result) == 0, + "getaddrinfo() on loopback address should work"); + + freeaddrinfo(result); + nl_addr_put(addr); +} +END_TEST + +START_TEST(addr_flags2str) +{ + int ifa_flags = IFA_F_TENTATIVE | IFA_F_DADFAILED; + int ifa_flags2; + char buf[128]; + + rtnl_addr_flags2str(ifa_flags, buf, sizeof(buf)); + ck_assert_str_eq(buf, "dadfailed,tentative"); + + ifa_flags2 = rtnl_addr_str2flags(buf); + ck_assert_int_eq(ifa_flags2, ifa_flags); +} +END_TEST + +Suite *make_nl_addr_suite(void) +{ + Suite *suite = suite_create("Abstract addresses"); + TCase *tc = tcase_create("Core"); + + tcase_add_test(tc, addr_alloc); + tcase_add_test(tc, addr_binary_addr); + tcase_add_test(tc, addr_parse4); + tcase_add_test(tc, addr_parse6); + tcase_add_test(tc, addr_info); + tcase_add_test(tc, addr_flags2str); + suite_add_tcase(suite, tc); + + return suite; +} diff --git a/tests/cksuite-all-attr.c b/tests/cksuite-all-attr.c new file mode 100644 index 00000000..824a5960 --- /dev/null +++ b/tests/cksuite-all-attr.c @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/* + * Copyright (c) 2013 Thomas Graf <tgraf@suug.ch> + */ + +#include <linux/netlink.h> +#include <linux/if_ether.h> + +#include "cksuite-all.h" +#include "netlink/attr.h" +#include "netlink/msg.h" +#include "netlink/route/cls/u32.h" +#include "netlink-private/route/tc-api.h" +#include "netlink-private/nl-auto.h" + +START_TEST(attr_size) +{ + ck_assert_msg(nla_attr_size(0) == NLA_HDRLEN, + "Length of empty attribute should match header size"); + ck_assert_msg(nla_attr_size(1) == NLA_HDRLEN + 1, + "Length of 1 bytes payload should be NLA_HDRLEN + 1"); + ck_assert_msg(nla_attr_size(2) == NLA_HDRLEN + 2, + "Length of 2 bytes payload should be NLA_HDRLEN + 2"); + ck_assert_msg(nla_attr_size(3) == NLA_HDRLEN + 3, + "Length of 3 bytes payload should be NLA_HDRLEN + 3"); + ck_assert_msg(nla_attr_size(4) == NLA_HDRLEN + 4, + "Length of 4 bytes payload should be NLA_HDRLEN + 4"); + + ck_assert_msg(nla_total_size(1) == NLA_HDRLEN + 4, + "Total size of 1 bytes payload should result in 8 bytes"); + ck_assert_msg(nla_total_size(2) == NLA_HDRLEN + 4, + "Total size of 2 bytes payload should result in 8 bytes"); + ck_assert_msg(nla_total_size(3) == NLA_HDRLEN + 4, + "Total size of 3 bytes payload should result in 8 bytes"); + ck_assert_msg(nla_total_size(4) == NLA_HDRLEN + 4, + "Total size of 4 bytes payload should result in 8 bytes"); + + ck_assert_msg(nla_padlen(1) == 3, + "2 bytes of payload should result in 3 padding bytes"); + ck_assert_msg(nla_padlen(2) == 2, + "2 bytes of payload should result in 2 padding bytes"); + ck_assert_msg(nla_padlen(3) == 1, + "3 bytes of payload should result in 1 padding bytes"); + ck_assert_msg(nla_padlen(4) == 0, + "4 bytes of payload should result in 0 padding bytes"); + ck_assert_msg(nla_padlen(5) == 3, + "5 bytes of payload should result in 3 padding bytes"); +} +END_TEST + +START_TEST(msg_construct) +{ + struct nl_msg *msg; + struct nlmsghdr *nlh; + struct nlattr *a; + int i, rem; + + msg = nlmsg_alloc(); + ck_assert_msg(msg, "Unable to allocate netlink message"); + + for (i = 1; i < 256; i++) { + ck_assert_msg(nla_put_u32(msg, i, i + 1) == 0, + "Unable to add attribute %d", i); + } + + nlh = nlmsg_hdr(msg); + i = 1; + nlmsg_for_each_attr (a, nlh, 0, rem) { + ck_assert_msg(nla_type(a) == i, "Expected attribute %d", i); + i++; + ck_assert_msg(nla_get_u32(a) == i, + "Expected attribute value %d", i); + } + + nlmsg_free(msg); +} +END_TEST + +START_TEST(clone_cls_u32) +{ + _nl_auto_rtnl_link struct rtnl_link *link = NULL; + _nl_auto_rtnl_cls struct rtnl_cls *cls = NULL; + _nl_auto_rtnl_cls struct rtnl_cls *cls2 = NULL; + int r; + const uint32_t direction = 16; + + link = rtnl_link_alloc(); + ck_assert(link); + + rtnl_link_set_ifindex(link, 5); + + cls = rtnl_cls_alloc(); + ck_assert(cls); + + rtnl_tc_set_link(TC_CAST(cls), link); + + r = rtnl_tc_set_kind(TC_CAST(cls), "u32"); + ck_assert(r == 0); + + rtnl_cls_set_prio(cls, 1); + rtnl_cls_set_protocol(cls, ETH_P_IP); + + rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(1, 0)); + + rtnl_u32_set_hashtable(cls, 5); + + rtnl_u32_add_key_uint32(cls, 0x0a000914, 0xffffffff, direction, 0); + + rtnl_u32_set_hashmask(cls, 0xff000000, direction); + + rtnl_u32_add_mark(cls, 55, 66); + + rtnl_u32_set_link(cls, 44); + + cls2 = (struct rtnl_cls *)nl_object_clone((struct nl_object *)cls); + ck_assert(cls2); +} +END_TEST + +/*****************************************************************************/ + +START_TEST(test_nltst_strtok) +{ +#define _assert_strtok(str, ...) \ + do { \ + const char *const _expected[] = { NULL, ##__VA_ARGS__, NULL }; \ + _nltst_auto_strfreev char **_tokens = NULL; \ + \ + _tokens = _nltst_strtokv(str); \ + _nltst_assert_strv_equal(_tokens, &_expected[1]); \ + } while (0) + + _assert_strtok(""); + _assert_strtok(" \n"); + _assert_strtok("a", "a"); + _assert_strtok(" a ", "a"); + _assert_strtok(" a\\ b", "a\\ ", "b"); + _assert_strtok(" a\\ b cc\\d", "a\\ ", "b", "cc\\d"); + _assert_strtok(" a\\ b\\ cc\\d", "a\\ ", "b\\ ", "cc\\d"); +} +END_TEST + +/*****************************************************************************/ + +Suite *make_nl_attr_suite(void) +{ + Suite *suite = suite_create("Netlink attributes"); + TCase *tc = tcase_create("Core"); + + tcase_add_test(tc, attr_size); + tcase_add_test(tc, msg_construct); + tcase_add_test(tc, clone_cls_u32); + tcase_add_test(tc, test_nltst_strtok); + suite_add_tcase(suite, tc); + + return suite; +} diff --git a/tests/check-ematch-tree-clone.c b/tests/cksuite-all-ematch-tree-clone.c index 9c35c52e..f9d17a98 100644 --- a/tests/check-ematch-tree-clone.c +++ b/tests/cksuite-all-ematch-tree-clone.c @@ -1,23 +1,20 @@ -#include <netlink-private/types.h> -#include <netlink/route/cls/ematch.h> - #include <linux/netlink.h> - #include <stdio.h> #include <time.h> - #include <check.h> -#include "util.h" -#define MAX_DEPTH 6 -#define MAX_CHILDREN 5 +#include "netlink-private/types.h" +#include "netlink/route/cls/ematch.h" +#include "cksuite-all.h" +#include "netlink-private/nl-auto.h" + +#define MAX_DEPTH 6 +#define MAX_CHILDREN 5 static int current_depth = 0; static int id = 1; static long long array_size = 0; -static int *src_result = NULL, *dst_result = NULL; - static long long my_pow(long long x, long long y) { int ret = x; @@ -28,7 +25,7 @@ static long long my_pow(long long x, long long y) if (y < 0 || x == 0) return 0; - while(--y) { + while (--y) { ret *= x; } @@ -79,7 +76,7 @@ static void dump_ematch_list(struct nl_list_head *head, int *result, int *index) { struct rtnl_ematch *pos = NULL; - nl_list_for_each_entry(pos, head, e_list) { + nl_list_for_each_entry (pos, head, e_list) { if (!nl_list_empty(&pos->e_childs)) dump_ematch_list(&pos->e_childs, result, index); result[*index] = pos->e_id; @@ -87,7 +84,8 @@ static void dump_ematch_list(struct nl_list_head *head, int *result, int *index) } } -static void dump_ematch_tree(struct rtnl_ematch_tree *tree, int *result, int *index) +static void dump_ematch_tree(struct rtnl_ematch_tree *tree, int *result, + int *index) { if (!tree) return; @@ -107,8 +105,12 @@ static int compare(int *r1, int *r2, int len) START_TEST(ematch_tree_clone) { - struct rtnl_ematch_tree *src = NULL, *dst = NULL; - int i = 0, j = 0; + _nl_auto_rtnl_ematch_tree struct rtnl_ematch_tree *src = NULL; + _nl_auto_rtnl_ematch_tree struct rtnl_ematch_tree *dst = NULL; + _nl_auto_free int *src_result = NULL; + _nl_auto_free int *dst_result = NULL; + int i = 0; + int j = 0; array_size = (MAX_DEPTH * my_pow(MAX_CHILDREN, MAX_DEPTH)) / 2; src_result = calloc(4, array_size); @@ -122,22 +124,19 @@ START_TEST(ematch_tree_clone) dst = rtnl_ematch_tree_clone(src); dump_ematch_tree(dst, dst_result, &j); - fail_if(!dst); - fail_if(i != j); - fail_if(compare(src_result, dst_result, i)); - - free(src_result); - free(dst_result); + ck_assert(dst); + ck_assert(i == j); + ck_assert(!compare(src_result, dst_result, i)); } END_TEST Suite *make_nl_ematch_tree_clone_suite(void) { Suite *suite = suite_create("Clone ematch tree"); + TCase *tc = tcase_create("Core"); - TCase *ematch_tree = tcase_create("Core"); - tcase_add_test(ematch_tree, ematch_tree_clone); - suite_add_tcase(suite, ematch_tree); + tcase_add_test(tc, ematch_tree_clone); + suite_add_tcase(suite, tc); return suite; } diff --git a/tests/cksuite-all-netns.c b/tests/cksuite-all-netns.c new file mode 100644 index 00000000..97f3a702 --- /dev/null +++ b/tests/cksuite-all-netns.c @@ -0,0 +1,319 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/* + * Author: Susant Sahani <susant@redhat.com> + * Copyright (c) 2018 Red Hat, Inc. + */ + +#include <stdlib.h> +#include <stdbool.h> +#include <linux/netlink.h> + +#include "netlink-private/utils.h" +#include "netlink/route/link.h" +#include "netlink/route/link/sit.h" +#include <netlink/route/link/bonding.h> +#include <netlink/route/link/bridge.h> +#include <netlink/route/link/ip6tnl.h> +#include <netlink/route/link/ipgre.h> +#include <netlink/route/link/ipip.h> +#include <netlink/route/link/ipvlan.h> +#include <netlink/route/link/ipvti.h> +#include <netlink/route/link/macsec.h> +#include <netlink/route/link/macvlan.h> +#include <netlink/route/link/macvtap.h> +#include <netlink/route/link/veth.h> +#include <netlink/route/link/vlan.h> +#include <netlink/route/link/vrf.h> +#include <netlink/route/link/vxlan.h> + +#include "cksuite-all.h" + +/*****************************************************************************/ + +static void _nltst_delete_link2(const char *ifname) +{ + _nltst_delete_link(NULL, ifname); +} +#define _nltst_auto_delete_link _nl_auto(_nltst_auto_delete_link_fcn) +_NL_AUTO_DEFINE_FCN_TYPED0(const char *, _nltst_auto_delete_link_fcn, + _nltst_delete_link2); + +/*****************************************************************************/ + +START_TEST(cache_and_clone) +{ + _nl_auto_nl_socket struct nl_sock *sk = NULL; + _nl_auto_nl_cache struct nl_cache *link_cache = NULL; + _nl_auto_free struct nl_object **links_all = NULL; + static const struct { + const char *ifname; + const char *kind; + bool add; + } links[] = { + { + .ifname = "xbr0", + .kind = "bridge", + .add = true, + }, + { + .ifname = "xdummy0", + .kind = "dummy", + .add = true, + }, + { + .ifname = "xbond0", + .kind = "bond", + .add = true, + }, + { + .ifname = "lo", + .kind = NULL, + .add = false, + }, + }; + int i; + int r; + + for (i = 0; i < _NL_N_ELEMENTS(links); i++) { + if (links[i].add) + _nltst_add_link(NULL, links[i].ifname, links[i].kind, + NULL); + } + + sk = _nltst_socket(NETLINK_ROUTE); + + r = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache); + ck_assert_int_eq(r, 0); + + r = nl_cache_refill(sk, link_cache); + ck_assert_int_eq(r, 0); + + for (i = 0; i < _NL_N_ELEMENTS(links); i++) { + _nl_auto_rtnl_link struct rtnl_link *link_clone = NULL; + struct rtnl_link *link; + + link = _nltst_cache_get_link(link_cache, links[i].ifname); + ck_assert_ptr_nonnull(link); + + ck_assert_str_eq(rtnl_link_get_name(link), links[i].ifname); + + if (_nl_streq(links[i].ifname, "lo")) + ck_assert_int_eq(rtnl_link_get_ifindex(link), 1); + else + ck_assert_int_gt(rtnl_link_get_ifindex(link), 1); + + link_clone = (struct rtnl_link *)nl_object_clone( + (struct nl_object *)link); + ck_assert(link_clone); + + _nltst_object_identical(link, link_clone); + } + + links_all = _nltst_cache_get_all(link_cache, NULL); + for (i = 0; links_all[i]; i++) { + struct rtnl_link *link = (struct rtnl_link *)links_all[i]; + _nl_auto_rtnl_link struct rtnl_link *link_clone = NULL; + + link_clone = (struct rtnl_link *)nl_object_clone( + (struct nl_object *)link); + ck_assert(link_clone); + + _nltst_object_identical(link, link_clone); + } +} +END_TEST + +/*****************************************************************************/ + +START_TEST(test_create_iface) +{ + const int TEST_IDX = _i; + _nl_auto_nl_socket struct nl_sock *sk = _nltst_socket(NETLINK_ROUTE); + _nl_auto_rtnl_link struct rtnl_link *link = NULL; + _nl_auto_rtnl_link struct rtnl_link *link2 = NULL; + _nl_auto_rtnl_link struct rtnl_link *peer = NULL; + _nltst_auto_delete_link const char *IFNAME_DUMMY = NULL; + _nltst_auto_delete_link const char *IFNAME = "ifname"; + int ifindex_dummy; + uint32_t u32; + int r; + + switch (TEST_IDX) { + case 0: + link = _nltst_assert(rtnl_link_bridge_alloc()); + rtnl_link_set_name(link, IFNAME); + break; + case 1: + link = _nltst_assert(rtnl_link_vxlan_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_vxlan_set_id(link, 128)); + break; + case 2: + link = _nltst_assert(rtnl_link_alloc()); + rtnl_link_set_type(link, "ifb"); + rtnl_link_set_name(link, IFNAME); + break; + case 3: + link = _nltst_assert(rtnl_link_ipgre_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_ipgre_set_local( + link, _nltst_inet4("192.168.254.12"))); + _nltst_assert_retcode(rtnl_link_ipgre_set_remote( + link, _nltst_inet4("192.168.254.13"))); + _nltst_assert_retcode(rtnl_link_ipgre_set_ttl(link, 64)); + break; + case 4: + link = _nltst_assert(rtnl_link_ip6_tnl_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_ip6_tnl_set_local( + link, _nltst_inet6p("2607:f0d0:1002:51::4"))); + _nltst_assert_retcode(rtnl_link_ip6_tnl_set_remote( + link, _nltst_inet6p("2607:f0d0:1002:52::5"))); + break; + case 5: + link = _nltst_assert(rtnl_link_ipgretap_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_ipgre_set_local( + link, _nltst_inet4("10.211.55.10"))); + _nltst_assert_retcode(rtnl_link_ipgre_set_remote( + link, _nltst_inet4("10.133.6.33"))); + _nltst_assert_retcode(rtnl_link_ipgre_set_ttl(link, 64)); + break; + case 6: + link = _nltst_assert(rtnl_link_ipvti_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_ipvti_set_local( + link, _nltst_inet4("192.168.254.12"))); + _nltst_assert_retcode(rtnl_link_ipvti_set_remote( + link, _nltst_inet4("192.168.254.13"))); + break; + case 7: + link = _nltst_assert(rtnl_link_sit_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_sit_set_local( + link, _nltst_inet4("192.168.254.12"))); + _nltst_assert_retcode(rtnl_link_sit_set_remote( + link, _nltst_inet4("192.168.254.13"))); + _nltst_assert_retcode(rtnl_link_sit_set_ttl(link, 64)); + break; + case 8: + link = _nltst_assert(rtnl_link_ipip_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_ipip_set_local( + link, _nltst_inet4("192.168.254.12"))); + _nltst_assert_retcode(rtnl_link_ipip_set_remote( + link, _nltst_inet4("192.168.254.13"))); + _nltst_assert_retcode(rtnl_link_ipip_set_ttl(link, 64)); + break; + case 9: + link = _nltst_assert(rtnl_link_bond_alloc()); + rtnl_link_set_name(link, IFNAME); + break; + case 10: + IFNAME_DUMMY = "ci-dummy"; + _nltst_add_link(sk, IFNAME_DUMMY, "dummy", &ifindex_dummy); + + link = _nltst_assert(rtnl_link_macvtap_alloc()); + rtnl_link_set_link(link, ifindex_dummy); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_macvtap_set_mode( + link, rtnl_link_macvtap_str2mode("bridge"))); + break; + case 11: + IFNAME_DUMMY = "ci-dummy"; + _nltst_add_link(sk, IFNAME_DUMMY, "dummy", &ifindex_dummy); + + link = _nltst_assert(rtnl_link_macvlan_alloc()); + rtnl_link_set_link(link, ifindex_dummy); + rtnl_link_set_name(link, IFNAME); + break; + case 12: + IFNAME_DUMMY = "ci-dummy"; + _nltst_add_link(sk, IFNAME_DUMMY, "dummy", &ifindex_dummy); + + link = _nltst_assert(rtnl_link_vlan_alloc()); + rtnl_link_set_link(link, ifindex_dummy); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_vlan_set_id(link, 10)); + break; + case 13: + IFNAME_DUMMY = "ci-dummy"; + _nltst_add_link(sk, IFNAME_DUMMY, "dummy", &ifindex_dummy); + + link = _nltst_assert(rtnl_link_macsec_alloc()); + rtnl_link_set_link(link, ifindex_dummy); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_macsec_set_port(link, 10)); + _nltst_assert_retcode(rtnl_link_macsec_set_encrypt(link, 1)); + _nltst_assert_retcode( + rtnl_link_macsec_set_replay_protect(link, 1)); + _nltst_assert_retcode(rtnl_link_macsec_set_window(link, 200)); + break; + case 14: + IFNAME_DUMMY = "ci-dummy"; + _nltst_add_link(sk, IFNAME_DUMMY, "dummy", &ifindex_dummy); + + link = _nltst_assert(rtnl_link_ipvlan_alloc()); + rtnl_link_set_link(link, ifindex_dummy); + _nltst_assert_retcode(rtnl_link_ipvlan_set_mode( + link, rtnl_link_ipvlan_str2mode("l2"))); + rtnl_link_set_name(link, IFNAME); + break; + case 15: + link = _nltst_assert(rtnl_link_vrf_alloc()); + rtnl_link_set_name(link, IFNAME); + _nltst_assert_retcode(rtnl_link_vrf_set_tableid(link, 10)); + break; + case 16: { + link = _nltst_assert(rtnl_link_veth_alloc()); + rtnl_link_set_name(link, IFNAME); + peer = _nltst_assert(rtnl_link_veth_get_peer(link)); + rtnl_link_set_name(peer, "ci-veth-peer"); + } break; + default: + ck_assert_msg(0, "unexpected TEST_IDX=%d", _i); + break; + } + + r = rtnl_link_add(sk, link, NLM_F_CREATE); + if (r == -NLE_OPNOTSUPP) { + /* Hm, no kernel module? Skip the test. */ + _nltst_assert_link_not_exists(IFNAME); + IFNAME = NULL; + return; + } + _nltst_assert_retcode(r); + + _nltst_assert_link_exists(IFNAME); + + switch (TEST_IDX) { + case 15: + _nltst_get_link(sk, IFNAME, NULL, &link2); + _nltst_assert_retcode(rtnl_link_vrf_get_tableid(link2, &u32)); + ck_assert_int_eq(u32, 10); + break; + case 16: + _nltst_assert_link_exists("ci-veth-peer"); + if (_nltst_rand_bool()) + IFNAME = "ci-veth-peer"; + break; + } +} +END_TEST + +/*****************************************************************************/ + +Suite *make_nl_netns_suite(void) +{ + Suite *suite = suite_create("netns"); + TCase *tc = tcase_create("Core"); + + tcase_add_checked_fixture(tc, nltst_netns_fixture_setup, + nltst_netns_fixture_teardown); + tcase_add_test(tc, cache_and_clone); + tcase_add_loop_test(tc, test_create_iface, 0, 17); + + suite_add_tcase(suite, tc); + + return suite; +} diff --git a/tests/cksuite-all.h b/tests/cksuite-all.h new file mode 100644 index 00000000..c4b1d8e5 --- /dev/null +++ b/tests/cksuite-all.h @@ -0,0 +1,12 @@ +#ifndef __LIBNL3_TESTS_CHECK_ALL_H__ +#define __LIBNL3_TESTS_CHECK_ALL_H__ + +#include <check.h> +#include "nl-test-util.h" + +Suite *make_nl_attr_suite(void); +Suite *make_nl_addr_suite(void); +Suite *make_nl_ematch_tree_clone_suite(void); +Suite *make_nl_netns_suite(void); + +#endif /* __LIBNL3_TESTS_CHECK_ALL_H__ */ diff --git a/tests/nl-test-util.c b/tests/nl-test-util.c new file mode 100644 index 00000000..1f67ac88 --- /dev/null +++ b/tests/nl-test-util.c @@ -0,0 +1,657 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ + +#include "nl-test-util.h" + +#include <fcntl.h> +#include <inttypes.h> +#include <limits.h> +#include <sched.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/mount.h> +#include <unistd.h> + +#include "netlink-private/utils.h" +#include "netlink/netlink.h" +#include "netlink/route/link.h" +#include "netlink/route/route.h" +#include "netlink/socket.h" + +/*****************************************************************************/ + +void _nltst_get_urandom(void *ptr, size_t len) +{ + int fd; + ssize_t nread; + + ck_assert_int_gt(len, 0); + ck_assert_ptr_nonnull(ptr); + + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); + _nltst_assert_errno(fd >= 0); + + nread = read(fd, ptr, len); + _nltst_assert_errno(nread == len); + + _nltst_close(fd); +} + +uint32_t _nltst_rand_u32(void) +{ + _nl_thread_local static unsigned short entropy[3]; + _nl_thread_local static bool has_entropy = false; + + if (!has_entropy) { + unsigned long long seed; + uint64_t seed64; + const char *s; + char *s_end; + + memset(entropy, 0, sizeof(entropy)); + s = getenv("NLTST_SEED_RAND"); + if (!s) + seed = 0; + else if (s[0] != '\0') { + errno = 0; + seed = strtoull(s, &s_end, 10); + if (errno != 0 || s_end[0] != '\0') { + ck_assert_msg( + 0, + "invalid NLTST_SEED_RAND=\"%s\". Must be an integer to seed the random numbers", + s); + } + } else + _nltst_get_urandom(&seed, sizeof(seed)); + + seed64 = seed; + printf("runs with NLTST_SEED_RAND=%" PRIu64 "\n", seed64); + + entropy[0] = (seed64 >> 0) ^ (seed64 >> 48); + entropy[1] = (seed64 >> 16) ^ (seed64 >> 0); + entropy[2] = (seed64 >> 32) ^ (seed64 >> 16); + has_entropy = true; + } + + _NL_STATIC_ASSERT(sizeof(long) >= sizeof(uint32_t)); + return jrand48(entropy); +} + +/*****************************************************************************/ + +#define _CANARY 539339 + +struct nltst_netns { + int canary; +}; + +/*****************************************************************************/ + +#define _assert_nltst_netns(nsdata) \ + do { \ + const struct nltst_netns *_nsdata = (nsdata); \ + \ + ck_assert_ptr_nonnull(_nsdata); \ + ck_assert_int_eq(_nsdata->canary, _CANARY); \ + } while (0) + +static struct { + struct nltst_netns *nsdata; +} _netns_fixture_global; + +void nltst_netns_fixture_setup(void) +{ + ck_assert(!_netns_fixture_global.nsdata); + + _netns_fixture_global.nsdata = nltst_netns_enter(); + _assert_nltst_netns(_netns_fixture_global.nsdata); +} + +void nltst_netns_fixture_teardown(void) +{ + _assert_nltst_netns(_netns_fixture_global.nsdata); + _nl_clear_pointer(&_netns_fixture_global.nsdata, nltst_netns_leave); +} + +/*****************************************************************************/ + +static void unshare_user(void) +{ + const uid_t uid = geteuid(); + const gid_t gid = getegid(); + FILE *f; + int r; + + /* Become a root in new user NS. */ + r = unshare(CLONE_NEWUSER); + _nltst_assert_errno(r == 0); + + /* Since Linux 3.19 we have to disable setgroups() in order to map users. + * Just proceed if the file is not there. */ + f = fopen("/proc/self/setgroups", "we"); + if (f) { + r = fprintf(f, "deny"); + _nltst_assert_errno(r > 0); + _nltst_fclose(f); + } + + /* Map current UID to root in NS to be created. */ + f = fopen("/proc/self/uid_map", "we"); + if (!f) { + if (errno == EACCES) { + /* Accessing uid_map might fail due to sandboxing. + * We ignore that error and proceed with the test. It will probably + * still work. */ + return; + } + _nltst_assert_errno(f); + } + r = fprintf(f, "0 %d 1", uid); + _nltst_assert_errno(r > 0); + _nltst_fclose(f); + + /* Map current GID to root in NS to be created. */ + f = fopen("/proc/self/gid_map", "we"); + _nltst_assert_errno(f); + r = fprintf(f, "0 %d 1", gid); + _nltst_assert_errno(r > 0); + _nltst_fclose(f); +} + +struct nltst_netns *nltst_netns_enter(void) +{ + struct nltst_netns *nsdata; + int r; + + nsdata = calloc(1, sizeof(struct nltst_netns)); + ck_assert(nsdata); + + nsdata->canary = _CANARY; + + unshare_user(); + + r = unshare(CLONE_NEWNET | CLONE_NEWNS); + _nltst_assert_errno(r == 0); + + /* We need a read-only /sys so that the platform knows there's no udev. */ + mount(NULL, "/sys", "sysfs", MS_SLAVE, NULL); + r = mount("sys", "/sys", "sysfs", MS_RDONLY, NULL); + _nltst_assert_errno(r == 0); + + return nsdata; +} + +void nltst_netns_leave(struct nltst_netns *nsdata) +{ + ck_assert(nsdata); + ck_assert_int_eq(nsdata->canary, _CANARY); + + /* nltst_netns_leave() was supposed to enter the original namespaces again + * and undo enter. + * + * However, I could get it to work (setns() always fails with EPERM) + * and valgrind on current Ubuntu seems not to support setns() call. + * + * So, do nothing. It's not really a problem, because the next test + * either should unshare yet another namespace, or not care about + * such things. */ + + free(nsdata); +} + +/*****************************************************************************/ + +void _nltst_object_identical(const void *a, const void *b) +{ + struct nl_object *o_a = (void *)a; + struct nl_object *o_b = (void *)b; + + ck_assert(a); + ck_assert(b); + + ck_assert_int_eq(nl_object_identical(o_a, o_b), 1); + ck_assert_int_eq(nl_object_identical(o_b, o_a), 1); + ck_assert_int_eq(nl_object_diff64(o_b, o_a), 0); + ck_assert_int_eq(nl_object_diff64(o_a, o_b), 0); + ck_assert_int_eq(nl_object_diff(o_a, o_b), 0); + ck_assert_int_eq(nl_object_diff(o_b, o_a), 0); +} + +/*****************************************************************************/ + +char *_nltst_object_to_string(struct nl_object *obj) +{ + size_t L = 1024; + size_t l; + char *s; + + if (!obj) + return strdup("(null)"); + + s = malloc(L); + ck_assert_ptr_nonnull(s); + + nl_object_dump_buf(obj, s, L); + l = strlen(s); + ck_assert_int_lt(l, L); + s = realloc(s, l + 1); + ck_assert_ptr_nonnull(s); + return s; +} + +struct cache_get_all_data { + struct nl_object **arr; + size_t len; + size_t idx; +}; + +static void _cache_get_all_fcn(struct nl_object *obj, void *user_data) +{ + struct cache_get_all_data *data = user_data; + size_t i; + + ck_assert(obj); + ck_assert_int_lt(data->idx, data->len); + + for (i = 0; i < data->idx; i++) + ck_assert_ptr_ne(data->arr[i], obj); + + data->arr[data->idx++] = obj; +} + +struct nl_object **_nltst_cache_get_all(struct nl_cache *cache, size_t *out_len) +{ + int nitems; + struct cache_get_all_data data = { + .idx = 0, + .len = 0, + }; + size_t len2 = 0; + size_t i; + size_t j; + + ck_assert(cache); + + nitems = nl_cache_nitems(cache); + ck_assert_int_ge(nitems, 0); + + data.len = nitems; + data.arr = malloc(sizeof(struct nl_object *) * (data.len + 1)); + ck_assert_ptr_nonnull(data.arr); + + nl_cache_foreach(cache, _cache_get_all_fcn, &data); + + ck_assert_int_eq(data.idx, data.len); + + ck_assert_int_le(data.len, SSIZE_MAX); + + data.arr[data.len] = NULL; + if (out_len) + *out_len = data.len; + + /* double check the result. */ + for (struct nl_object *obj = nl_cache_get_first(cache); obj; + obj = nl_cache_get_next(obj)) { + ck_assert_ptr_eq(data.arr[len2], obj); + len2++; + } + ck_assert_ptr_null(data.arr[len2]); + + for (i = 0; i < data.len; i++) { + ck_assert_ptr_nonnull(data.arr[i]); + for (j = i + 1; j < data.len; j++) + ck_assert_ptr_ne(data.arr[i], data.arr[j]); + } + + return data.arr; +} + +struct rtnl_link *_nltst_cache_get_link(struct nl_cache *cache, + const char *ifname) +{ + _nl_auto_free struct nl_object **objs = NULL; + struct rtnl_link *link = NULL; + size_t i; + + ck_assert_ptr_nonnull(cache); + ck_assert_ptr_nonnull(ifname); + + objs = _nltst_cache_get_all(cache, NULL); + for (i = 0; objs[i]; i++) { + if (_nl_streq(rtnl_link_get_name((struct rtnl_link *)objs[i]), + ifname)) { + ck_assert_ptr_null(link); + link = (struct rtnl_link *)objs[i]; + } + } + + if (_nltst_rand_u32_range(5) == 0) { + _nl_auto_rtnl_link struct rtnl_link *link2 = NULL; + + link2 = rtnl_link_get_by_name(cache, ifname); + ck_assert_ptr_eq(link2, link); + } + + return link; +} + +/*****************************************************************************/ + +struct nl_sock *_nltst_socket(int protocol) +{ + struct nl_sock *sk; + int r; + + sk = nl_socket_alloc(); + ck_assert(sk); + + r = nl_connect(sk, protocol); + ck_assert_int_eq(r, 0); + + if (_nltst_rand_u32_range(5) == 0) + nl_cache_free(_nltst_rtnl_link_alloc_cache(sk, AF_UNSPEC, 0)); + + if (_nltst_rand_u32_range(5) == 0) + nl_cache_free(_nltst_rtnl_route_alloc_cache( + sk, _nltst_rand_select(AF_UNSPEC, AF_INET, AF_INET6))); + + return sk; +} + +void _nltst_add_link(struct nl_sock *sk, const char *ifname, const char *kind, + int *out_ifindex) +{ + _nl_auto_nl_socket struct nl_sock *sk_free = NULL; + _nl_auto_rtnl_link struct rtnl_link *link = NULL; + _nl_auto_nl_cache struct nl_cache *cache = NULL; + struct rtnl_link *link2; + int ifindex; + int r; + + ck_assert(ifname); + ck_assert(kind); + + if (_nltst_rand_u32_range(5) == 0) + _nltst_assert_link_not_exists(ifname); + + if (!sk) { + sk = _nltst_socket(NETLINK_ROUTE); + sk_free = sk; + } + + link = rtnl_link_alloc(); + ck_assert(link); + + r = rtnl_link_set_type(link, kind); + ck_assert_int_eq(r, 0); + + rtnl_link_set_name(link, ifname); + + r = rtnl_link_add(sk, link, NLM_F_CREATE); + ck_assert_int_eq(r, 0); + + if (!out_ifindex && _nltst_rand_u32_range(5) != 0) + return; + + cache = _nltst_rtnl_link_alloc_cache(sk, AF_UNSPEC, 0); + + link2 = _nltst_cache_get_link(cache, ifname); + ck_assert_ptr_nonnull(link2); + + ifindex = rtnl_link_get_ifindex(link2); + ck_assert_int_gt(ifindex, 0); + + if (out_ifindex) + *out_ifindex = ifindex; +} + +void _nltst_delete_link(struct nl_sock *sk, const char *ifname) +{ + _nl_auto_nl_socket struct nl_sock *sk_free = NULL; + _nl_auto_rtnl_link struct rtnl_link *link = NULL; + + _nltst_assert_link_exists(ifname); + + if (!sk) { + sk = _nltst_socket(NETLINK_ROUTE); + sk_free = sk; + } + + if (_nltst_rand_u32_range(5) == 0) { + _nl_auto_nl_cache struct nl_cache *cache = NULL; + + cache = _nltst_rtnl_link_alloc_cache(sk, AF_UNSPEC, 0); + ck_assert_ptr_nonnull(_nltst_cache_get_link(cache, ifname)); + } + + link = rtnl_link_alloc(); + ck_assert_ptr_nonnull(link); + + rtnl_link_set_name(link, ifname); + + _nltst_assert_retcode(rtnl_link_delete(sk, link)); + + _nltst_assert_link_not_exists(ifname); +} + +void _nltst_get_link(struct nl_sock *sk, const char *ifname, int *out_ifindex, + struct rtnl_link **out_link) +{ + _nl_auto_nl_cache struct nl_cache *cache = NULL; + struct rtnl_link *link; + + if (_nltst_rand_u32_range(5) == 0) + _nltst_assert_link_exists(ifname); + + cache = _nltst_rtnl_link_alloc_cache(sk, AF_UNSPEC, 0); + + link = _nltst_cache_get_link(cache, ifname); + ck_assert(link); + + if (out_ifindex) + *out_ifindex = rtnl_link_get_ifindex(link); + + if (out_link) { + nl_object_get((struct nl_object *)link); + *out_link = link; + } +} + +struct nl_cache *_nltst_rtnl_link_alloc_cache(struct nl_sock *sk, + int addr_family, unsigned flags) +{ + _nl_auto_nl_socket struct nl_sock *sk_free = NULL; + struct nl_cache *cache; + int r; + + if (!sk) { + sk = _nltst_socket(NETLINK_ROUTE); + sk_free = sk; + } + + if (flags == 0 && _nltst_rand_bool()) + r = rtnl_link_alloc_cache(sk, addr_family, &cache); + else + r = rtnl_link_alloc_cache_flags(sk, addr_family, &cache, flags); + + _nltst_assert_retcode(r); + + if (_nltst_rand_u32_range(5) == 0) + free(_nltst_cache_get_all(cache, NULL)); + + return _nltst_assert(cache); +} + +struct nl_cache *_nltst_rtnl_route_alloc_cache(struct nl_sock *sk, + int addr_family) +{ + struct nl_cache *cache; + + ck_assert_ptr_nonnull(sk); + ck_assert(addr_family == AF_UNSPEC || addr_family == AF_INET || + addr_family == AF_INET6); + + _nltst_assert_retcode( + rtnl_route_alloc_cache(sk, addr_family, 0, &cache)); + + if (_nltst_rand_u32_range(5) == 0) + free(_nltst_cache_get_all(cache, NULL)); + + return _nltst_assert(cache); +} + +/*****************************************************************************/ + +char *_nltst_strtok(const char **p_str) +{ + const char *str; + _nl_auto_free char *dst = NULL; + size_t dst_len = 0; + size_t dst_alloc = 0; + size_t i; + + ck_assert_ptr_nonnull(p_str); + + str = _nltst_str_skip_space(*p_str); + + if (str[0] == '\0') { + *p_str = str; + return NULL; + } + + dst_len = 0; + dst_alloc = 10; + dst = malloc(dst_alloc); + ck_assert_ptr_nonnull(dst); + + i = 0; + while (true) { + char ch1 = '\0'; + char ch2 = '\0'; + + /* We take the first word, up until whitespace. Note that backslash + * escape is honored, so you can backslash escape spaces. The returned + * string will NOT have backslashes removed. */ + + if (str[i] == '\0') { + *p_str = &str[i]; + break; + } + if (_nltst_char_is_space(str[i])) { + *p_str = _nltst_str_skip_space(&str[i + 1]); + break; + } + ch1 = str[i]; + if (str[i] == '\\') { + if (str[i + 1] != '\0') { + ch2 = str[i + 1]; + i += 2; + } else + i += 1; + } else + i += 1; + + if (dst_len + 3 >= dst_alloc) { + dst_alloc *= 2; + dst = realloc(dst, dst_alloc); + ck_assert_ptr_nonnull(dst); + } + dst[dst_len++] = ch1; + if (ch2 != '\0') + dst[dst_len++] = ch2; + } + + ck_assert_int_gt(dst_len, 0); + return strndup(dst, dst_len); +} + +char **_nltst_strtokv(const char *str) +{ + _nl_auto_free char *s = NULL; + _nltst_auto_strfreev char **result = NULL; + size_t r_len = 0; + size_t r_alloc = 0; + + if (!str) + return NULL; + + r_alloc = 4; + result = malloc(sizeof(char *) * r_alloc); + ck_assert_ptr_nonnull(result); + + while ((s = _nltst_strtok(&str))) { + if (r_len + 2 >= r_alloc) { + r_alloc *= 2; + result = realloc(result, sizeof(char *) * r_alloc); + ck_assert_ptr_nonnull(result); + } + result[r_len++] = _nl_steal_pointer(&s); + } + ck_assert_int_lt(r_len, r_alloc); + result[r_len] = NULL; + return _nl_steal_pointer(&result); +} + +/*****************************************************************************/ + +void _nltst_assert_link_exists_full(const char *ifname, bool exists) +{ + _nl_auto_nl_cache struct nl_cache *cache = NULL; + _nl_auto_rtnl_link struct rtnl_link *link_clone = NULL; + struct rtnl_link *link; + char path[100]; + struct stat st; + int rnd; + int r; + + ck_assert_pstr_ne(ifname, NULL); + ck_assert_int_lt(strlen(ifname), IFNAMSIZ); + + strcpy(path, "/sys/class/net/"); + strcat(path, ifname); + ck_assert_int_lt(strlen(path), sizeof(path)); + + r = stat(path, &st); + if (exists) { + if (r != 0) { + const int errsv = (errno); + + ck_assert_msg( + 0, + "link(%s) does not exist (stat(%s) failed with r=%d, errno=%d (%s)", + ifname, path, r, errsv, strerror(errsv)); + } + } else { + if (r != -1 && errno != ENOENT) { + const int errsv = (errno); + + ck_assert_msg( + 0, + "link(%s) should not exist but stat(%s) gave r=%d, errno=%d (%s)", + ifname, path, r, errsv, strerror(errsv)); + } + } + + rnd = _nltst_rand_u32_range(3); + + if (rnd == 0) + return; + + cache = _nltst_rtnl_link_alloc_cache(NULL, AF_UNSPEC, 0); + + link = _nltst_cache_get_link(cache, ifname); + if (exists) + ck_assert_ptr_nonnull(link); + else + ck_assert_ptr_null(link); + + if (!link || rnd == 1) + return; + + link_clone = + (struct rtnl_link *)nl_object_clone((struct nl_object *)link); + ck_assert(link_clone); + + /* FIXME: we would expect that the cloned object is identical. It is not. */ + /* _nltst_object_identical(link, link_clone); */ +} diff --git a/tests/nl-test-util.h b/tests/nl-test-util.h new file mode 100644 index 00000000..0ff97528 --- /dev/null +++ b/tests/nl-test-util.h @@ -0,0 +1,400 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ + +#ifndef __NL_TEST_UTIL_H__ +#define __NL_TEST_UTIL_H__ + +#include <errno.h> +#include <sys/stat.h> +#include <check.h> +#include <string.h> +#include <stdbool.h> +#include <arpa/inet.h> + +#include "netlink/object.h" +#include "netlink/cache.h" + +#include "netlink-private/nl-auto.h" +#include "netlink-private/utils.h" + +/*****************************************************************************/ + +static inline void _nltst_strfreev(char **strv) +{ + size_t i; + + if (strv) { + for (i = 0; strv[i]; i++) + free(strv[i]); + free(strv); + } +} + +#define _nltst_auto_strfreev _nl_auto(_nltst_auto_strfreev_fcn) +_NL_AUTO_DEFINE_FCN_TYPED0(char **, _nltst_auto_strfreev_fcn, _nltst_strfreev); + +/*****************************************************************************/ + +#ifndef ck_assert_ptr_nonnull +#define ck_assert_ptr_nonnull(ptr) ck_assert(ptr) +#endif + +#ifndef ck_assert_pstr_ne +#define ck_assert_pstr_ne(a, b) \ + do { \ + const char *_a = (a); \ + const char *_b = (b); \ + \ + ck_assert(!(_a == _b || (_a && _b && strcmp(_a, _b) == 0))); \ + } while (0) +#endif + +#ifndef ck_assert_ptr_null +#define ck_assert_ptr_null(ptr) ck_assert(!(ptr)) +#endif + +/*****************************************************************************/ + +void _nltst_get_urandom(void *ptr, size_t len); + +uint32_t _nltst_rand_u32(void); + +static inline uint32_t _nltst_rand_u32_range(uint32_t n) +{ + uint32_t rem; + uint32_t i; + + if (n == 0) + return _nltst_rand_u32(); + if (n == 1) + return 0; + + rem = UINT32_MAX % n; + for (;;) { + i = _nltst_rand_u32(); + if (i < (UINT32_MAX - rem)) + return i % n; + } +} + +static inline bool _nltst_rand_bool(void) +{ + return _nltst_rand_u32() % 2 == 0; +} + +#define _nltst_rand_select(a, ...) \ + ({ \ + const typeof(a) _lst[] = { (a), ##__VA_ARGS__ }; \ + \ + _lst[_nltst_rand_u32_range(_NL_N_ELEMENTS(_lst))]; \ + }) + +/*****************************************************************************/ + +#define _nltst_assert(expr) \ + ({ \ + typeof(expr) _expr = (expr); \ + \ + if (!_expr) { \ + ck_assert_msg(0, "assert(%s) failed", #expr); \ + } \ + _expr; \ + }) + +#define _nltst_assert_errno(expr) \ + do { \ + if (expr) { \ + } else { \ + const int _errno = (errno); \ + \ + ck_assert_msg(0, "assert(%s) failed (errno=%d, %s)", \ + #expr, _errno, strerror(_errno)); \ + } \ + } while (0) + +#define _nltst_assert_retcode(expr) \ + do { \ + const int _r = (expr); \ + \ + if (_r < 0) { \ + ck_assert_msg( \ + 0, "command(%s) failed with return code %d", \ + #expr, _r); \ + } \ + if (_r > 0) { \ + ck_assert_msg( \ + 0, \ + "command(%s) has unexpected positive return code %d", \ + #expr, _r); \ + } \ + } while (0) + +#define _nltst_close(fd) \ + do { \ + int _r; \ + \ + _r = _nl_close((fd)); \ + _nltst_assert_errno(_r == 0); \ + } while (0) + +#define _nltst_fclose(f) \ + do { \ + int _r; \ + \ + _r = fclose((f)); \ + _nltst_assert_errno(_r == 0); \ + } while (0) + +void _nltst_assert_link_exists_full(const char *ifname, bool exists); + +#define _nltst_assert_link_exists(ifname) \ + _nltst_assert_link_exists_full((ifname), true) + +#define _nltst_assert_link_not_exists(ifname) \ + _nltst_assert_link_exists_full((ifname), false) + +/*****************************************************************************/ + +typedef union { + in_addr_t addr4; + struct in_addr a4; + struct in6_addr a6; +} NLTstIPAddr; + +static inline char *_nltst_inet_ntop(int addr_family, const void *addr, + char buf[static INET_ADDRSTRLEN]) +{ + char *r; + + ck_assert(addr_family == AF_INET || addr_family == AF_INET6); + ck_assert(addr); + + r = (char *)inet_ntop(addr_family, addr, buf, + (addr_family == AF_INET) ? INET_ADDRSTRLEN : + INET6_ADDRSTRLEN); + ck_assert_ptr_eq(r, buf); + ck_assert_int_lt(strlen(r), (addr_family == AF_INET) ? + INET_ADDRSTRLEN : + INET6_ADDRSTRLEN); + return r; +} + +static inline char *_nltst_inet_ntop_dup(int addr_family, const void *addr) +{ + return (char *)_nltst_inet_ntop(addr_family, addr, + malloc((addr_family == AF_INET) ? + INET_ADDRSTRLEN : + INET6_ADDRSTRLEN)); +} + +static inline bool _nltst_inet_pton(int addr_family, const char *str, + int *out_addr_family, void *out_addr) +{ + NLTstIPAddr a; + int r; + + ck_assert(addr_family == AF_UNSPEC || addr_family == AF_INET || + addr_family == AF_INET6); + + /* when requesting @out_addr, then the addr-family must either be + * pre-determined or requested too. */ + ck_assert(!out_addr || out_addr_family || addr_family != AF_UNSPEC); + + if (!str) + return false; + + if (addr_family == AF_UNSPEC) + addr_family = strchr(str, ':') ? AF_INET6 : AF_INET; + + r = inet_pton(addr_family, str, &a); + if (r != 1) + return false; + + if (out_addr) { + memcpy(out_addr, &a, + addr_family == AF_INET ? sizeof(in_addr_t) : + sizeof(struct in6_addr)); + } + if (out_addr_family) + *out_addr_family = addr_family; + + return true; +} + +static inline bool _nltst_inet_valid(int addr_family, const char *addr) +{ + return _nltst_inet_pton(addr_family, addr, NULL, NULL); +} + +static inline in_addr_t _nltst_inet4(const char *addr) +{ + in_addr_t addr_bin = 0; + + _nltst_assert(_nltst_inet_pton(AF_INET, addr, NULL, &addr_bin)); + return addr_bin; +} + +static inline struct in6_addr *_nltst_inet6p(const char *addr) +{ + _nl_thread_local static struct in6_addr addr_bin; + + ck_assert(_nltst_inet_pton(AF_INET6, addr, NULL, &addr_bin)); + return &addr_bin; +} + +static inline struct in6_addr _nltst_inet6(const char *addr) +{ + struct in6_addr addr_bin; + + ck_assert(_nltst_inet_pton(AF_INET6, addr, NULL, &addr_bin)); + return addr_bin; +} + +static inline int _nltst_inet_addr_family(int addr_family, const char *addr) +{ + if (!_nltst_inet_pton(addr_family, addr, &addr_family, NULL)) + return AF_UNSPEC; + return addr_family; +} + +static inline char *_nltst_inet_normalize(int addr_family, const char *addr, + char buf[static INET_ADDRSTRLEN]) +{ + NLTstIPAddr a; + + buf[0] = '\0'; + if (!_nltst_inet_pton(addr_family, addr, &addr_family, &a)) + return NULL; + return _nltst_inet_ntop(addr_family, &a, buf); +} + +/*****************************************************************************/ + +char *_nltst_strtok(const char **p_str); + +char **_nltst_strtokv(const char *str); + +#define _nltst_assert_strv_equal(strv1, strv2) \ + do { \ + typeof(strv1) _strv1 = (strv1); \ + typeof(strv2) _strv2 = (strv2); \ + _nl_unused const void *_strv1_typecheck1 = _strv1; \ + _nl_unused const void *_strv2_typecheck1 = _strv2; \ + _nl_unused const char *_strv1_typecheck2 = \ + _strv1 ? _strv1[0] : NULL; \ + _nl_unused const char *_strv2_typecheck2 = \ + _strv2 ? _strv2[0] : NULL; \ + size_t _i; \ + \ + ck_assert_int_eq(!!_strv1, !!_strv2); \ + if (_strv1) { \ + for (_i = 0; _strv1[_i] || _strv2[_i]; _i++) { \ + ck_assert_str_eq(_strv1[_i], _strv2[_i]); \ + } \ + } \ + } while (0) + +#define _NLTST_CHARSET_SPACE " \n\r\t" + +#define _nltst_char_is(ch, charset) (!!(strchr("" charset "", (ch)))) + +#define _nltst_char_is_space(ch) _nltst_char_is(ch, _NLTST_CHARSET_SPACE) + +#define _nltst_str_skip_predicate(s, ch, predicate) \ + ({ \ + typeof(s) _s1 = (s); \ + _nl_unused const char *_s1_typecheck = (_s1); \ + \ + if (_s1) { \ + while (({ \ + const char ch = _s1[0]; \ + \ + (ch != '\0') && (predicate); \ + })) \ + _s1++; \ + } \ + _s1; \ + }) + +#define _nltst_str_skip_charset(s, charset) \ + _nltst_str_skip_predicate(s, _ch, _nltst_char_is(_ch, "" charset "")) + +#define _nltst_str_skip_space(s) \ + _nltst_str_skip_charset(s, _NLTST_CHARSET_SPACE) + +#define _nltst_str_has_prefix_and_space(s, prefix) \ + ({ \ + typeof(s) _s2 = (s); \ + _nl_unused const char *_s2_typecheck = (_s2); \ + const size_t _l = strlen("" prefix ""); \ + \ + if (_s2) { \ + if ((strncmp(_s2, "" prefix "", _l)) == 0 && \ + _nltst_char_is_space(_s2[_l])) \ + _s2 = _nltst_str_skip_space(&_s2[_l + 1]); \ + else \ + _s2 = NULL; \ + } \ + _s2; \ + }) + +#define _nltst_str_find_first_not_from_charset(s, charset) \ + ({ \ + typeof(s) _s3 = (s); \ + _nl_unused const char *_s3_typecheck = (_s3); \ + size_t _l3; \ + \ + _l3 = strspn(_s3, "" charset ""); \ + \ + &_s3[_l3]; \ + }) + +#define _nltst_str_find_first_from_charset(s, charset) \ + ({ \ + typeof(s) _s3 = (s); \ + _nl_unused const char *_s3_typecheck = (_s3); \ + size_t _l3; \ + \ + _l3 = strcspn(_s3, "" charset ""); \ + \ + &_s3[_l3]; \ + }) + +/*****************************************************************************/ + +void nltst_netns_fixture_setup(void); +void nltst_netns_fixture_teardown(void); + +struct nltst_netns; + +struct nltst_netns *nltst_netns_enter(void); +void nltst_netns_leave(struct nltst_netns *nsdata); + +/*****************************************************************************/ + +void _nltst_object_identical(const void *a, const void *b); + +char *_nltst_object_to_string(struct nl_object *obj); + +struct nl_object **_nltst_cache_get_all(struct nl_cache *cache, + size_t *out_len); + +struct rtnl_link *_nltst_cache_get_link(struct nl_cache *cache, + const char *ifname); + +struct nl_cache *_nltst_rtnl_link_alloc_cache(struct nl_sock *sk, + int addr_family, unsigned flags); + +struct nl_cache *_nltst_rtnl_route_alloc_cache(struct nl_sock *sk, + int addr_family); + +struct nl_sock *_nltst_socket(int protocol); + +void _nltst_add_link(struct nl_sock *sk, const char *ifname, const char *kind, + int *out_ifindex); + +void _nltst_delete_link(struct nl_sock *sk, const char *ifname); + +void _nltst_get_link(struct nl_sock *sk, const char *ifname, int *out_ifindex, + struct rtnl_link **out_link); + +#endif /* __NL_TEST_UTIL_H__ */ diff --git a/tests/test-complex-HTB-with-hash-filters.c b/tests/test-complex-HTB-with-hash-filters.c index b1bf36e5..016d467a 100644 --- a/tests/test-complex-HTB-with-hash-filters.c +++ b/tests/test-complex-HTB-with-hash-filters.c @@ -1,11 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * test/test-complex-HTB-with-hash-filters.c Add HTB qdisc, HTB classes and creates some hash filters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2011 Adrian Ban <adrian.ban@mantech.ro> */ diff --git a/tests/test-u32-filter-with-actions.c b/tests/test-u32-filter-with-actions.c index e9910e33..17e7bdc1 100644 --- a/tests/test-u32-filter-with-actions.c +++ b/tests/test-u32-filter-with-actions.c @@ -1,14 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ /* - * test/tests-u32-with-actions.c Add ingress qdisc, create some hash filters, and add redirect action - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. + * Copyright (c) 2013 Cong Wang <xiyou.wangcong@gmail.com> * * Stolen from tests/test-complex-HTB-with-hash-filters.c - * - * Copyright (c) 2013 Cong Wang <xiyou.wangcong@gmail.com> */ #include <netlink/route/link.h> diff --git a/tests/util.h b/tests/util.h deleted file mode 100644 index 8c9acf12..00000000 --- a/tests/util.h +++ /dev/null @@ -1,10 +0,0 @@ -#include <check.h> - -#define nl_fail_if(condition, error, message) \ - fail_if((condition), "nlerr=%d (%s): %s", \ - (error), nl_geterror(error), (message)) - -Suite *make_nl_attr_suite(void); -Suite *make_nl_addr_suite(void); -Suite *make_nl_ematch_tree_clone_suite(void); - |