diff mbox series

[bpf-next,v3,4/6] selftests/bpf: Monitor traffic for tc_redirect.

Message ID 20240730002745.1484204-5-thinker.li@gmail.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series monitor network traffic for flaky test cases | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-17 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-42 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 7 this patch: 7
netdev/build_tools success Errors and warnings before: 10 this patch: 10
netdev/cc_maintainers warning 10 maintainers not CCed: kpsingh@kernel.org shuah@kernel.org haoluo@google.com daniel@iogearbox.net john.fastabend@gmail.com jolsa@kernel.org linux-kselftest@vger.kernel.org yonghong.song@linux.dev mykolal@fb.com eddyz87@gmail.com
netdev/build_clang success Errors and warnings before: 7 this patch: 7
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 7 this patch: 7
netdev/checkpatch warning WARNING: line length of 93 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-PR fail merge-conflict

Commit Message

Kui-Feng Lee July 30, 2024, 12:27 a.m. UTC
Enable traffic monitoring for the test case tc_redirect.

Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
---
 .../selftests/bpf/prog_tests/tc_redirect.c    | 48 ++++++++++++++-----
 1 file changed, 36 insertions(+), 12 deletions(-)

Comments

Geliang Tang July 30, 2024, 9:43 a.m. UTC | #1
On Mon, 2024-07-29 at 17:27 -0700, Kui-Feng Lee wrote:
> Enable traffic monitoring for the test case tc_redirect.
> 
> Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
> ---
>  .../selftests/bpf/prog_tests/tc_redirect.c    | 48 ++++++++++++++---
> --
>  1 file changed, 36 insertions(+), 12 deletions(-)
> 
> diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> index 327d51f59142..46d397c5c79a 100644
> --- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> +++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> @@ -68,6 +68,7 @@
>  		__FILE__, __LINE__, strerror(errno), ##__VA_ARGS__)
>  
>  static const char * const namespaces[] = {NS_SRC, NS_FWD, NS_DST,
> NULL};
> +static struct netns_obj *netns_objs[3];
>  
>  static int write_file(const char *path, const char *newval)
>  {
> @@ -85,29 +86,52 @@ static int write_file(const char *path, const
> char *newval)
>  	return 0;
>  }
>  
> -static int netns_setup_namespaces(const char *verb)
> +enum NETNS_VERB {
> +	NETNS_ADD,
> +	NETNS_DEL,
> +};
> +
> +static int netns_setup_namespaces(enum NETNS_VERB verb)
>  {
>  	const char * const *ns = namespaces;
> -	char cmd[128];
> +	struct netns_obj **ns_obj = netns_objs;
>  
>  	while (*ns) {
> -		snprintf(cmd, sizeof(cmd), "ip netns %s %s", verb,
> *ns);
> -		if (!ASSERT_OK(system(cmd), cmd))
> -			return -1;
> +		if (verb == NETNS_ADD) {

Maybe better to keep "verb" parameter as "char *", and use

		if (!strcmp(verb, "add"))

here instead?

> +			*ns_obj = netns_new(*ns, false);
> +			if (!*ns_obj) {
> +				log_err("netns_new failed");
> +				return -1;
> +			}
> +		} else {
> +			if (!*ns_obj) {
> +				log_err("netns_obj is NULL");
> +				return -1;
> +			}
> +			netns_free(*ns_obj);
> +			*ns_obj = NULL;
> +		}
>  		ns++;
> +		ns_obj++;
>  	}
>  	return 0;
>  }
>  
> -static void netns_setup_namespaces_nofail(const char *verb)
> +static void netns_setup_namespaces_nofail(enum NETNS_VERB verb)
>  {
>  	const char * const *ns = namespaces;
> -	char cmd[128];
> +	struct netns_obj **ns_obj = netns_objs;
>  
>  	while (*ns) {
> -		snprintf(cmd, sizeof(cmd), "ip netns %s %s >
> /dev/null 2>&1", verb, *ns);
> -		system(cmd);
> +		if (verb == NETNS_ADD) {
> +			*ns_obj = netns_new(*ns, false);
> +		} else {
> +			if (*ns_obj)
> +				netns_free(*ns_obj);
> +			*ns_obj = NULL;
> +		}
>  		ns++;
> +		ns_obj++;
>  	}
>  }
>  
> @@ -1250,17 +1274,17 @@ static void test_tc_redirect_peer_l3(struct
> netns_setup_result *setup_result)
>  	({                                                          
>                         \
>  		struct netns_setup_result setup_result = { .dev_mode
> = mode, };             \
>  		if
> (test__start_subtest(#name))                                         
>     \
> -			if (ASSERT_OK(netns_setup_namespaces("add"),
> "setup namespaces")) { \
> +			if
> (ASSERT_OK(netns_setup_namespaces(NETNS_ADD), "setup namespaces")) {
> \
>  				if
> (ASSERT_OK(netns_setup_links_and_routes(&setup_result),  \
>  					      "setup links and
> routes"))                    \
>  					test_ ##
> name(&setup_result);                       \
> -
> 				netns_setup_namespaces("delete");                           \
> +				netns_setup_namespaces(NETNS_DEL);  
>                         \
>  			}                                           
>                         \
>  	})
>  
>  static void *test_tc_redirect_run_tests(void *arg)
>  {
> -	netns_setup_namespaces_nofail("delete");
> +	netns_setup_namespaces_nofail(NETNS_DEL);
>  
>  	RUN_TEST(tc_redirect_peer, MODE_VETH);
>  	RUN_TEST(tc_redirect_peer, MODE_NETKIT);
Kui-Feng Lee July 30, 2024, 4:33 p.m. UTC | #2
On 7/30/24 02:43, Geliang Tang wrote:
> On Mon, 2024-07-29 at 17:27 -0700, Kui-Feng Lee wrote:
>> Enable traffic monitoring for the test case tc_redirect.
>>
>> Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
>> ---
>>   .../selftests/bpf/prog_tests/tc_redirect.c    | 48 ++++++++++++++---
>> --
>>   1 file changed, 36 insertions(+), 12 deletions(-)
>>
>> diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
>> b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
>> index 327d51f59142..46d397c5c79a 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
>> @@ -68,6 +68,7 @@
>>   		__FILE__, __LINE__, strerror(errno), ##__VA_ARGS__)
>>   
>>   static const char * const namespaces[] = {NS_SRC, NS_FWD, NS_DST,
>> NULL};
>> +static struct netns_obj *netns_objs[3];
>>   
>>   static int write_file(const char *path, const char *newval)
>>   {
>> @@ -85,29 +86,52 @@ static int write_file(const char *path, const
>> char *newval)
>>   	return 0;
>>   }
>>   
>> -static int netns_setup_namespaces(const char *verb)
>> +enum NETNS_VERB {
>> +	NETNS_ADD,
>> +	NETNS_DEL,
>> +};
>> +
>> +static int netns_setup_namespaces(enum NETNS_VERB verb)
>>   {
>>   	const char * const *ns = namespaces;
>> -	char cmd[128];
>> +	struct netns_obj **ns_obj = netns_objs;
>>   
>>   	while (*ns) {
>> -		snprintf(cmd, sizeof(cmd), "ip netns %s %s", verb,
>> *ns);
>> -		if (!ASSERT_OK(system(cmd), cmd))
>> -			return -1;
>> +		if (verb == NETNS_ADD) {
> 
> Maybe better to keep "verb" parameter as "char *", and use
> 
> 		if (!strcmp(verb, "add"))
> 
> here instead?

I have no strong opinion here.
May I know why you think string is better here?

> 
>> +			*ns_obj = netns_new(*ns, false);
>> +			if (!*ns_obj) {
>> +				log_err("netns_new failed");
>> +				return -1;
>> +			}
>> +		} else {
>> +			if (!*ns_obj) {
>> +				log_err("netns_obj is NULL");
>> +				return -1;
>> +			}
>> +			netns_free(*ns_obj);
>> +			*ns_obj = NULL;
>> +		}
>>   		ns++;
>> +		ns_obj++;
>>   	}
>>   	return 0;
>>   }
>>   
>> -static void netns_setup_namespaces_nofail(const char *verb)
>> +static void netns_setup_namespaces_nofail(enum NETNS_VERB verb)
>>   {
>>   	const char * const *ns = namespaces;
>> -	char cmd[128];
>> +	struct netns_obj **ns_obj = netns_objs;
>>   
>>   	while (*ns) {
>> -		snprintf(cmd, sizeof(cmd), "ip netns %s %s >
>> /dev/null 2>&1", verb, *ns);
>> -		system(cmd);
>> +		if (verb == NETNS_ADD) {
>> +			*ns_obj = netns_new(*ns, false);
>> +		} else {
>> +			if (*ns_obj)
>> +				netns_free(*ns_obj);
>> +			*ns_obj = NULL;
>> +		}
>>   		ns++;
>> +		ns_obj++;
>>   	}
>>   }
>>   
>> @@ -1250,17 +1274,17 @@ static void test_tc_redirect_peer_l3(struct
>> netns_setup_result *setup_result)
>>   	({
>>                          \
>>   		struct netns_setup_result setup_result = { .dev_mode
>> = mode, };             \
>>   		if
>> (test__start_subtest(#name))
>>      \
>> -			if (ASSERT_OK(netns_setup_namespaces("add"),
>> "setup namespaces")) { \
>> +			if
>> (ASSERT_OK(netns_setup_namespaces(NETNS_ADD), "setup namespaces")) {
>> \
>>   				if
>> (ASSERT_OK(netns_setup_links_and_routes(&setup_result),  \
>>   					      "setup links and
>> routes"))                    \
>>   					test_ ##
>> name(&setup_result);                       \
>> -
>> 				netns_setup_namespaces("delete");                           \
>> +				netns_setup_namespaces(NETNS_DEL);
>>                          \
>>   			}
>>                          \
>>   	})
>>   
>>   static void *test_tc_redirect_run_tests(void *arg)
>>   {
>> -	netns_setup_namespaces_nofail("delete");
>> +	netns_setup_namespaces_nofail(NETNS_DEL);
>>   
>>   	RUN_TEST(tc_redirect_peer, MODE_VETH);
>>   	RUN_TEST(tc_redirect_peer, MODE_NETKIT);
>
Geliang Tang July 31, 2024, 1:25 a.m. UTC | #3
On Tue, 2024-07-30 at 09:33 -0700, Kui-Feng Lee wrote:
> 
> 
> On 7/30/24 02:43, Geliang Tang wrote:
> > On Mon, 2024-07-29 at 17:27 -0700, Kui-Feng Lee wrote:
> > > Enable traffic monitoring for the test case tc_redirect.
> > > 
> > > Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
> > > ---
> > >   .../selftests/bpf/prog_tests/tc_redirect.c    | 48
> > > ++++++++++++++---
> > > --
> > >   1 file changed, 36 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> > > b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> > > index 327d51f59142..46d397c5c79a 100644
> > > --- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> > > +++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
> > > @@ -68,6 +68,7 @@
> > >   		__FILE__, __LINE__, strerror(errno),
> > > ##__VA_ARGS__)
> > >   
> > >   static const char * const namespaces[] = {NS_SRC, NS_FWD,
> > > NS_DST,
> > > NULL};
> > > +static struct netns_obj *netns_objs[3];
> > >   
> > >   static int write_file(const char *path, const char *newval)
> > >   {
> > > @@ -85,29 +86,52 @@ static int write_file(const char *path, const
> > > char *newval)
> > >   	return 0;
> > >   }
> > >   
> > > -static int netns_setup_namespaces(const char *verb)
> > > +enum NETNS_VERB {
> > > +	NETNS_ADD,
> > > +	NETNS_DEL,
> > > +};
> > > +
> > > +static int netns_setup_namespaces(enum NETNS_VERB verb)
> > >   {
> > >   	const char * const *ns = namespaces;
> > > -	char cmd[128];
> > > +	struct netns_obj **ns_obj = netns_objs;
> > >   
> > >   	while (*ns) {
> > > -		snprintf(cmd, sizeof(cmd), "ip netns %s %s",
> > > verb,
> > > *ns);
> > > -		if (!ASSERT_OK(system(cmd), cmd))
> > > -			return -1;
> > > +		if (verb == NETNS_ADD) {
> > 
> > Maybe better to keep "verb" parameter as "char *", and use
> > 
> > 		if (!strcmp(verb, "add"))
> > 
> > here instead?
> 
> I have no strong opinion here.
> May I know why you think string is better here?

I don't mean that string is better, I mean that "keep using strings" is
better. If we continue to use string, test_tc_redirect_peer_l3 and
test_tc_redirect_run_tests can remain unchanged, it at least makes this
patch smaller.

> 
> > 
> > > +			*ns_obj = netns_new(*ns, false);
> > > +			if (!*ns_obj) {
> > > +				log_err("netns_new failed");
> > > +				return -1;
> > > +			}
> > > +		} else {
> > > +			if (!*ns_obj) {
> > > +				log_err("netns_obj is NULL");
> > > +				return -1;
> > > +			}
> > > +			netns_free(*ns_obj);
> > > +			*ns_obj = NULL;
> > > +		}
> > >   		ns++;
> > > +		ns_obj++;
> > >   	}
> > >   	return 0;
> > >   }
> > >   
> > > -static void netns_setup_namespaces_nofail(const char *verb)
> > > +static void netns_setup_namespaces_nofail(enum NETNS_VERB verb)
> > >   {
> > >   	const char * const *ns = namespaces;
> > > -	char cmd[128];
> > > +	struct netns_obj **ns_obj = netns_objs;
> > >   
> > >   	while (*ns) {
> > > -		snprintf(cmd, sizeof(cmd), "ip netns %s %s >
> > > /dev/null 2>&1", verb, *ns);
> > > -		system(cmd);
> > > +		if (verb == NETNS_ADD) {
> > > +			*ns_obj = netns_new(*ns, false);
> > > +		} else {
> > > +			if (*ns_obj)
> > > +				netns_free(*ns_obj);
> > > +			*ns_obj = NULL;
> > > +		}
> > >   		ns++;
> > > +		ns_obj++;
> > >   	}
> > >   }
> > >   
> > > @@ -1250,17 +1274,17 @@ static void
> > > test_tc_redirect_peer_l3(struct
> > > netns_setup_result *setup_result)
> > >   	({
> > >                          \
> > >   		struct netns_setup_result setup_result = {
> > > .dev_mode
> > > = mode, };             \
> > >   		if
> > > (test__start_subtest(#name))
> > >      \
> > > -			if
> > > (ASSERT_OK(netns_setup_namespaces("add"),
> > > "setup namespaces")) { \
> > > +			if
> > > (ASSERT_OK(netns_setup_namespaces(NETNS_ADD), "setup
> > > namespaces")) {
> > > \
> > >   				if
> > > (ASSERT_OK(netns_setup_links_and_routes(&setup_result),  \
> > >   					      "setup links and
> > > routes"))                    \
> > >   					test_ ##
> > > name(&setup_result);                       \
> > > -
> > > 				netns_setup_namespaces("delete")
> > > ;                           \
> > > +				netns_setup_namespaces(NETNS_DEL
> > > );
> > >                          \
> > >   			}
> > >                          \
> > >   	})
> > >   
> > >   static void *test_tc_redirect_run_tests(void *arg)
> > >   {
> > > -	netns_setup_namespaces_nofail("delete");
> > > +	netns_setup_namespaces_nofail(NETNS_DEL);
> > >   
> > >   	RUN_TEST(tc_redirect_peer, MODE_VETH);
> > >   	RUN_TEST(tc_redirect_peer, MODE_NETKIT);
> > 
>
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
index 327d51f59142..46d397c5c79a 100644
--- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
+++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c
@@ -68,6 +68,7 @@ 
 		__FILE__, __LINE__, strerror(errno), ##__VA_ARGS__)
 
 static const char * const namespaces[] = {NS_SRC, NS_FWD, NS_DST, NULL};
+static struct netns_obj *netns_objs[3];
 
 static int write_file(const char *path, const char *newval)
 {
@@ -85,29 +86,52 @@  static int write_file(const char *path, const char *newval)
 	return 0;
 }
 
-static int netns_setup_namespaces(const char *verb)
+enum NETNS_VERB {
+	NETNS_ADD,
+	NETNS_DEL,
+};
+
+static int netns_setup_namespaces(enum NETNS_VERB verb)
 {
 	const char * const *ns = namespaces;
-	char cmd[128];
+	struct netns_obj **ns_obj = netns_objs;
 
 	while (*ns) {
-		snprintf(cmd, sizeof(cmd), "ip netns %s %s", verb, *ns);
-		if (!ASSERT_OK(system(cmd), cmd))
-			return -1;
+		if (verb == NETNS_ADD) {
+			*ns_obj = netns_new(*ns, false);
+			if (!*ns_obj) {
+				log_err("netns_new failed");
+				return -1;
+			}
+		} else {
+			if (!*ns_obj) {
+				log_err("netns_obj is NULL");
+				return -1;
+			}
+			netns_free(*ns_obj);
+			*ns_obj = NULL;
+		}
 		ns++;
+		ns_obj++;
 	}
 	return 0;
 }
 
-static void netns_setup_namespaces_nofail(const char *verb)
+static void netns_setup_namespaces_nofail(enum NETNS_VERB verb)
 {
 	const char * const *ns = namespaces;
-	char cmd[128];
+	struct netns_obj **ns_obj = netns_objs;
 
 	while (*ns) {
-		snprintf(cmd, sizeof(cmd), "ip netns %s %s > /dev/null 2>&1", verb, *ns);
-		system(cmd);
+		if (verb == NETNS_ADD) {
+			*ns_obj = netns_new(*ns, false);
+		} else {
+			if (*ns_obj)
+				netns_free(*ns_obj);
+			*ns_obj = NULL;
+		}
 		ns++;
+		ns_obj++;
 	}
 }
 
@@ -1250,17 +1274,17 @@  static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result)
 	({                                                                                  \
 		struct netns_setup_result setup_result = { .dev_mode = mode, };             \
 		if (test__start_subtest(#name))                                             \
-			if (ASSERT_OK(netns_setup_namespaces("add"), "setup namespaces")) { \
+			if (ASSERT_OK(netns_setup_namespaces(NETNS_ADD), "setup namespaces")) { \
 				if (ASSERT_OK(netns_setup_links_and_routes(&setup_result),  \
 					      "setup links and routes"))                    \
 					test_ ## name(&setup_result);                       \
-				netns_setup_namespaces("delete");                           \
+				netns_setup_namespaces(NETNS_DEL);                          \
 			}                                                                   \
 	})
 
 static void *test_tc_redirect_run_tests(void *arg)
 {
-	netns_setup_namespaces_nofail("delete");
+	netns_setup_namespaces_nofail(NETNS_DEL);
 
 	RUN_TEST(tc_redirect_peer, MODE_VETH);
 	RUN_TEST(tc_redirect_peer, MODE_NETKIT);