Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
An ipvlan bug fix in 'net' conflicted with the abstraction away of the IPV6 specific support in 'net-next'. Similarly, a bug fix for mlx5 in 'net' conflicted with the flow action conversion in 'net-next'. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -10,6 +10,7 @@ TARGETS += drivers/dma-buf
|
||||
TARGETS += efivarfs
|
||||
TARGETS += exec
|
||||
TARGETS += filesystems
|
||||
TARGETS += filesystems/binderfs
|
||||
TARGETS += firmware
|
||||
TARGETS += ftrace
|
||||
TARGETS += futex
|
||||
|
@@ -13,7 +13,7 @@ static inline unsigned int bpf_num_possible_cpus(void)
|
||||
unsigned int start, end, possible_cpus = 0;
|
||||
char buff[128];
|
||||
FILE *fp;
|
||||
int n;
|
||||
int len, n, i, j = 0;
|
||||
|
||||
fp = fopen(fcpu, "r");
|
||||
if (!fp) {
|
||||
@@ -21,17 +21,27 @@ static inline unsigned int bpf_num_possible_cpus(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (fgets(buff, sizeof(buff), fp)) {
|
||||
n = sscanf(buff, "%u-%u", &start, &end);
|
||||
if (n == 0) {
|
||||
printf("Failed to retrieve # possible CPUs!\n");
|
||||
exit(1);
|
||||
} else if (n == 1) {
|
||||
end = start;
|
||||
}
|
||||
possible_cpus = start == 0 ? end + 1 : 0;
|
||||
break;
|
||||
if (!fgets(buff, sizeof(buff), fp)) {
|
||||
printf("Failed to read %s!\n", fcpu);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
len = strlen(buff);
|
||||
for (i = 0; i <= len; i++) {
|
||||
if (buff[i] == ',' || buff[i] == '\0') {
|
||||
buff[i] = '\0';
|
||||
n = sscanf(&buff[j], "%u-%u", &start, &end);
|
||||
if (n <= 0) {
|
||||
printf("Failed to retrieve # possible CPUs!\n");
|
||||
exit(1);
|
||||
} else if (n == 1) {
|
||||
end = start;
|
||||
}
|
||||
possible_cpus += end - start + 1;
|
||||
j = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return possible_cpus;
|
||||
|
@@ -1902,13 +1902,12 @@ static struct btf_raw_test raw_tests[] = {
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "func proto (CONST=>TYPEDEF=>FUNC_PROTO)",
|
||||
.descr = "func proto (TYPEDEF=>FUNC_PROTO)",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */
|
||||
BTF_CONST_ENC(4), /* [3] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 5), /* [4] */
|
||||
BTF_FUNC_PROTO_ENC(0, 2), /* [5] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 4), /* [3] */
|
||||
BTF_FUNC_PROTO_ENC(0, 2), /* [4] */
|
||||
BTF_FUNC_PROTO_ARG_ENC(0, 1),
|
||||
BTF_FUNC_PROTO_ARG_ENC(0, 2),
|
||||
BTF_END_RAW,
|
||||
@@ -1922,8 +1921,6 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid type_id",
|
||||
},
|
||||
|
||||
{
|
||||
|
@@ -37,6 +37,10 @@ prerequisite()
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
present_cpus=`cat $SYSFS/devices/system/cpu/present`
|
||||
present_max=${present_cpus##*-}
|
||||
echo "present_cpus = $present_cpus present_max = $present_max"
|
||||
|
||||
echo -e "\t Cpus in online state: $online_cpus"
|
||||
|
||||
offline_cpus=`cat $SYSFS/devices/system/cpu/offline`
|
||||
@@ -151,6 +155,8 @@ online_cpus=0
|
||||
online_max=0
|
||||
offline_cpus=0
|
||||
offline_max=0
|
||||
present_cpus=0
|
||||
present_max=0
|
||||
|
||||
while getopts e:ahp: opt; do
|
||||
case $opt in
|
||||
@@ -190,9 +196,10 @@ if [ $allcpus -eq 0 ]; then
|
||||
online_cpu_expect_success $online_max
|
||||
|
||||
if [[ $offline_cpus -gt 0 ]]; then
|
||||
echo -e "\t offline to online to offline: cpu $offline_max"
|
||||
online_cpu_expect_success $offline_max
|
||||
offline_cpu_expect_success $offline_max
|
||||
echo -e "\t offline to online to offline: cpu $present_max"
|
||||
online_cpu_expect_success $present_max
|
||||
offline_cpu_expect_success $present_max
|
||||
online_cpu $present_max
|
||||
fi
|
||||
exit 0
|
||||
else
|
||||
|
1
tools/testing/selftests/filesystems/binderfs/.gitignore
vendored
Normal file
1
tools/testing/selftests/filesystems/binderfs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
binderfs_test
|
6
tools/testing/selftests/filesystems/binderfs/Makefile
Normal file
6
tools/testing/selftests/filesystems/binderfs/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
CFLAGS += -I../../../../../usr/include/
|
||||
TEST_GEN_PROGS := binderfs_test
|
||||
|
||||
include ../../lib.mk
|
275
tools/testing/selftests/filesystems/binderfs/binderfs_test.c
Normal file
275
tools/testing/selftests/filesystems/binderfs/binderfs_test.c
Normal file
@@ -0,0 +1,275 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/android/binder.h>
|
||||
#include <linux/android/binderfs.h>
|
||||
#include "../../kselftest.h"
|
||||
|
||||
static ssize_t write_nointr(int fd, const void *buf, size_t count)
|
||||
{
|
||||
ssize_t ret;
|
||||
again:
|
||||
ret = write(fd, buf, count);
|
||||
if (ret < 0 && errno == EINTR)
|
||||
goto again;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void write_to_file(const char *filename, const void *buf, size_t count,
|
||||
int allowed_errno)
|
||||
{
|
||||
int fd, saved_errno;
|
||||
ssize_t ret;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
ksft_exit_fail_msg("%s - Failed to open file %s\n",
|
||||
strerror(errno), filename);
|
||||
|
||||
ret = write_nointr(fd, buf, count);
|
||||
if (ret < 0) {
|
||||
if (allowed_errno && (errno == allowed_errno)) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if ((size_t)ret != count)
|
||||
goto on_error;
|
||||
|
||||
close(fd);
|
||||
return;
|
||||
|
||||
on_error:
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
errno = saved_errno;
|
||||
|
||||
if (ret < 0)
|
||||
ksft_exit_fail_msg("%s - Failed to write to file %s\n",
|
||||
strerror(errno), filename);
|
||||
|
||||
ksft_exit_fail_msg("Failed to write to file %s\n", filename);
|
||||
}
|
||||
|
||||
static void change_to_userns(void)
|
||||
{
|
||||
int ret;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
/* {g,u}id_map files only allow a max of 4096 bytes written to them */
|
||||
char idmap[4096];
|
||||
|
||||
uid = getuid();
|
||||
gid = getgid();
|
||||
|
||||
ret = unshare(CLONE_NEWUSER);
|
||||
if (ret < 0)
|
||||
ksft_exit_fail_msg("%s - Failed to unshare user namespace\n",
|
||||
strerror(errno));
|
||||
|
||||
write_to_file("/proc/self/setgroups", "deny", strlen("deny"), ENOENT);
|
||||
|
||||
ret = snprintf(idmap, sizeof(idmap), "0 %d 1", uid);
|
||||
if (ret < 0 || (size_t)ret >= sizeof(idmap))
|
||||
ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n",
|
||||
strerror(errno));
|
||||
|
||||
write_to_file("/proc/self/uid_map", idmap, strlen(idmap), 0);
|
||||
|
||||
ret = snprintf(idmap, sizeof(idmap), "0 %d 1", gid);
|
||||
if (ret < 0 || (size_t)ret >= sizeof(idmap))
|
||||
ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n",
|
||||
strerror(errno));
|
||||
|
||||
write_to_file("/proc/self/gid_map", idmap, strlen(idmap), 0);
|
||||
|
||||
ret = setgid(0);
|
||||
if (ret)
|
||||
ksft_exit_fail_msg("%s - Failed to setgid(0)\n",
|
||||
strerror(errno));
|
||||
|
||||
ret = setuid(0);
|
||||
if (ret)
|
||||
ksft_exit_fail_msg("%s - Failed to setgid(0)\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
static void change_to_mountns(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = unshare(CLONE_NEWNS);
|
||||
if (ret < 0)
|
||||
ksft_exit_fail_msg("%s - Failed to unshare mount namespace\n",
|
||||
strerror(errno));
|
||||
|
||||
ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
|
||||
if (ret < 0)
|
||||
ksft_exit_fail_msg("%s - Failed to mount / as private\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
static void rmdir_protect_errno(const char *dir)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
(void)rmdir(dir);
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
static void __do_binderfs_test(void)
|
||||
{
|
||||
int fd, ret, saved_errno;
|
||||
size_t len;
|
||||
ssize_t wret;
|
||||
bool keep = false;
|
||||
struct binderfs_device device = { 0 };
|
||||
struct binder_version version = { 0 };
|
||||
|
||||
change_to_mountns();
|
||||
|
||||
ret = mkdir("/dev/binderfs", 0755);
|
||||
if (ret < 0) {
|
||||
if (errno != EEXIST)
|
||||
ksft_exit_fail_msg(
|
||||
"%s - Failed to create binderfs mountpoint\n",
|
||||
strerror(errno));
|
||||
|
||||
keep = true;
|
||||
}
|
||||
|
||||
ret = mount(NULL, "/dev/binderfs", "binder", 0, 0);
|
||||
if (ret < 0) {
|
||||
if (errno != ENODEV)
|
||||
ksft_exit_fail_msg("%s - Failed to mount binderfs\n",
|
||||
strerror(errno));
|
||||
|
||||
keep ? : rmdir_protect_errno("/dev/binderfs");
|
||||
ksft_exit_skip(
|
||||
"The Android binderfs filesystem is not available\n");
|
||||
}
|
||||
|
||||
/* binderfs mount test passed */
|
||||
ksft_inc_pass_cnt();
|
||||
|
||||
memcpy(device.name, "my-binder", strlen("my-binder"));
|
||||
|
||||
fd = open("/dev/binderfs/binder-control", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
ksft_exit_fail_msg(
|
||||
"%s - Failed to open binder-control device\n",
|
||||
strerror(errno));
|
||||
|
||||
ret = ioctl(fd, BINDER_CTL_ADD, &device);
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
errno = saved_errno;
|
||||
if (ret < 0) {
|
||||
keep ? : rmdir_protect_errno("/dev/binderfs");
|
||||
ksft_exit_fail_msg(
|
||||
"%s - Failed to allocate new binder device\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
ksft_print_msg(
|
||||
"Allocated new binder device with major %d, minor %d, and name %s\n",
|
||||
device.major, device.minor, device.name);
|
||||
|
||||
/* binder device allocation test passed */
|
||||
ksft_inc_pass_cnt();
|
||||
|
||||
fd = open("/dev/binderfs/my-binder", O_CLOEXEC | O_RDONLY);
|
||||
if (fd < 0) {
|
||||
keep ? : rmdir_protect_errno("/dev/binderfs");
|
||||
ksft_exit_fail_msg("%s - Failed to open my-binder device\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
ret = ioctl(fd, BINDER_VERSION, &version);
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
errno = saved_errno;
|
||||
if (ret < 0) {
|
||||
keep ? : rmdir_protect_errno("/dev/binderfs");
|
||||
ksft_exit_fail_msg(
|
||||
"%s - Failed to open perform BINDER_VERSION request\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
ksft_print_msg("Detected binder version: %d\n",
|
||||
version.protocol_version);
|
||||
|
||||
/* binder transaction with binderfs binder device passed */
|
||||
ksft_inc_pass_cnt();
|
||||
|
||||
ret = unlink("/dev/binderfs/my-binder");
|
||||
if (ret < 0) {
|
||||
keep ? : rmdir_protect_errno("/dev/binderfs");
|
||||
ksft_exit_fail_msg("%s - Failed to delete binder device\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/* binder device removal passed */
|
||||
ksft_inc_pass_cnt();
|
||||
|
||||
ret = unlink("/dev/binderfs/binder-control");
|
||||
if (!ret) {
|
||||
keep ? : rmdir_protect_errno("/dev/binderfs");
|
||||
ksft_exit_fail_msg("Managed to delete binder-control device\n");
|
||||
} else if (errno != EPERM) {
|
||||
keep ? : rmdir_protect_errno("/dev/binderfs");
|
||||
ksft_exit_fail_msg(
|
||||
"%s - Failed to delete binder-control device but exited with unexpected error code\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/* binder-control device removal failed as expected */
|
||||
ksft_inc_xfail_cnt();
|
||||
|
||||
on_error:
|
||||
ret = umount2("/dev/binderfs", MNT_DETACH);
|
||||
keep ?: rmdir_protect_errno("/dev/binderfs");
|
||||
if (ret < 0)
|
||||
ksft_exit_fail_msg("%s - Failed to unmount binderfs\n",
|
||||
strerror(errno));
|
||||
|
||||
/* binderfs unmount test passed */
|
||||
ksft_inc_pass_cnt();
|
||||
}
|
||||
|
||||
static void binderfs_test_privileged()
|
||||
{
|
||||
if (geteuid() != 0)
|
||||
ksft_print_msg(
|
||||
"Tests are not run as root. Skipping privileged tests\n");
|
||||
else
|
||||
__do_binderfs_test();
|
||||
}
|
||||
|
||||
static void binderfs_test_unprivileged()
|
||||
{
|
||||
change_to_userns();
|
||||
__do_binderfs_test();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
binderfs_test_privileged();
|
||||
binderfs_test_unprivileged();
|
||||
ksft_exit_pass();
|
||||
}
|
3
tools/testing/selftests/filesystems/binderfs/config
Normal file
3
tools/testing/selftests/filesystems/binderfs/config
Normal file
@@ -0,0 +1,3 @@
|
||||
CONFIG_ANDROID=y
|
||||
CONFIG_ANDROID_BINDERFS=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
@@ -1,5 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
TEST_PROGS := ir_loopback.sh
|
||||
TEST_GEN_PROGS_EXTENDED := ir_loopback
|
||||
APIDIR := ../../../include/uapi
|
||||
CFLAGS += -Wall -O2 -I$(APIDIR)
|
||||
|
||||
include ../lib.mk
|
||||
|
@@ -21,6 +21,6 @@ TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls
|
||||
KSFT_KHDR_INSTALL := 1
|
||||
include ../lib.mk
|
||||
|
||||
$(OUTPUT)/reuseport_bpf_numa: LDFLAGS += -lnuma
|
||||
$(OUTPUT)/reuseport_bpf_numa: LDLIBS += -lnuma
|
||||
$(OUTPUT)/tcp_mmap: LDFLAGS += -lpthread
|
||||
$(OUTPUT)/tcp_inq: LDFLAGS += -lpthread
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Makefile for netfilter selftests
|
||||
|
||||
TEST_PROGS := nft_trans_stress.sh
|
||||
TEST_PROGS := nft_trans_stress.sh nft_nat.sh
|
||||
|
||||
include ../lib.mk
|
||||
|
@@ -1,2 +1,2 @@
|
||||
CONFIG_NET_NS=y
|
||||
NF_TABLES_INET=y
|
||||
CONFIG_NF_TABLES_INET=y
|
||||
|
762
tools/testing/selftests/netfilter/nft_nat.sh
Executable file
762
tools/testing/selftests/netfilter/nft_nat.sh
Executable file
@@ -0,0 +1,762 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This test is for basic NAT functionality: snat, dnat, redirect, masquerade.
|
||||
#
|
||||
|
||||
# Kselftest framework requirement - SKIP code is 4.
|
||||
ksft_skip=4
|
||||
ret=0
|
||||
|
||||
nft --version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
echo "SKIP: Could not run test without nft tool"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
ip -Version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
echo "SKIP: Could not run test without ip tool"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
ip netns add ns0
|
||||
ip netns add ns1
|
||||
ip netns add ns2
|
||||
|
||||
ip link add veth0 netns ns0 type veth peer name eth0 netns ns1
|
||||
ip link add veth1 netns ns0 type veth peer name eth0 netns ns2
|
||||
|
||||
ip -net ns0 link set lo up
|
||||
ip -net ns0 link set veth0 up
|
||||
ip -net ns0 addr add 10.0.1.1/24 dev veth0
|
||||
ip -net ns0 addr add dead:1::1/64 dev veth0
|
||||
|
||||
ip -net ns0 link set veth1 up
|
||||
ip -net ns0 addr add 10.0.2.1/24 dev veth1
|
||||
ip -net ns0 addr add dead:2::1/64 dev veth1
|
||||
|
||||
for i in 1 2; do
|
||||
ip -net ns$i link set lo up
|
||||
ip -net ns$i link set eth0 up
|
||||
ip -net ns$i addr add 10.0.$i.99/24 dev eth0
|
||||
ip -net ns$i route add default via 10.0.$i.1
|
||||
ip -net ns$i addr add dead:$i::99/64 dev eth0
|
||||
ip -net ns$i route add default via dead:$i::1
|
||||
done
|
||||
|
||||
bad_counter()
|
||||
{
|
||||
local ns=$1
|
||||
local counter=$2
|
||||
local expect=$3
|
||||
|
||||
echo "ERROR: $counter counter in $ns has unexpected value (expected $expect)" 1>&2
|
||||
ip netns exec $ns nft list counter inet filter $counter 1>&2
|
||||
}
|
||||
|
||||
check_counters()
|
||||
{
|
||||
ns=$1
|
||||
local lret=0
|
||||
|
||||
cnt=$(ip netns exec $ns nft list counter inet filter ns0in | grep -q "packets 1 bytes 84")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter $ns ns0in "packets 1 bytes 84"
|
||||
lret=1
|
||||
fi
|
||||
cnt=$(ip netns exec $ns nft list counter inet filter ns0out | grep -q "packets 1 bytes 84")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter $ns ns0out "packets 1 bytes 84"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
expect="packets 1 bytes 104"
|
||||
cnt=$(ip netns exec $ns nft list counter inet filter ns0in6 | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter $ns ns0in6 "$expect"
|
||||
lret=1
|
||||
fi
|
||||
cnt=$(ip netns exec $ns nft list counter inet filter ns0out6 | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter $ns ns0out6 "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
check_ns0_counters()
|
||||
{
|
||||
local ns=$1
|
||||
local lret=0
|
||||
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns0in | grep -q "packets 0 bytes 0")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns0in "packets 0 bytes 0"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns0in6 | grep -q "packets 0 bytes 0")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns0in6 "packets 0 bytes 0"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns0out | grep -q "packets 0 bytes 0")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns0out "packets 0 bytes 0"
|
||||
lret=1
|
||||
fi
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns0out6 | grep -q "packets 0 bytes 0")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns0out6 "packets 0 bytes 0"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
for dir in "in" "out" ; do
|
||||
expect="packets 1 bytes 84"
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ${ns}${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 $ns$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
expect="packets 1 bytes 104"
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ${ns}${dir}6 | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 $ns$dir6 "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
reset_counters()
|
||||
{
|
||||
for i in 0 1 2;do
|
||||
ip netns exec ns$i nft reset counters inet > /dev/null
|
||||
done
|
||||
}
|
||||
|
||||
test_local_dnat6()
|
||||
{
|
||||
local lret=0
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip6 nat {
|
||||
chain output {
|
||||
type nat hook output priority 0; policy accept;
|
||||
ip6 daddr dead:1::99 dnat to dead:2::99
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add add ip6 dnat hook"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
# ping netns1, expect rewrite to netns2
|
||||
ip netns exec ns0 ping -q -c 1 dead:1::99 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
lret=1
|
||||
echo "ERROR: ping6 failed"
|
||||
return $lret
|
||||
fi
|
||||
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
expect="packets 1 bytes 104"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# expect 0 count in ns1
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# expect 1 packet in ns2
|
||||
expect="packets 1 bytes 104"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
test $lret -eq 0 && echo "PASS: ipv6 ping to ns1 was NATted to ns2"
|
||||
ip netns exec ns0 nft flush chain ip6 nat output
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
test_local_dnat()
|
||||
{
|
||||
local lret=0
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip nat {
|
||||
chain output {
|
||||
type nat hook output priority 0; policy accept;
|
||||
ip daddr 10.0.1.99 dnat to 10.0.2.99
|
||||
}
|
||||
}
|
||||
EOF
|
||||
# ping netns1, expect rewrite to netns2
|
||||
ip netns exec ns0 ping -q -c 1 10.0.1.99 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
lret=1
|
||||
echo "ERROR: ping failed"
|
||||
return $lret
|
||||
fi
|
||||
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# expect 0 count in ns1
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# expect 1 packet in ns2
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
test $lret -eq 0 && echo "PASS: ping to ns1 was NATted to ns2"
|
||||
|
||||
ip netns exec ns0 nft flush chain ip nat output
|
||||
|
||||
reset_counters
|
||||
ip netns exec ns0 ping -q -c 1 10.0.1.99 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
lret=1
|
||||
echo "ERROR: ping failed"
|
||||
return $lret
|
||||
fi
|
||||
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# expect 1 count in ns1
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns0 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# expect 0 packet in ns2
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
test $lret -eq 0 && echo "PASS: ping to ns1 OK after nat output chain flush"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
|
||||
test_masquerade6()
|
||||
{
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 via ipv6"
|
||||
return 1
|
||||
lret=1
|
||||
fi
|
||||
|
||||
expect="packets 1 bytes 104"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
reset_counters
|
||||
|
||||
# add masquerading rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip6 nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority 0; policy accept;
|
||||
meta oif veth0 masquerade
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ipv6 masquerading"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
# ns1 should have seen packets from ns0, due to masquerade
|
||||
expect="packets 1 bytes 104"
|
||||
for dir in "in6" "out6" ; do
|
||||
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# ns1 should not have seen packets from ns2, due to masquerade
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft flush chain ip6 nat postrouting
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not flush ip6 nat postrouting" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IPv6 masquerade for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
test_masquerade()
|
||||
{
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
|
||||
ip netns exec ns0 sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: canot ping ns1 from ns2"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
reset_counters
|
||||
|
||||
# add masquerading rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority 0; policy accept;
|
||||
meta oif veth0 masquerade
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ip masquerading"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
# ns1 should have seen packets from ns0, due to masquerade
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# ns1 should not have seen packets from ns2, due to masquerade
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft flush chain ip nat postrouting
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not flush nat postrouting" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IP masquerade for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
test_redirect6()
|
||||
{
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannnot ping ns1 from ns2 via ipv6"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
expect="packets 1 bytes 104"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
reset_counters
|
||||
|
||||
# add redirect rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip6 nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority 0; policy accept;
|
||||
meta iif veth1 meta l4proto icmpv6 ip6 saddr dead:2::99 ip6 daddr dead:1::99 redirect
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ip6 redirect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
# ns1 should have seen no packets from ns2, due to redirection
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# ns0 should have seen packets from ns2, due to masquerade
|
||||
expect="packets 1 bytes 104"
|
||||
for dir in "in6" "out6" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft delete table ip6 nat
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not delete ip6 nat table" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IPv6 redirection for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
test_redirect()
|
||||
{
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
|
||||
ip netns exec ns0 sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns2$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns2 ns1$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
reset_counters
|
||||
|
||||
# add redirect rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority 0; policy accept;
|
||||
meta iif veth1 ip protocol icmp ip saddr 10.0.2.99 ip daddr 10.0.1.99 redirect
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ip redirect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
# ns1 should have seen no packets from ns2, due to redirection
|
||||
expect="packets 0 bytes 0"
|
||||
for dir in "in" "out" ; do
|
||||
|
||||
cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
# ns0 should have seen packets from ns2, due to masquerade
|
||||
expect="packets 1 bytes 84"
|
||||
for dir in "in" "out" ; do
|
||||
cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect")
|
||||
if [ $? -ne 0 ]; then
|
||||
bad_counter ns1 ns0$dir "$expect"
|
||||
lret=1
|
||||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft delete table ip nat
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not delete nat table" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IP redirection for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
|
||||
# ip netns exec ns0 ping -c 1 -q 10.0.$i.99
|
||||
for i in 0 1 2; do
|
||||
ip netns exec ns$i nft -f - <<EOF
|
||||
table inet filter {
|
||||
counter ns0in {}
|
||||
counter ns1in {}
|
||||
counter ns2in {}
|
||||
|
||||
counter ns0out {}
|
||||
counter ns1out {}
|
||||
counter ns2out {}
|
||||
|
||||
counter ns0in6 {}
|
||||
counter ns1in6 {}
|
||||
counter ns2in6 {}
|
||||
|
||||
counter ns0out6 {}
|
||||
counter ns1out6 {}
|
||||
counter ns2out6 {}
|
||||
|
||||
map nsincounter {
|
||||
type ipv4_addr : counter
|
||||
elements = { 10.0.1.1 : "ns0in",
|
||||
10.0.2.1 : "ns0in",
|
||||
10.0.1.99 : "ns1in",
|
||||
10.0.2.99 : "ns2in" }
|
||||
}
|
||||
|
||||
map nsincounter6 {
|
||||
type ipv6_addr : counter
|
||||
elements = { dead:1::1 : "ns0in6",
|
||||
dead:2::1 : "ns0in6",
|
||||
dead:1::99 : "ns1in6",
|
||||
dead:2::99 : "ns2in6" }
|
||||
}
|
||||
|
||||
map nsoutcounter {
|
||||
type ipv4_addr : counter
|
||||
elements = { 10.0.1.1 : "ns0out",
|
||||
10.0.2.1 : "ns0out",
|
||||
10.0.1.99: "ns1out",
|
||||
10.0.2.99: "ns2out" }
|
||||
}
|
||||
|
||||
map nsoutcounter6 {
|
||||
type ipv6_addr : counter
|
||||
elements = { dead:1::1 : "ns0out6",
|
||||
dead:2::1 : "ns0out6",
|
||||
dead:1::99 : "ns1out6",
|
||||
dead:2::99 : "ns2out6" }
|
||||
}
|
||||
|
||||
chain input {
|
||||
type filter hook input priority 0; policy accept;
|
||||
counter name ip saddr map @nsincounter
|
||||
icmpv6 type { "echo-request", "echo-reply" } counter name ip6 saddr map @nsincounter6
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
counter name ip daddr map @nsoutcounter
|
||||
icmpv6 type { "echo-request", "echo-reply" } counter name ip6 daddr map @nsoutcounter6
|
||||
}
|
||||
}
|
||||
EOF
|
||||
done
|
||||
|
||||
sleep 3
|
||||
# test basic connectivity
|
||||
for i in 1 2; do
|
||||
ip netns exec ns0 ping -c 1 -q 10.0.$i.99 > /dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: Could not reach other namespace(s)" 1>&2
|
||||
ret=1
|
||||
fi
|
||||
|
||||
ip netns exec ns0 ping -c 1 -q dead:$i::99 > /dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
echo "ERROR: Could not reach other namespace(s) via ipv6" 1>&2
|
||||
ret=1
|
||||
fi
|
||||
check_counters ns$i
|
||||
if [ $? -ne 0 ]; then
|
||||
ret=1
|
||||
fi
|
||||
|
||||
check_ns0_counters ns$i
|
||||
if [ $? -ne 0 ]; then
|
||||
ret=1
|
||||
fi
|
||||
reset_counters
|
||||
done
|
||||
|
||||
if [ $ret -eq 0 ];then
|
||||
echo "PASS: netns routing/connectivity: ns0 can reach ns1 and ns2"
|
||||
fi
|
||||
|
||||
reset_counters
|
||||
test_local_dnat
|
||||
test_local_dnat6
|
||||
|
||||
reset_counters
|
||||
test_masquerade
|
||||
test_masquerade6
|
||||
|
||||
reset_counters
|
||||
test_redirect
|
||||
test_redirect6
|
||||
|
||||
for i in 0 1 2; do ip netns del ns$i;done
|
||||
|
||||
exit $ret
|
1
tools/testing/selftests/proc/.gitignore
vendored
1
tools/testing/selftests/proc/.gitignore
vendored
@@ -10,4 +10,5 @@
|
||||
/proc-uptime-002
|
||||
/read
|
||||
/self
|
||||
/setns-dcache
|
||||
/thread-self
|
||||
|
@@ -14,6 +14,7 @@ TEST_GEN_PROGS += proc-uptime-001
|
||||
TEST_GEN_PROGS += proc-uptime-002
|
||||
TEST_GEN_PROGS += read
|
||||
TEST_GEN_PROGS += self
|
||||
TEST_GEN_PROGS += setns-dcache
|
||||
TEST_GEN_PROGS += thread-self
|
||||
|
||||
include ../lib.mk
|
||||
|
129
tools/testing/selftests/proc/setns-dcache.c
Normal file
129
tools/testing/selftests/proc/setns-dcache.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright © 2019 Alexey Dobriyan <adobriyan@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* Test that setns(CLONE_NEWNET) points to new /proc/net content even
|
||||
* if old one is in dcache.
|
||||
*
|
||||
* FIXME /proc/net/unix is under CONFIG_UNIX which can be disabled.
|
||||
*/
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
static pid_t pid = -1;
|
||||
|
||||
static void f(void)
|
||||
{
|
||||
if (pid > 0) {
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fd[2];
|
||||
char _ = 0;
|
||||
int nsfd;
|
||||
|
||||
atexit(f);
|
||||
|
||||
/* Check for priviledges and syscall availability straight away. */
|
||||
if (unshare(CLONE_NEWNET) == -1) {
|
||||
if (errno == ENOSYS || errno == EPERM) {
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* Distinguisher between two otherwise empty net namespaces. */
|
||||
if (socket(AF_UNIX, SOCK_STREAM, 0) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pipe(fd) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (unshare(CLONE_NEWNET) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (write(fd[1], &_, 1) != 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pause();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read(fd[0], &_, 1) != 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "/proc/%u/ns/net", pid);
|
||||
nsfd = open(buf, O_RDONLY);
|
||||
if (nsfd == -1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reliably pin dentry into dcache. */
|
||||
(void)open("/proc/net/unix", O_RDONLY);
|
||||
|
||||
if (setns(nsfd, CLONE_NEWNET) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
kill(pid, SIGTERM);
|
||||
pid = 0;
|
||||
|
||||
{
|
||||
char buf[4096];
|
||||
ssize_t rv;
|
||||
int fd;
|
||||
|
||||
fd = open("/proc/net/unix", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define S "Num RefCount Protocol Flags Type St Inode Path\n"
|
||||
rv = read(fd, buf, sizeof(buf));
|
||||
|
||||
assert(rv == strlen(S));
|
||||
assert(memcmp(buf, S, strlen(S)) == 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1608,7 +1608,16 @@ TEST_F(TRACE_poke, getpid_runs_normally)
|
||||
#ifdef SYSCALL_NUM_RET_SHARE_REG
|
||||
# define EXPECT_SYSCALL_RETURN(val, action) EXPECT_EQ(-1, action)
|
||||
#else
|
||||
# define EXPECT_SYSCALL_RETURN(val, action) EXPECT_EQ(val, action)
|
||||
# define EXPECT_SYSCALL_RETURN(val, action) \
|
||||
do { \
|
||||
errno = 0; \
|
||||
if (val < 0) { \
|
||||
EXPECT_EQ(-1, action); \
|
||||
EXPECT_EQ(-(val), errno); \
|
||||
} else { \
|
||||
EXPECT_EQ(val, action); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for
|
||||
@@ -1647,7 +1656,7 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
|
||||
|
||||
/* Architecture-specific syscall changing routine. */
|
||||
void change_syscall(struct __test_metadata *_metadata,
|
||||
pid_t tracee, int syscall)
|
||||
pid_t tracee, int syscall, int result)
|
||||
{
|
||||
int ret;
|
||||
ARCH_REGS regs;
|
||||
@@ -1706,7 +1715,7 @@ void change_syscall(struct __test_metadata *_metadata,
|
||||
#ifdef SYSCALL_NUM_RET_SHARE_REG
|
||||
TH_LOG("Can't modify syscall return on this architecture");
|
||||
#else
|
||||
regs.SYSCALL_RET = EPERM;
|
||||
regs.SYSCALL_RET = result;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETREGS
|
||||
@@ -1734,14 +1743,19 @@ void tracer_syscall(struct __test_metadata *_metadata, pid_t tracee,
|
||||
case 0x1002:
|
||||
/* change getpid to getppid. */
|
||||
EXPECT_EQ(__NR_getpid, get_syscall(_metadata, tracee));
|
||||
change_syscall(_metadata, tracee, __NR_getppid);
|
||||
change_syscall(_metadata, tracee, __NR_getppid, 0);
|
||||
break;
|
||||
case 0x1003:
|
||||
/* skip gettid. */
|
||||
/* skip gettid with valid return code. */
|
||||
EXPECT_EQ(__NR_gettid, get_syscall(_metadata, tracee));
|
||||
change_syscall(_metadata, tracee, -1);
|
||||
change_syscall(_metadata, tracee, -1, 45000);
|
||||
break;
|
||||
case 0x1004:
|
||||
/* skip openat with error. */
|
||||
EXPECT_EQ(__NR_openat, get_syscall(_metadata, tracee));
|
||||
change_syscall(_metadata, tracee, -1, -ESRCH);
|
||||
break;
|
||||
case 0x1005:
|
||||
/* do nothing (allow getppid) */
|
||||
EXPECT_EQ(__NR_getppid, get_syscall(_metadata, tracee));
|
||||
break;
|
||||
@@ -1774,9 +1788,11 @@ void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,
|
||||
nr = get_syscall(_metadata, tracee);
|
||||
|
||||
if (nr == __NR_getpid)
|
||||
change_syscall(_metadata, tracee, __NR_getppid);
|
||||
change_syscall(_metadata, tracee, __NR_getppid, 0);
|
||||
if (nr == __NR_gettid)
|
||||
change_syscall(_metadata, tracee, -1, 45000);
|
||||
if (nr == __NR_openat)
|
||||
change_syscall(_metadata, tracee, -1);
|
||||
change_syscall(_metadata, tracee, -1, -ESRCH);
|
||||
}
|
||||
|
||||
FIXTURE_DATA(TRACE_syscall) {
|
||||
@@ -1793,8 +1809,10 @@ FIXTURE_SETUP(TRACE_syscall)
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1002),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_gettid, 0, 1),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1003),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_openat, 0, 1),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1004),
|
||||
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1005),
|
||||
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
|
||||
@@ -1842,15 +1860,26 @@ TEST_F(TRACE_syscall, ptrace_syscall_redirected)
|
||||
EXPECT_NE(self->mypid, syscall(__NR_getpid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, ptrace_syscall_dropped)
|
||||
TEST_F(TRACE_syscall, ptrace_syscall_errno)
|
||||
{
|
||||
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL,
|
||||
true);
|
||||
|
||||
/* Tracer should skip the open syscall, resulting in EPERM. */
|
||||
EXPECT_SYSCALL_RETURN(EPERM, syscall(__NR_openat));
|
||||
/* Tracer should skip the open syscall, resulting in ESRCH. */
|
||||
EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, ptrace_syscall_faked)
|
||||
{
|
||||
/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */
|
||||
teardown_trace_fixture(_metadata, self->tracer);
|
||||
self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL,
|
||||
true);
|
||||
|
||||
/* Tracer should skip the gettid syscall, resulting fake pid. */
|
||||
EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, syscall_allowed)
|
||||
@@ -1883,7 +1912,21 @@ TEST_F(TRACE_syscall, syscall_redirected)
|
||||
EXPECT_NE(self->mypid, syscall(__NR_getpid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, syscall_dropped)
|
||||
TEST_F(TRACE_syscall, syscall_errno)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* openat has been skipped and an errno return. */
|
||||
EXPECT_SYSCALL_RETURN(-ESRCH, syscall(__NR_openat));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, syscall_faked)
|
||||
{
|
||||
long ret;
|
||||
|
||||
@@ -1894,8 +1937,7 @@ TEST_F(TRACE_syscall, syscall_dropped)
|
||||
ASSERT_EQ(0, ret);
|
||||
|
||||
/* gettid has been skipped and an altered return value stored. */
|
||||
EXPECT_SYSCALL_RETURN(EPERM, syscall(__NR_gettid));
|
||||
EXPECT_NE(self->mytid, syscall(__NR_gettid));
|
||||
EXPECT_SYSCALL_RETURN(45000, syscall(__NR_gettid));
|
||||
}
|
||||
|
||||
TEST_F(TRACE_syscall, skip_after_RET_TRACE)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
CFLAGS += -O3 -Wl,-no-as-needed -Wall
|
||||
LDFLAGS += -lrt -lpthread -lm
|
||||
LDLIBS += -lrt -lpthread -lm
|
||||
|
||||
# these are all "safe" tests that don't modify
|
||||
# system time or require escalated privileges
|
||||
|
Reference in New Issue
Block a user