Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Highlights: - Gustavo A. R. Silva keeps working on the implicit switch fallthru changes. - Support 802.11ax High-Efficiency wireless in cfg80211 et al, From Luca Coelho. - Re-enable ASPM in r8169, from Kai-Heng Feng. - Add virtual XFRM interfaces, which avoids all of the limitations of existing IPSEC tunnels. From Steffen Klassert. - Convert GRO over to use a hash table, so that when we have many flows active we don't traverse a long list during accumluation. - Many new self tests for routing, TC, tunnels, etc. Too many contributors to mention them all, but I'm really happy to keep seeing this stuff. - Hardware timestamping support for dpaa_eth/fsl-fman from Yangbo Lu. - Lots of cleanups and fixes in L2TP code from Guillaume Nault. - Add IPSEC offload support to netdevsim, from Shannon Nelson. - Add support for slotting with non-uniform distribution to netem packet scheduler, from Yousuk Seung. - Add UDP GSO support to mlx5e, from Boris Pismenny. - Support offloading of Team LAG in NFP, from John Hurley. - Allow to configure TX queue selection based upon RX queue, from Amritha Nambiar. - Support ethtool ring size configuration in aquantia, from Anton Mikaev. - Support DSCP and flowlabel per-transport in SCTP, from Xin Long. - Support list based batching and stack traversal of SKBs, this is very exciting work. From Edward Cree. - Busyloop optimizations in vhost_net, from Toshiaki Makita. - Introduce the ETF qdisc, which allows time based transmissions. IGB can offload this in hardware. From Vinicius Costa Gomes. - Add parameter support to devlink, from Moshe Shemesh. - Several multiplication and division optimizations for BPF JIT in nfp driver, from Jiong Wang. - Lots of prepatory work to make more of the packet scheduler layer lockless, when possible, from Vlad Buslov. - Add ACK filter and NAT awareness to sch_cake packet scheduler, from Toke Høiland-Jørgensen. - Support regions and region snapshots in devlink, from Alex Vesker. - Allow to attach XDP programs to both HW and SW at the same time on a given device, with initial support in nfp. From Jakub Kicinski. - Add TLS RX offload and support in mlx5, from Ilya Lesokhin. - Use PHYLIB in r8169 driver, from Heiner Kallweit. - All sorts of changes to support Spectrum 2 in mlxsw driver, from Ido Schimmel. - PTP support in mv88e6xxx DSA driver, from Andrew Lunn. - Make TCP_USER_TIMEOUT socket option more accurate, from Jon Maxwell. - Support for templates in packet scheduler classifier, from Jiri Pirko. - IPV6 support in RDS, from Ka-Cheong Poon. - Native tproxy support in nf_tables, from Máté Eckl. - Maintain IP fragment queue in an rbtree, but optimize properly for in-order frags. From Peter Oskolkov. - Improvde handling of ACKs on hole repairs, from Yuchung Cheng" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1996 commits) bpf: test: fix spelling mistake "REUSEEPORT" -> "REUSEPORT" hv/netvsc: Fix NULL dereference at single queue mode fallback net: filter: mark expected switch fall-through xen-netfront: fix warn message as irq device name has '/' cxgb4: Add new T5 PCI device ids 0x50af and 0x50b0 net: dsa: mv88e6xxx: missing unlock on error path rds: fix building with IPV6=m inet/connection_sock: prefer _THIS_IP_ to current_text_addr net: dsa: mv88e6xxx: bitwise vs logical bug net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd() ieee802154: hwsim: using right kind of iteration net: hns3: Add vlan filter setting by ethtool command -K net: hns3: Set tx ring' tc info when netdev is up net: hns3: Remove tx ring BD len register in hns3_enet net: hns3: Fix desc num set to default when setting channel net: hns3: Fix for phy link issue when using marvell phy driver net: hns3: Fix for information of phydev lost problem when down/up net: hns3: Fix for command format parsing error in hclge_is_all_function_id_zero net: hns3: Add support for serdes loopback selftest bnxt_en: take coredump_record structure off stack ...
This commit is contained in:
@@ -22,7 +22,8 @@ $(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c
|
||||
# Order correspond to 'make run_tests' order
|
||||
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
|
||||
test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \
|
||||
test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user
|
||||
test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \
|
||||
test_socket_cookie test_cgroup_storage test_select_reuseport
|
||||
|
||||
TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
|
||||
test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \
|
||||
@@ -33,7 +34,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
|
||||
test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o \
|
||||
test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \
|
||||
test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \
|
||||
get_cgroup_id_kern.o
|
||||
get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \
|
||||
test_skb_cgroup_id_kern.o
|
||||
|
||||
# Order correspond to 'make run_tests' order
|
||||
TEST_PROGS := test_kmod.sh \
|
||||
@@ -44,10 +46,11 @@ TEST_PROGS := test_kmod.sh \
|
||||
test_sock_addr.sh \
|
||||
test_tunnel.sh \
|
||||
test_lwt_seg6local.sh \
|
||||
test_lirc_mode2.sh
|
||||
test_lirc_mode2.sh \
|
||||
test_skb_cgroup_id.sh
|
||||
|
||||
# Compile but not part of 'make run_tests'
|
||||
TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr
|
||||
TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user
|
||||
|
||||
include ../lib.mk
|
||||
|
||||
@@ -58,11 +61,15 @@ $(TEST_GEN_PROGS): $(BPFOBJ)
|
||||
$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
|
||||
|
||||
$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
|
||||
$(OUTPUT)/test_skb_cgroup_id_user: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sock: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sock_addr: cgroup_helpers.c
|
||||
$(OUTPUT)/test_socket_cookie: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sockmap: cgroup_helpers.c
|
||||
$(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c
|
||||
$(OUTPUT)/test_progs: trace_helpers.c
|
||||
$(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c
|
||||
$(OUTPUT)/test_cgroup_storage: cgroup_helpers.c
|
||||
|
||||
.PHONY: force
|
||||
|
||||
|
@@ -65,6 +65,8 @@ static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
|
||||
(void *) BPF_FUNC_xdp_adjust_head;
|
||||
static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) =
|
||||
(void *) BPF_FUNC_xdp_adjust_meta;
|
||||
static int (*bpf_get_socket_cookie)(void *ctx) =
|
||||
(void *) BPF_FUNC_get_socket_cookie;
|
||||
static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval,
|
||||
int optlen) =
|
||||
(void *) BPF_FUNC_setsockopt;
|
||||
@@ -109,6 +111,8 @@ static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) =
|
||||
static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state,
|
||||
int size, int flags) =
|
||||
(void *) BPF_FUNC_skb_get_xfrm_state;
|
||||
static int (*bpf_sk_select_reuseport)(void *ctx, void *map, void *key, __u32 flags) =
|
||||
(void *) BPF_FUNC_sk_select_reuseport;
|
||||
static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) =
|
||||
(void *) BPF_FUNC_get_stack;
|
||||
static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params,
|
||||
@@ -133,6 +137,12 @@ static int (*bpf_rc_keydown)(void *ctx, unsigned int protocol,
|
||||
(void *) BPF_FUNC_rc_keydown;
|
||||
static unsigned long long (*bpf_get_current_cgroup_id)(void) =
|
||||
(void *) BPF_FUNC_get_current_cgroup_id;
|
||||
static void *(*bpf_get_local_storage)(void *map, unsigned long long flags) =
|
||||
(void *) BPF_FUNC_get_local_storage;
|
||||
static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) =
|
||||
(void *) BPF_FUNC_skb_cgroup_id;
|
||||
static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) =
|
||||
(void *) BPF_FUNC_skb_ancestor_cgroup_id;
|
||||
|
||||
/* llvm builtin functions that eBPF C program may use to
|
||||
* emit BPF_LD_ABS and BPF_LD_IND instructions
|
||||
@@ -169,6 +179,8 @@ struct bpf_map_def {
|
||||
|
||||
static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) =
|
||||
(void *) BPF_FUNC_skb_load_bytes;
|
||||
static int (*bpf_skb_load_bytes_relative)(void *ctx, int off, void *to, int len, __u32 start_header) =
|
||||
(void *) BPF_FUNC_skb_load_bytes_relative;
|
||||
static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =
|
||||
(void *) BPF_FUNC_skb_store_bytes;
|
||||
static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) =
|
||||
|
@@ -44,4 +44,8 @@ static inline unsigned int bpf_num_possible_cpus(void)
|
||||
name[bpf_num_possible_cpus()]
|
||||
#define bpf_percpu(name, cpu) name[(cpu)].v
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#endif /* __BPF_UTIL__ */
|
||||
|
@@ -118,7 +118,7 @@ static int join_cgroup_from_top(char *cgroup_path)
|
||||
*
|
||||
* On success, it returns 0, otherwise on failure it returns 1.
|
||||
*/
|
||||
int join_cgroup(char *path)
|
||||
int join_cgroup(const char *path)
|
||||
{
|
||||
char cgroup_path[PATH_MAX + 1];
|
||||
|
||||
@@ -158,7 +158,7 @@ void cleanup_cgroup_environment(void)
|
||||
* On success, it returns the file descriptor. On failure it returns 0.
|
||||
* If there is a failure, it prints the error to stderr.
|
||||
*/
|
||||
int create_and_get_cgroup(char *path)
|
||||
int create_and_get_cgroup(const char *path)
|
||||
{
|
||||
char cgroup_path[PATH_MAX + 1];
|
||||
int fd;
|
||||
@@ -186,7 +186,7 @@ int create_and_get_cgroup(char *path)
|
||||
* which is an invalid cgroup id.
|
||||
* If there is a failure, it prints the error to stderr.
|
||||
*/
|
||||
unsigned long long get_cgroup_id(char *path)
|
||||
unsigned long long get_cgroup_id(const char *path)
|
||||
{
|
||||
int dirfd, err, flags, mount_id, fhsize;
|
||||
union {
|
||||
|
@@ -9,10 +9,10 @@
|
||||
__FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
|
||||
int create_and_get_cgroup(char *path);
|
||||
int join_cgroup(char *path);
|
||||
int create_and_get_cgroup(const char *path);
|
||||
int join_cgroup(const char *path);
|
||||
int setup_cgroup_environment(void);
|
||||
void cleanup_cgroup_environment(void);
|
||||
unsigned long long get_cgroup_id(char *path);
|
||||
unsigned long long get_cgroup_id(const char *path);
|
||||
|
||||
#endif
|
||||
|
60
tools/testing/selftests/bpf/socket_cookie_prog.c
Normal file
60
tools/testing/selftests/bpf/socket_cookie_prog.c
Normal file
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_endian.h"
|
||||
|
||||
struct bpf_map_def SEC("maps") socket_cookies = {
|
||||
.type = BPF_MAP_TYPE_HASH,
|
||||
.key_size = sizeof(__u64),
|
||||
.value_size = sizeof(__u32),
|
||||
.max_entries = 1 << 8,
|
||||
};
|
||||
|
||||
SEC("cgroup/connect6")
|
||||
int set_cookie(struct bpf_sock_addr *ctx)
|
||||
{
|
||||
__u32 cookie_value = 0xFF;
|
||||
__u64 cookie_key;
|
||||
|
||||
if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6)
|
||||
return 1;
|
||||
|
||||
cookie_key = bpf_get_socket_cookie(ctx);
|
||||
if (bpf_map_update_elem(&socket_cookies, &cookie_key, &cookie_value, 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("sockops")
|
||||
int update_cookie(struct bpf_sock_ops *ctx)
|
||||
{
|
||||
__u32 new_cookie_value;
|
||||
__u32 *cookie_value;
|
||||
__u64 cookie_key;
|
||||
|
||||
if (ctx->family != AF_INET6)
|
||||
return 1;
|
||||
|
||||
if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB)
|
||||
return 1;
|
||||
|
||||
cookie_key = bpf_get_socket_cookie(ctx);
|
||||
|
||||
cookie_value = bpf_map_lookup_elem(&socket_cookies, &cookie_key);
|
||||
if (!cookie_value)
|
||||
return 1;
|
||||
|
||||
new_cookie_value = (ctx->local_port << 8) | *cookie_value;
|
||||
bpf_map_update_elem(&socket_cookies, &cookie_key, &new_cookie_value, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
@@ -9,11 +9,11 @@ import subprocess
|
||||
import select
|
||||
|
||||
def read(sock, n):
|
||||
buf = ''
|
||||
buf = b''
|
||||
while len(buf) < n:
|
||||
rem = n - len(buf)
|
||||
try: s = sock.recv(rem)
|
||||
except (socket.error), e: return ''
|
||||
except (socket.error) as e: return b''
|
||||
buf += s
|
||||
return buf
|
||||
|
||||
@@ -22,7 +22,7 @@ def send(sock, s):
|
||||
count = 0
|
||||
while count < total:
|
||||
try: n = sock.send(s)
|
||||
except (socket.error), e: n = 0
|
||||
except (socket.error) as e: n = 0
|
||||
if n == 0:
|
||||
return count;
|
||||
count += n
|
||||
@@ -39,10 +39,10 @@ try:
|
||||
except socket.error as e:
|
||||
sys.exit(1)
|
||||
|
||||
buf = ''
|
||||
buf = b''
|
||||
n = 0
|
||||
while n < 1000:
|
||||
buf += '+'
|
||||
buf += b'+'
|
||||
n += 1
|
||||
|
||||
sock.settimeout(1);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
@@ -9,11 +9,11 @@ import subprocess
|
||||
import select
|
||||
|
||||
def read(sock, n):
|
||||
buf = ''
|
||||
buf = b''
|
||||
while len(buf) < n:
|
||||
rem = n - len(buf)
|
||||
try: s = sock.recv(rem)
|
||||
except (socket.error), e: return ''
|
||||
except (socket.error) as e: return b''
|
||||
buf += s
|
||||
return buf
|
||||
|
||||
@@ -22,7 +22,7 @@ def send(sock, s):
|
||||
count = 0
|
||||
while count < total:
|
||||
try: n = sock.send(s)
|
||||
except (socket.error), e: n = 0
|
||||
except (socket.error) as e: n = 0
|
||||
if n == 0:
|
||||
return count;
|
||||
count += n
|
||||
@@ -43,7 +43,7 @@ host = socket.gethostname()
|
||||
|
||||
try: serverSocket.bind((host, 0))
|
||||
except socket.error as msg:
|
||||
print 'bind fails: ', msg
|
||||
print('bind fails: ' + str(msg))
|
||||
|
||||
sn = serverSocket.getsockname()
|
||||
serverPort = sn[1]
|
||||
@@ -51,10 +51,10 @@ serverPort = sn[1]
|
||||
cmdStr = ("./tcp_client.py %d &") % (serverPort)
|
||||
os.system(cmdStr)
|
||||
|
||||
buf = ''
|
||||
buf = b''
|
||||
n = 0
|
||||
while n < 500:
|
||||
buf += '.'
|
||||
buf += b'.'
|
||||
n += 1
|
||||
|
||||
serverSocket.listen(MAX_PORTS)
|
||||
@@ -79,5 +79,5 @@ while True:
|
||||
serverSocket.close()
|
||||
sys.exit(0)
|
||||
else:
|
||||
print 'Select timeout!'
|
||||
print('Select timeout!')
|
||||
sys.exit(1)
|
||||
|
@@ -18,10 +18,7 @@
|
||||
|
||||
#include "../../../include/linux/filter.h"
|
||||
#include "bpf_rlimit.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
#include "bpf_util.h"
|
||||
|
||||
#define MAX_INSNS 512
|
||||
#define MAX_MATCHES 16
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <bpf/btf.h>
|
||||
|
||||
#include "bpf_rlimit.h"
|
||||
#include "bpf_util.h"
|
||||
|
||||
static uint32_t pass_cnt;
|
||||
static uint32_t error_cnt;
|
||||
@@ -93,10 +94,6 @@ static int __base_pr(const char *format, ...)
|
||||
#define MAX_NR_RAW_TYPES 1024
|
||||
#define BTF_LOG_BUF_SIZE 65535
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
static struct args {
|
||||
unsigned int raw_test_num;
|
||||
unsigned int file_test_num;
|
||||
@@ -131,6 +128,8 @@ struct btf_raw_test {
|
||||
__u32 max_entries;
|
||||
bool btf_load_err;
|
||||
bool map_create_err;
|
||||
bool ordered_map;
|
||||
bool lossless_map;
|
||||
int hdr_len_delta;
|
||||
int type_off_delta;
|
||||
int str_off_delta;
|
||||
@@ -2093,8 +2092,7 @@ struct pprint_mapv {
|
||||
} aenum;
|
||||
};
|
||||
|
||||
static struct btf_raw_test pprint_test = {
|
||||
.descr = "BTF pretty print test #1",
|
||||
static struct btf_raw_test pprint_test_template = {
|
||||
.raw_types = {
|
||||
/* unsighed char */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
|
||||
@@ -2146,8 +2144,6 @@ static struct btf_raw_test pprint_test = {
|
||||
},
|
||||
.str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum",
|
||||
.str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "pprint_test",
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
@@ -2155,6 +2151,40 @@ static struct btf_raw_test pprint_test = {
|
||||
.max_entries = 128 * 1024,
|
||||
};
|
||||
|
||||
static struct btf_pprint_test_meta {
|
||||
const char *descr;
|
||||
enum bpf_map_type map_type;
|
||||
const char *map_name;
|
||||
bool ordered_map;
|
||||
bool lossless_map;
|
||||
} pprint_tests_meta[] = {
|
||||
{
|
||||
.descr = "BTF pretty print array",
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "pprint_test_array",
|
||||
.ordered_map = true,
|
||||
.lossless_map = true,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "BTF pretty print hash",
|
||||
.map_type = BPF_MAP_TYPE_HASH,
|
||||
.map_name = "pprint_test_hash",
|
||||
.ordered_map = false,
|
||||
.lossless_map = true,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "BTF pretty print lru hash",
|
||||
.map_type = BPF_MAP_TYPE_LRU_HASH,
|
||||
.map_name = "pprint_test_lru_hash",
|
||||
.ordered_map = false,
|
||||
.lossless_map = false,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
|
||||
{
|
||||
v->ui32 = i;
|
||||
@@ -2166,10 +2196,12 @@ static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
|
||||
v->aenum = i & 0x03;
|
||||
}
|
||||
|
||||
static int test_pprint(void)
|
||||
static int do_test_pprint(void)
|
||||
{
|
||||
const struct btf_raw_test *test = &pprint_test;
|
||||
const struct btf_raw_test *test = &pprint_test_template;
|
||||
struct bpf_create_map_attr create_attr = {};
|
||||
unsigned int key, nr_read_elems;
|
||||
bool ordered_map, lossless_map;
|
||||
int map_fd = -1, btf_fd = -1;
|
||||
struct pprint_mapv mapv = {};
|
||||
unsigned int raw_btf_size;
|
||||
@@ -2178,7 +2210,6 @@ static int test_pprint(void)
|
||||
char pin_path[255];
|
||||
size_t line_len = 0;
|
||||
char *line = NULL;
|
||||
unsigned int key;
|
||||
uint8_t *raw_btf;
|
||||
ssize_t nread;
|
||||
int err, ret;
|
||||
@@ -2251,14 +2282,18 @@ static int test_pprint(void)
|
||||
goto done;
|
||||
}
|
||||
|
||||
key = 0;
|
||||
nr_read_elems = 0;
|
||||
ordered_map = test->ordered_map;
|
||||
lossless_map = test->lossless_map;
|
||||
do {
|
||||
ssize_t nexpected_line;
|
||||
unsigned int next_key;
|
||||
|
||||
set_pprint_mapv(&mapv, key);
|
||||
next_key = ordered_map ? nr_read_elems : atoi(line);
|
||||
set_pprint_mapv(&mapv, next_key);
|
||||
nexpected_line = snprintf(expected_line, sizeof(expected_line),
|
||||
"%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n",
|
||||
key,
|
||||
next_key,
|
||||
mapv.ui32, mapv.si32,
|
||||
mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b,
|
||||
mapv.ui64,
|
||||
@@ -2281,11 +2316,12 @@ static int test_pprint(void)
|
||||
}
|
||||
|
||||
nread = getline(&line, &line_len, pin_file);
|
||||
} while (++key < test->max_entries && nread > 0);
|
||||
} while (++nr_read_elems < test->max_entries && nread > 0);
|
||||
|
||||
if (CHECK(key < test->max_entries,
|
||||
"Unexpected EOF. key:%u test->max_entries:%u",
|
||||
key, test->max_entries)) {
|
||||
if (lossless_map &&
|
||||
CHECK(nr_read_elems < test->max_entries,
|
||||
"Unexpected EOF. nr_read_elems:%u test->max_entries:%u",
|
||||
nr_read_elems, test->max_entries)) {
|
||||
err = -1;
|
||||
goto done;
|
||||
}
|
||||
@@ -2314,6 +2350,24 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_pprint(void)
|
||||
{
|
||||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) {
|
||||
pprint_test_template.descr = pprint_tests_meta[i].descr;
|
||||
pprint_test_template.map_type = pprint_tests_meta[i].map_type;
|
||||
pprint_test_template.map_name = pprint_tests_meta[i].map_name;
|
||||
pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map;
|
||||
pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map;
|
||||
|
||||
err |= count_result(do_test_pprint());
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void usage(const char *cmd)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n",
|
||||
@@ -2409,7 +2463,7 @@ int main(int argc, char **argv)
|
||||
err |= test_file();
|
||||
|
||||
if (args.pprint_test)
|
||||
err |= count_result(test_pprint());
|
||||
err |= test_pprint();
|
||||
|
||||
if (args.raw_test || args.get_info_test || args.file_test ||
|
||||
args.pprint_test)
|
||||
|
130
tools/testing/selftests/bpf/test_cgroup_storage.c
Normal file
130
tools/testing/selftests/bpf/test_cgroup_storage.c
Normal file
@@ -0,0 +1,130 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <assert.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <linux/filter.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cgroup_helpers.h"
|
||||
|
||||
char bpf_log_buf[BPF_LOG_BUF_SIZE];
|
||||
|
||||
#define TEST_CGROUP "/test-bpf-cgroup-storage-buf/"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct bpf_insn prog[] = {
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_MOV64_IMM(BPF_REG_1, 1),
|
||||
BPF_STX_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x1),
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
|
||||
int error = EXIT_FAILURE;
|
||||
int map_fd, prog_fd, cgroup_fd;
|
||||
struct bpf_cgroup_storage_key key;
|
||||
unsigned long long value;
|
||||
|
||||
map_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(key),
|
||||
sizeof(value), 0, 0);
|
||||
if (map_fd < 0) {
|
||||
printf("Failed to create map: %s\n", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
prog[0].imm = map_fd;
|
||||
prog_fd = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
|
||||
prog, insns_cnt, "GPL", 0,
|
||||
bpf_log_buf, BPF_LOG_BUF_SIZE);
|
||||
if (prog_fd < 0) {
|
||||
printf("Failed to load bpf program: %s\n", bpf_log_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (setup_cgroup_environment()) {
|
||||
printf("Failed to setup cgroup environment\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Create a cgroup, get fd, and join it */
|
||||
cgroup_fd = create_and_get_cgroup(TEST_CGROUP);
|
||||
if (!cgroup_fd) {
|
||||
printf("Failed to create test cgroup\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (join_cgroup(TEST_CGROUP)) {
|
||||
printf("Failed to join cgroup\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Attach the bpf program */
|
||||
if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) {
|
||||
printf("Failed to attach bpf program\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (bpf_map_get_next_key(map_fd, NULL, &key)) {
|
||||
printf("Failed to get the first key in cgroup storage\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (bpf_map_lookup_elem(map_fd, &key, &value)) {
|
||||
printf("Failed to lookup cgroup storage\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Every second packet should be dropped */
|
||||
assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
|
||||
assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
|
||||
assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
|
||||
|
||||
/* Check the counter in the cgroup local storage */
|
||||
if (bpf_map_lookup_elem(map_fd, &key, &value)) {
|
||||
printf("Failed to lookup cgroup storage\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (value != 3) {
|
||||
printf("Unexpected data in the cgroup storage: %llu\n", value);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Bump the counter in the cgroup local storage */
|
||||
value++;
|
||||
if (bpf_map_update_elem(map_fd, &key, &value, 0)) {
|
||||
printf("Failed to update the data in the cgroup storage\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Every second packet should be dropped */
|
||||
assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
|
||||
assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
|
||||
assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
|
||||
|
||||
/* Check the final value of the counter in the cgroup local storage */
|
||||
if (bpf_map_lookup_elem(map_fd, &key, &value)) {
|
||||
printf("Failed to lookup the cgroup storage\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (value != 7) {
|
||||
printf("Unexpected data in the cgroup storage: %llu\n", value);
|
||||
goto err;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
printf("test_cgroup_storage:PASS\n");
|
||||
|
||||
err:
|
||||
cleanup_cgroup_environment();
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
@@ -17,7 +17,8 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/bpf.h>
|
||||
|
||||
#include <bpf/bpf.h>
|
||||
@@ -26,8 +27,21 @@
|
||||
#include "bpf_util.h"
|
||||
#include "bpf_rlimit.h"
|
||||
|
||||
#ifndef ENOTSUPP
|
||||
#define ENOTSUPP 524
|
||||
#endif
|
||||
|
||||
static int map_flags;
|
||||
|
||||
#define CHECK(condition, tag, format...) ({ \
|
||||
int __ret = !!(condition); \
|
||||
if (__ret) { \
|
||||
printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \
|
||||
printf(format); \
|
||||
exit(-1); \
|
||||
} \
|
||||
})
|
||||
|
||||
static void test_hashmap(int task, void *data)
|
||||
{
|
||||
long long key, next_key, first_key, value;
|
||||
@@ -1150,6 +1164,250 @@ static void test_map_wronly(void)
|
||||
assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM);
|
||||
}
|
||||
|
||||
static void prepare_reuseport_grp(int type, int map_fd,
|
||||
__s64 *fds64, __u64 *sk_cookies,
|
||||
unsigned int n)
|
||||
{
|
||||
socklen_t optlen, addrlen;
|
||||
struct sockaddr_in6 s6;
|
||||
const __u32 index0 = 0;
|
||||
const int optval = 1;
|
||||
unsigned int i;
|
||||
u64 sk_cookie;
|
||||
__s64 fd64;
|
||||
int err;
|
||||
|
||||
s6.sin6_family = AF_INET6;
|
||||
s6.sin6_addr = in6addr_any;
|
||||
s6.sin6_port = 0;
|
||||
addrlen = sizeof(s6);
|
||||
optlen = sizeof(sk_cookie);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
fd64 = socket(AF_INET6, type, 0);
|
||||
CHECK(fd64 == -1, "socket()",
|
||||
"sock_type:%d fd64:%lld errno:%d\n",
|
||||
type, fd64, errno);
|
||||
|
||||
err = setsockopt(fd64, SOL_SOCKET, SO_REUSEPORT,
|
||||
&optval, sizeof(optval));
|
||||
CHECK(err == -1, "setsockopt(SO_REUSEPORT)",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
|
||||
/* reuseport_array does not allow unbound sk */
|
||||
err = bpf_map_update_elem(map_fd, &index0, &fd64,
|
||||
BPF_ANY);
|
||||
CHECK(err != -1 || errno != EINVAL,
|
||||
"reuseport array update unbound sk",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
|
||||
err = bind(fd64, (struct sockaddr *)&s6, sizeof(s6));
|
||||
CHECK(err == -1, "bind()",
|
||||
"sock_type:%d err:%d errno:%d\n", type, err, errno);
|
||||
|
||||
if (i == 0) {
|
||||
err = getsockname(fd64, (struct sockaddr *)&s6,
|
||||
&addrlen);
|
||||
CHECK(err == -1, "getsockname()",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
}
|
||||
|
||||
err = getsockopt(fd64, SOL_SOCKET, SO_COOKIE, &sk_cookie,
|
||||
&optlen);
|
||||
CHECK(err == -1, "getsockopt(SO_COOKIE)",
|
||||
"sock_type:%d err:%d errno:%d\n", type, err, errno);
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
/*
|
||||
* reuseport_array does not allow
|
||||
* non-listening tcp sk.
|
||||
*/
|
||||
err = bpf_map_update_elem(map_fd, &index0, &fd64,
|
||||
BPF_ANY);
|
||||
CHECK(err != -1 || errno != EINVAL,
|
||||
"reuseport array update non-listening sk",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
err = listen(fd64, 0);
|
||||
CHECK(err == -1, "listen()",
|
||||
"sock_type:%d, err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
}
|
||||
|
||||
fds64[i] = fd64;
|
||||
sk_cookies[i] = sk_cookie;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_reuseport_array(void)
|
||||
{
|
||||
#define REUSEPORT_FD_IDX(err, last) ({ (err) ? last : !last; })
|
||||
|
||||
const __u32 array_size = 4, index0 = 0, index3 = 3;
|
||||
int types[2] = { SOCK_STREAM, SOCK_DGRAM }, type;
|
||||
__u64 grpa_cookies[2], sk_cookie, map_cookie;
|
||||
__s64 grpa_fds64[2] = { -1, -1 }, fd64 = -1;
|
||||
const __u32 bad_index = array_size;
|
||||
int map_fd, err, t, f;
|
||||
__u32 fds_idx = 0;
|
||||
int fd;
|
||||
|
||||
map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
|
||||
sizeof(__u32), sizeof(__u64), array_size, 0);
|
||||
CHECK(map_fd == -1, "reuseport array create",
|
||||
"map_fd:%d, errno:%d\n", map_fd, errno);
|
||||
|
||||
/* Test lookup/update/delete with invalid index */
|
||||
err = bpf_map_delete_elem(map_fd, &bad_index);
|
||||
CHECK(err != -1 || errno != E2BIG, "reuseport array del >=max_entries",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
|
||||
err = bpf_map_update_elem(map_fd, &bad_index, &fd64, BPF_ANY);
|
||||
CHECK(err != -1 || errno != E2BIG,
|
||||
"reuseport array update >=max_entries",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
|
||||
err = bpf_map_lookup_elem(map_fd, &bad_index, &map_cookie);
|
||||
CHECK(err != -1 || errno != ENOENT,
|
||||
"reuseport array update >=max_entries",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
|
||||
/* Test lookup/delete non existence elem */
|
||||
err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
|
||||
CHECK(err != -1 || errno != ENOENT,
|
||||
"reuseport array lookup not-exist elem",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
err = bpf_map_delete_elem(map_fd, &index3);
|
||||
CHECK(err != -1 || errno != ENOENT,
|
||||
"reuseport array del not-exist elem",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
|
||||
for (t = 0; t < ARRAY_SIZE(types); t++) {
|
||||
type = types[t];
|
||||
|
||||
prepare_reuseport_grp(type, map_fd, grpa_fds64,
|
||||
grpa_cookies, ARRAY_SIZE(grpa_fds64));
|
||||
|
||||
/* Test BPF_* update flags */
|
||||
/* BPF_EXIST failure case */
|
||||
err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
|
||||
BPF_EXIST);
|
||||
CHECK(err != -1 || errno != ENOENT,
|
||||
"reuseport array update empty elem BPF_EXIST",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
|
||||
|
||||
/* BPF_NOEXIST success case */
|
||||
err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
|
||||
BPF_NOEXIST);
|
||||
CHECK(err == -1,
|
||||
"reuseport array update empty elem BPF_NOEXIST",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
|
||||
|
||||
/* BPF_EXIST success case. */
|
||||
err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
|
||||
BPF_EXIST);
|
||||
CHECK(err == -1,
|
||||
"reuseport array update same elem BPF_EXIST",
|
||||
"sock_type:%d err:%d errno:%d\n", type, err, errno);
|
||||
fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
|
||||
|
||||
/* BPF_NOEXIST failure case */
|
||||
err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
|
||||
BPF_NOEXIST);
|
||||
CHECK(err != -1 || errno != EEXIST,
|
||||
"reuseport array update non-empty elem BPF_NOEXIST",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
|
||||
|
||||
/* BPF_ANY case (always succeed) */
|
||||
err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
|
||||
BPF_ANY);
|
||||
CHECK(err == -1,
|
||||
"reuseport array update same sk with BPF_ANY",
|
||||
"sock_type:%d err:%d errno:%d\n", type, err, errno);
|
||||
|
||||
fd64 = grpa_fds64[fds_idx];
|
||||
sk_cookie = grpa_cookies[fds_idx];
|
||||
|
||||
/* The same sk cannot be added to reuseport_array twice */
|
||||
err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_ANY);
|
||||
CHECK(err != -1 || errno != EBUSY,
|
||||
"reuseport array update same sk with same index",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
|
||||
err = bpf_map_update_elem(map_fd, &index0, &fd64, BPF_ANY);
|
||||
CHECK(err != -1 || errno != EBUSY,
|
||||
"reuseport array update same sk with different index",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
|
||||
/* Test delete elem */
|
||||
err = bpf_map_delete_elem(map_fd, &index3);
|
||||
CHECK(err == -1, "reuseport array delete sk",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
|
||||
/* Add it back with BPF_NOEXIST */
|
||||
err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
|
||||
CHECK(err == -1,
|
||||
"reuseport array re-add with BPF_NOEXIST after del",
|
||||
"sock_type:%d err:%d errno:%d\n", type, err, errno);
|
||||
|
||||
/* Test cookie */
|
||||
err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
|
||||
CHECK(err == -1 || sk_cookie != map_cookie,
|
||||
"reuseport array lookup re-added sk",
|
||||
"sock_type:%d err:%d errno:%d sk_cookie:0x%llx map_cookie:0x%llxn",
|
||||
type, err, errno, sk_cookie, map_cookie);
|
||||
|
||||
/* Test elem removed by close() */
|
||||
for (f = 0; f < ARRAY_SIZE(grpa_fds64); f++)
|
||||
close(grpa_fds64[f]);
|
||||
err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
|
||||
CHECK(err != -1 || errno != ENOENT,
|
||||
"reuseport array lookup after close()",
|
||||
"sock_type:%d err:%d errno:%d\n",
|
||||
type, err, errno);
|
||||
}
|
||||
|
||||
/* Test SOCK_RAW */
|
||||
fd64 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
|
||||
CHECK(fd64 == -1, "socket(SOCK_RAW)", "err:%d errno:%d\n",
|
||||
err, errno);
|
||||
err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
|
||||
CHECK(err != -1 || errno != ENOTSUPP, "reuseport array update SOCK_RAW",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
close(fd64);
|
||||
|
||||
/* Close the 64 bit value map */
|
||||
close(map_fd);
|
||||
|
||||
/* Test 32 bit fd */
|
||||
map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
|
||||
sizeof(__u32), sizeof(__u32), array_size, 0);
|
||||
CHECK(map_fd == -1, "reuseport array create",
|
||||
"map_fd:%d, errno:%d\n", map_fd, errno);
|
||||
prepare_reuseport_grp(SOCK_STREAM, map_fd, &fd64, &sk_cookie, 1);
|
||||
fd = fd64;
|
||||
err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST);
|
||||
CHECK(err == -1, "reuseport array update 32 bit fd",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
|
||||
CHECK(err != -1 || errno != ENOSPC,
|
||||
"reuseport array lookup 32 bit fd",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
close(fd);
|
||||
close(map_fd);
|
||||
}
|
||||
|
||||
static void run_all_tests(void)
|
||||
{
|
||||
test_hashmap(0, NULL);
|
||||
@@ -1170,6 +1428,8 @@ static void run_all_tests(void)
|
||||
|
||||
test_map_rdonly();
|
||||
test_map_wronly();
|
||||
|
||||
test_reuseport_array();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
@@ -158,8 +158,9 @@ def tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False):
|
||||
else:
|
||||
return ret, out
|
||||
|
||||
def bpftool(args, JSON=True, ns="", fail=True):
|
||||
return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail)
|
||||
def bpftool(args, JSON=True, ns="", fail=True, include_stderr=False):
|
||||
return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns,
|
||||
fail=fail, include_stderr=include_stderr)
|
||||
|
||||
def bpftool_prog_list(expected=None, ns=""):
|
||||
_, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
|
||||
@@ -201,6 +202,21 @@ def bpftool_map_list_wait(expected=0, n_retry=20):
|
||||
time.sleep(0.05)
|
||||
raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps))
|
||||
|
||||
def bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None,
|
||||
fail=True, include_stderr=False):
|
||||
args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name)
|
||||
if prog_type is not None:
|
||||
args += " type " + prog_type
|
||||
if dev is not None:
|
||||
args += " dev " + dev
|
||||
if len(maps):
|
||||
args += " map " + " map ".join(maps)
|
||||
|
||||
res = bpftool(args, fail=fail, include_stderr=include_stderr)
|
||||
if res[0] == 0:
|
||||
files.append(file_name)
|
||||
return res
|
||||
|
||||
def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False):
|
||||
if force:
|
||||
args = "-force " + args
|
||||
@@ -307,21 +323,25 @@ class NetdevSim:
|
||||
Class for netdevsim netdevice and its attributes.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, link=None):
|
||||
self.link = link
|
||||
|
||||
self.dev = self._netdevsim_create()
|
||||
devs.append(self)
|
||||
|
||||
self.ns = ""
|
||||
|
||||
self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname'])
|
||||
self.sdev_dir = self.dfs_dir + '/sdev/'
|
||||
self.dfs_refresh()
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.dev[key]
|
||||
|
||||
def _netdevsim_create(self):
|
||||
link = "" if self.link is None else "link " + self.link.dev['ifname']
|
||||
_, old = ip("link show")
|
||||
ip("link add sim%d type netdevsim")
|
||||
ip("link add sim%d {link} type netdevsim".format(link=link))
|
||||
_, new = ip("link show")
|
||||
|
||||
for dev in new:
|
||||
@@ -339,13 +359,18 @@ class NetdevSim:
|
||||
self.dfs = DebugfsDir(self.dfs_dir)
|
||||
return self.dfs
|
||||
|
||||
def dfs_read(self, f):
|
||||
path = os.path.join(self.dfs_dir, f)
|
||||
_, data = cmd('cat %s' % (path))
|
||||
return data.strip()
|
||||
|
||||
def dfs_num_bound_progs(self):
|
||||
path = os.path.join(self.dfs_dir, "bpf_bound_progs")
|
||||
path = os.path.join(self.sdev_dir, "bpf_bound_progs")
|
||||
_, progs = cmd('ls %s' % (path))
|
||||
return len(progs.split())
|
||||
|
||||
def dfs_get_bound_progs(self, expected):
|
||||
progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs"))
|
||||
progs = DebugfsDir(os.path.join(self.sdev_dir, "bpf_bound_progs"))
|
||||
if expected is not None:
|
||||
if len(progs) != expected:
|
||||
fail(True, "%d BPF programs bound, expected %d" %
|
||||
@@ -547,11 +572,11 @@ def check_extack(output, reference, args):
|
||||
if skip_extack:
|
||||
return
|
||||
lines = output.split("\n")
|
||||
comp = len(lines) >= 2 and lines[1] == reference
|
||||
comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
|
||||
fail(not comp, "Missing or incorrect netlink extack message")
|
||||
|
||||
def check_extack_nsim(output, reference, args):
|
||||
check_extack(output, "Error: netdevsim: " + reference, args)
|
||||
check_extack(output, "netdevsim: " + reference, args)
|
||||
|
||||
def check_no_extack(res, needle):
|
||||
fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
|
||||
@@ -654,7 +679,7 @@ try:
|
||||
ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "TC filter loaded without enabling TC offloads")
|
||||
check_extack(err, "Error: TC offload is disabled on net device.", args)
|
||||
check_extack(err, "TC offload is disabled on net device.", args)
|
||||
sim.wait_for_flush()
|
||||
|
||||
sim.set_ethtool_tc_offloads(True)
|
||||
@@ -694,7 +719,7 @@ try:
|
||||
skip_sw=True,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "Offloaded a filter to chain other than 0")
|
||||
check_extack(err, "Error: Driver supports only offload of chain 0.", args)
|
||||
check_extack(err, "Driver supports only offload of chain 0.", args)
|
||||
sim.tc_flush_filters()
|
||||
|
||||
start_test("Test TC replace...")
|
||||
@@ -814,24 +839,20 @@ try:
|
||||
"Device parameters reported for non-offloaded program")
|
||||
|
||||
start_test("Test XDP prog replace with bad flags...")
|
||||
ret, _, err = sim.set_xdp(obj, "offload", force=True,
|
||||
ret, _, err = sim.set_xdp(obj, "generic", force=True,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "Replaced XDP program with a program in different mode")
|
||||
check_extack_nsim(err, "program loaded with different flags.", args)
|
||||
fail(err.count("File exists") != 1, "Replaced driver XDP with generic")
|
||||
ret, _, err = sim.set_xdp(obj, "", force=True,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "Replaced XDP program with a program in different mode")
|
||||
check_extack_nsim(err, "program loaded with different flags.", args)
|
||||
check_extack(err, "program loaded with different flags.", args)
|
||||
|
||||
start_test("Test XDP prog remove with bad flags...")
|
||||
ret, _, err = sim.unset_xdp("offload", force=True,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "Removed program with a bad mode mode")
|
||||
check_extack_nsim(err, "program loaded with different flags.", args)
|
||||
ret, _, err = sim.unset_xdp("", force=True,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "Removed program with a bad mode mode")
|
||||
check_extack_nsim(err, "program loaded with different flags.", args)
|
||||
fail(ret == 0, "Removed program with a bad mode")
|
||||
check_extack(err, "program loaded with different flags.", args)
|
||||
|
||||
start_test("Test MTU restrictions...")
|
||||
ret, _ = sim.set_mtu(9000, fail=False)
|
||||
@@ -846,6 +867,25 @@ try:
|
||||
sim.set_mtu(1500)
|
||||
|
||||
sim.wait_for_flush()
|
||||
start_test("Test non-offload XDP attaching to HW...")
|
||||
bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/nooffload")
|
||||
nooffload = bpf_pinned("/sys/fs/bpf/nooffload")
|
||||
ret, _, err = sim.set_xdp(nooffload, "offload",
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "attached non-offloaded XDP program to HW")
|
||||
check_extack_nsim(err, "xdpoffload of non-bound program.", args)
|
||||
rm("/sys/fs/bpf/nooffload")
|
||||
|
||||
start_test("Test offload XDP attaching to drv...")
|
||||
bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload",
|
||||
dev=sim['ifname'])
|
||||
offload = bpf_pinned("/sys/fs/bpf/offload")
|
||||
ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True)
|
||||
fail(ret == 0, "attached offloaded XDP program to drv")
|
||||
check_extack(err, "using device-bound program without HW_MODE flag is not supported.", args)
|
||||
rm("/sys/fs/bpf/offload")
|
||||
sim.wait_for_flush()
|
||||
|
||||
start_test("Test XDP offload...")
|
||||
_, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True)
|
||||
ipl = sim.ip_link_show(xdp=True)
|
||||
@@ -891,6 +931,60 @@ try:
|
||||
rm(pin_file)
|
||||
bpftool_prog_list_wait(expected=0)
|
||||
|
||||
start_test("Test multi-attachment XDP - attach...")
|
||||
sim.set_xdp(obj, "offload")
|
||||
xdp = sim.ip_link_show(xdp=True)["xdp"]
|
||||
offloaded = sim.dfs_read("bpf_offloaded_id")
|
||||
fail("prog" not in xdp, "Base program not reported in single program mode")
|
||||
fail(len(ipl["xdp"]["attached"]) != 1,
|
||||
"Wrong attached program count with one program")
|
||||
|
||||
sim.set_xdp(obj, "")
|
||||
two_xdps = sim.ip_link_show(xdp=True)["xdp"]
|
||||
offloaded2 = sim.dfs_read("bpf_offloaded_id")
|
||||
|
||||
fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs")
|
||||
fail("prog" in two_xdps, "Base program reported in multi program mode")
|
||||
fail(xdp["attached"][0] not in two_xdps["attached"],
|
||||
"Offload program not reported after driver activated")
|
||||
fail(len(two_xdps["attached"]) != 2,
|
||||
"Wrong attached program count with two programs")
|
||||
fail(two_xdps["attached"][0]["prog"]["id"] ==
|
||||
two_xdps["attached"][1]["prog"]["id"],
|
||||
"offloaded and drv programs have the same id")
|
||||
fail(offloaded != offloaded2,
|
||||
"offload ID changed after loading driver program")
|
||||
|
||||
start_test("Test multi-attachment XDP - replace...")
|
||||
ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
|
||||
fail(err.count("busy") != 1, "Replaced one of programs without -force")
|
||||
|
||||
start_test("Test multi-attachment XDP - detach...")
|
||||
ret, _, err = sim.unset_xdp("drv", force=True,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "Removed program with a bad mode")
|
||||
check_extack(err, "program loaded with different flags.", args)
|
||||
|
||||
sim.unset_xdp("offload")
|
||||
xdp = sim.ip_link_show(xdp=True)["xdp"]
|
||||
offloaded = sim.dfs_read("bpf_offloaded_id")
|
||||
|
||||
fail(xdp["mode"] != 1, "Bad mode reported after multiple programs")
|
||||
fail("prog" not in xdp,
|
||||
"Base program not reported after multi program mode")
|
||||
fail(xdp["attached"][0] not in two_xdps["attached"],
|
||||
"Offload program not reported after driver activated")
|
||||
fail(len(ipl["xdp"]["attached"]) != 1,
|
||||
"Wrong attached program count with remaining programs")
|
||||
fail(offloaded != "0", "offload ID reported with only driver program left")
|
||||
|
||||
start_test("Test multi-attachment XDP - device remove...")
|
||||
sim.set_xdp(obj, "offload")
|
||||
sim.remove()
|
||||
|
||||
sim = NetdevSim()
|
||||
sim.set_ethtool_tc_offloads(True)
|
||||
|
||||
start_test("Test mixing of TC and XDP...")
|
||||
sim.tc_add_ingress()
|
||||
sim.set_xdp(obj, "offload")
|
||||
@@ -1085,6 +1179,106 @@ try:
|
||||
fail(ret == 0,
|
||||
"netdevsim didn't refuse to create a map with offload disabled")
|
||||
|
||||
sim.remove()
|
||||
|
||||
start_test("Test multi-dev ASIC program reuse...")
|
||||
simA = NetdevSim()
|
||||
simB1 = NetdevSim()
|
||||
simB2 = NetdevSim(link=simB1)
|
||||
simB3 = NetdevSim(link=simB1)
|
||||
sims = (simA, simB1, simB2, simB3)
|
||||
simB = (simB1, simB2, simB3)
|
||||
|
||||
bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA",
|
||||
dev=simA['ifname'])
|
||||
progA = bpf_pinned("/sys/fs/bpf/nsimA")
|
||||
bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB",
|
||||
dev=simB1['ifname'])
|
||||
progB = bpf_pinned("/sys/fs/bpf/nsimB")
|
||||
|
||||
simA.set_xdp(progA, "offload", JSON=False)
|
||||
for d in simB:
|
||||
d.set_xdp(progB, "offload", JSON=False)
|
||||
|
||||
start_test("Test multi-dev ASIC cross-dev replace...")
|
||||
ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False)
|
||||
fail(ret == 0, "cross-ASIC program allowed")
|
||||
for d in simB:
|
||||
ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False)
|
||||
fail(ret == 0, "cross-ASIC program allowed")
|
||||
|
||||
start_test("Test multi-dev ASIC cross-dev install...")
|
||||
for d in sims:
|
||||
d.unset_xdp("offload")
|
||||
|
||||
ret, _, err = simA.set_xdp(progB, "offload", force=True, JSON=False,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "cross-ASIC program allowed")
|
||||
check_extack_nsim(err, "program bound to different dev.", args)
|
||||
for d in simB:
|
||||
ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False,
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "cross-ASIC program allowed")
|
||||
check_extack_nsim(err, "program bound to different dev.", args)
|
||||
|
||||
start_test("Test multi-dev ASIC cross-dev map reuse...")
|
||||
|
||||
mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0]
|
||||
mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0]
|
||||
|
||||
ret, _ = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
|
||||
dev=simB3['ifname'],
|
||||
maps=["idx 0 id %d" % (mapB)],
|
||||
fail=False)
|
||||
fail(ret != 0, "couldn't reuse a map on the same ASIC")
|
||||
rm("/sys/fs/bpf/nsimB_")
|
||||
|
||||
ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA_",
|
||||
dev=simA['ifname'],
|
||||
maps=["idx 0 id %d" % (mapB)],
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "could reuse a map on a different ASIC")
|
||||
fail(err.count("offload device mismatch between prog and map") == 0,
|
||||
"error message missing for cross-ASIC map")
|
||||
|
||||
ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
|
||||
dev=simB1['ifname'],
|
||||
maps=["idx 0 id %d" % (mapA)],
|
||||
fail=False, include_stderr=True)
|
||||
fail(ret == 0, "could reuse a map on a different ASIC")
|
||||
fail(err.count("offload device mismatch between prog and map") == 0,
|
||||
"error message missing for cross-ASIC map")
|
||||
|
||||
start_test("Test multi-dev ASIC cross-dev destruction...")
|
||||
bpftool_prog_list_wait(expected=2)
|
||||
|
||||
simA.remove()
|
||||
bpftool_prog_list_wait(expected=1)
|
||||
|
||||
ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
|
||||
fail(ifnameB != simB1['ifname'], "program not bound to originial device")
|
||||
simB1.remove()
|
||||
bpftool_prog_list_wait(expected=1)
|
||||
|
||||
start_test("Test multi-dev ASIC cross-dev destruction - move...")
|
||||
ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
|
||||
fail(ifnameB not in (simB2['ifname'], simB3['ifname']),
|
||||
"program not bound to remaining devices")
|
||||
|
||||
simB2.remove()
|
||||
ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
|
||||
fail(ifnameB != simB3['ifname'], "program not bound to remaining device")
|
||||
|
||||
simB3.remove()
|
||||
bpftool_prog_list_wait(expected=0)
|
||||
|
||||
start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
|
||||
ret, out = bpftool("prog show %s" % (progB), fail=False)
|
||||
fail(ret == 0, "got information about orphaned program")
|
||||
fail("error" not in out, "no error reported for get info on orphaned")
|
||||
fail(out["error"] != "can't get prog info: No such device",
|
||||
"wrong error for get info on orphaned")
|
||||
|
||||
print("%s: OK" % (os.path.basename(__file__)))
|
||||
|
||||
finally:
|
||||
|
688
tools/testing/selftests/bpf/test_select_reuseport.c
Normal file
688
tools/testing/selftests/bpf/test_select_reuseport.c
Normal file
@@ -0,0 +1,688 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Facebook */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include "bpf_rlimit.h"
|
||||
#include "bpf_util.h"
|
||||
#include "test_select_reuseport_common.h"
|
||||
|
||||
#define MIN_TCPHDR_LEN 20
|
||||
#define UDPHDR_LEN 8
|
||||
|
||||
#define TCP_SYNCOOKIE_SYSCTL "/proc/sys/net/ipv4/tcp_syncookies"
|
||||
#define TCP_FO_SYSCTL "/proc/sys/net/ipv4/tcp_fastopen"
|
||||
#define REUSEPORT_ARRAY_SIZE 32
|
||||
|
||||
static int result_map, tmp_index_ovr_map, linum_map, data_check_map;
|
||||
static enum result expected_results[NR_RESULTS];
|
||||
static int sk_fds[REUSEPORT_ARRAY_SIZE];
|
||||
static int reuseport_array, outer_map;
|
||||
static int select_by_skb_data_prog;
|
||||
static int saved_tcp_syncookie;
|
||||
static struct bpf_object *obj;
|
||||
static int saved_tcp_fo;
|
||||
static __u32 index_zero;
|
||||
static int epfd;
|
||||
|
||||
static union sa46 {
|
||||
struct sockaddr_in6 v6;
|
||||
struct sockaddr_in v4;
|
||||
sa_family_t family;
|
||||
} srv_sa;
|
||||
|
||||
#define CHECK(condition, tag, format...) ({ \
|
||||
int __ret = !!(condition); \
|
||||
if (__ret) { \
|
||||
printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \
|
||||
printf(format); \
|
||||
exit(-1); \
|
||||
} \
|
||||
})
|
||||
|
||||
static void create_maps(void)
|
||||
{
|
||||
struct bpf_create_map_attr attr = {};
|
||||
|
||||
/* Creating reuseport_array */
|
||||
attr.name = "reuseport_array";
|
||||
attr.map_type = BPF_MAP_TYPE_REUSEPORT_SOCKARRAY;
|
||||
attr.key_size = sizeof(__u32);
|
||||
attr.value_size = sizeof(__u32);
|
||||
attr.max_entries = REUSEPORT_ARRAY_SIZE;
|
||||
|
||||
reuseport_array = bpf_create_map_xattr(&attr);
|
||||
CHECK(reuseport_array == -1, "creating reuseport_array",
|
||||
"reuseport_array:%d errno:%d\n", reuseport_array, errno);
|
||||
|
||||
/* Creating outer_map */
|
||||
attr.name = "outer_map";
|
||||
attr.map_type = BPF_MAP_TYPE_ARRAY_OF_MAPS;
|
||||
attr.key_size = sizeof(__u32);
|
||||
attr.value_size = sizeof(__u32);
|
||||
attr.max_entries = 1;
|
||||
attr.inner_map_fd = reuseport_array;
|
||||
outer_map = bpf_create_map_xattr(&attr);
|
||||
CHECK(outer_map == -1, "creating outer_map",
|
||||
"outer_map:%d errno:%d\n", outer_map, errno);
|
||||
}
|
||||
|
||||
static void prepare_bpf_obj(void)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
struct bpf_object_open_attr attr = {
|
||||
.file = "test_select_reuseport_kern.o",
|
||||
.prog_type = BPF_PROG_TYPE_SK_REUSEPORT,
|
||||
};
|
||||
|
||||
obj = bpf_object__open_xattr(&attr);
|
||||
CHECK(IS_ERR_OR_NULL(obj), "open test_select_reuseport_kern.o",
|
||||
"obj:%p PTR_ERR(obj):%ld\n", obj, PTR_ERR(obj));
|
||||
|
||||
prog = bpf_program__next(NULL, obj);
|
||||
CHECK(!prog, "get first bpf_program", "!prog\n");
|
||||
bpf_program__set_type(prog, attr.prog_type);
|
||||
|
||||
map = bpf_object__find_map_by_name(obj, "outer_map");
|
||||
CHECK(!map, "find outer_map", "!map\n");
|
||||
err = bpf_map__reuse_fd(map, outer_map);
|
||||
CHECK(err, "reuse outer_map", "err:%d\n", err);
|
||||
|
||||
err = bpf_object__load(obj);
|
||||
CHECK(err, "load bpf_object", "err:%d\n", err);
|
||||
|
||||
select_by_skb_data_prog = bpf_program__fd(prog);
|
||||
CHECK(select_by_skb_data_prog == -1, "get prog fd",
|
||||
"select_by_skb_data_prog:%d\n", select_by_skb_data_prog);
|
||||
|
||||
map = bpf_object__find_map_by_name(obj, "result_map");
|
||||
CHECK(!map, "find result_map", "!map\n");
|
||||
result_map = bpf_map__fd(map);
|
||||
CHECK(result_map == -1, "get result_map fd",
|
||||
"result_map:%d\n", result_map);
|
||||
|
||||
map = bpf_object__find_map_by_name(obj, "tmp_index_ovr_map");
|
||||
CHECK(!map, "find tmp_index_ovr_map", "!map\n");
|
||||
tmp_index_ovr_map = bpf_map__fd(map);
|
||||
CHECK(tmp_index_ovr_map == -1, "get tmp_index_ovr_map fd",
|
||||
"tmp_index_ovr_map:%d\n", tmp_index_ovr_map);
|
||||
|
||||
map = bpf_object__find_map_by_name(obj, "linum_map");
|
||||
CHECK(!map, "find linum_map", "!map\n");
|
||||
linum_map = bpf_map__fd(map);
|
||||
CHECK(linum_map == -1, "get linum_map fd",
|
||||
"linum_map:%d\n", linum_map);
|
||||
|
||||
map = bpf_object__find_map_by_name(obj, "data_check_map");
|
||||
CHECK(!map, "find data_check_map", "!map\n");
|
||||
data_check_map = bpf_map__fd(map);
|
||||
CHECK(data_check_map == -1, "get data_check_map fd",
|
||||
"data_check_map:%d\n", data_check_map);
|
||||
}
|
||||
|
||||
static void sa46_init_loopback(union sa46 *sa, sa_family_t family)
|
||||
{
|
||||
memset(sa, 0, sizeof(*sa));
|
||||
sa->family = family;
|
||||
if (sa->family == AF_INET6)
|
||||
sa->v6.sin6_addr = in6addr_loopback;
|
||||
else
|
||||
sa->v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
static void sa46_init_inany(union sa46 *sa, sa_family_t family)
|
||||
{
|
||||
memset(sa, 0, sizeof(*sa));
|
||||
sa->family = family;
|
||||
if (sa->family == AF_INET6)
|
||||
sa->v6.sin6_addr = in6addr_any;
|
||||
else
|
||||
sa->v4.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
|
||||
static int read_int_sysctl(const char *sysctl)
|
||||
{
|
||||
char buf[16];
|
||||
int fd, ret;
|
||||
|
||||
fd = open(sysctl, 0);
|
||||
CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n",
|
||||
sysctl, fd, errno);
|
||||
|
||||
ret = read(fd, buf, sizeof(buf));
|
||||
CHECK(ret <= 0, "read(sysctl)", "sysctl:%s ret:%d errno:%d\n",
|
||||
sysctl, ret, errno);
|
||||
close(fd);
|
||||
|
||||
return atoi(buf);
|
||||
}
|
||||
|
||||
static void write_int_sysctl(const char *sysctl, int v)
|
||||
{
|
||||
int fd, ret, size;
|
||||
char buf[16];
|
||||
|
||||
fd = open(sysctl, O_RDWR);
|
||||
CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n",
|
||||
sysctl, fd, errno);
|
||||
|
||||
size = snprintf(buf, sizeof(buf), "%d", v);
|
||||
ret = write(fd, buf, size);
|
||||
CHECK(ret != size, "write(sysctl)",
|
||||
"sysctl:%s ret:%d size:%d errno:%d\n", sysctl, ret, size, errno);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void restore_sysctls(void)
|
||||
{
|
||||
write_int_sysctl(TCP_FO_SYSCTL, saved_tcp_fo);
|
||||
write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, saved_tcp_syncookie);
|
||||
}
|
||||
|
||||
static void enable_fastopen(void)
|
||||
{
|
||||
int fo;
|
||||
|
||||
fo = read_int_sysctl(TCP_FO_SYSCTL);
|
||||
write_int_sysctl(TCP_FO_SYSCTL, fo | 7);
|
||||
}
|
||||
|
||||
static void enable_syncookie(void)
|
||||
{
|
||||
write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 2);
|
||||
}
|
||||
|
||||
static void disable_syncookie(void)
|
||||
{
|
||||
write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 0);
|
||||
}
|
||||
|
||||
static __u32 get_linum(void)
|
||||
{
|
||||
__u32 linum;
|
||||
int err;
|
||||
|
||||
err = bpf_map_lookup_elem(linum_map, &index_zero, &linum);
|
||||
CHECK(err == -1, "lookup_elem(linum_map)", "err:%d errno:%d\n",
|
||||
err, errno);
|
||||
|
||||
return linum;
|
||||
}
|
||||
|
||||
static void check_data(int type, sa_family_t family, const struct cmd *cmd,
|
||||
int cli_fd)
|
||||
{
|
||||
struct data_check expected = {}, result;
|
||||
union sa46 cli_sa;
|
||||
socklen_t addrlen;
|
||||
int err;
|
||||
|
||||
addrlen = sizeof(cli_sa);
|
||||
err = getsockname(cli_fd, (struct sockaddr *)&cli_sa,
|
||||
&addrlen);
|
||||
CHECK(err == -1, "getsockname(cli_fd)", "err:%d errno:%d\n",
|
||||
err, errno);
|
||||
|
||||
err = bpf_map_lookup_elem(data_check_map, &index_zero, &result);
|
||||
CHECK(err == -1, "lookup_elem(data_check_map)", "err:%d errno:%d\n",
|
||||
err, errno);
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
expected.len = MIN_TCPHDR_LEN;
|
||||
expected.ip_protocol = IPPROTO_TCP;
|
||||
} else {
|
||||
expected.len = UDPHDR_LEN;
|
||||
expected.ip_protocol = IPPROTO_UDP;
|
||||
}
|
||||
|
||||
if (family == AF_INET6) {
|
||||
expected.eth_protocol = htons(ETH_P_IPV6);
|
||||
expected.bind_inany = !srv_sa.v6.sin6_addr.s6_addr32[3] &&
|
||||
!srv_sa.v6.sin6_addr.s6_addr32[2] &&
|
||||
!srv_sa.v6.sin6_addr.s6_addr32[1] &&
|
||||
!srv_sa.v6.sin6_addr.s6_addr32[0];
|
||||
|
||||
memcpy(&expected.skb_addrs[0], cli_sa.v6.sin6_addr.s6_addr32,
|
||||
sizeof(cli_sa.v6.sin6_addr));
|
||||
memcpy(&expected.skb_addrs[4], &in6addr_loopback,
|
||||
sizeof(in6addr_loopback));
|
||||
expected.skb_ports[0] = cli_sa.v6.sin6_port;
|
||||
expected.skb_ports[1] = srv_sa.v6.sin6_port;
|
||||
} else {
|
||||
expected.eth_protocol = htons(ETH_P_IP);
|
||||
expected.bind_inany = !srv_sa.v4.sin_addr.s_addr;
|
||||
|
||||
expected.skb_addrs[0] = cli_sa.v4.sin_addr.s_addr;
|
||||
expected.skb_addrs[1] = htonl(INADDR_LOOPBACK);
|
||||
expected.skb_ports[0] = cli_sa.v4.sin_port;
|
||||
expected.skb_ports[1] = srv_sa.v4.sin_port;
|
||||
}
|
||||
|
||||
if (memcmp(&result, &expected, offsetof(struct data_check,
|
||||
equal_check_end))) {
|
||||
printf("unexpected data_check\n");
|
||||
printf(" result: (0x%x, %u, %u)\n",
|
||||
result.eth_protocol, result.ip_protocol,
|
||||
result.bind_inany);
|
||||
printf("expected: (0x%x, %u, %u)\n",
|
||||
expected.eth_protocol, expected.ip_protocol,
|
||||
expected.bind_inany);
|
||||
CHECK(1, "data_check result != expected",
|
||||
"bpf_prog_linum:%u\n", get_linum());
|
||||
}
|
||||
|
||||
CHECK(!result.hash, "data_check result.hash empty",
|
||||
"result.hash:%u", result.hash);
|
||||
|
||||
expected.len += cmd ? sizeof(*cmd) : 0;
|
||||
if (type == SOCK_STREAM)
|
||||
CHECK(expected.len > result.len, "expected.len > result.len",
|
||||
"expected.len:%u result.len:%u bpf_prog_linum:%u\n",
|
||||
expected.len, result.len, get_linum());
|
||||
else
|
||||
CHECK(expected.len != result.len, "expected.len != result.len",
|
||||
"expected.len:%u result.len:%u bpf_prog_linum:%u\n",
|
||||
expected.len, result.len, get_linum());
|
||||
}
|
||||
|
||||
static void check_results(void)
|
||||
{
|
||||
__u32 results[NR_RESULTS];
|
||||
__u32 i, broken = 0;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < NR_RESULTS; i++) {
|
||||
err = bpf_map_lookup_elem(result_map, &i, &results[i]);
|
||||
CHECK(err == -1, "lookup_elem(result_map)",
|
||||
"i:%u err:%d errno:%d\n", i, err, errno);
|
||||
}
|
||||
|
||||
for (i = 0; i < NR_RESULTS; i++) {
|
||||
if (results[i] != expected_results[i]) {
|
||||
broken = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == NR_RESULTS)
|
||||
return;
|
||||
|
||||
printf("unexpected result\n");
|
||||
printf(" result: [");
|
||||
printf("%u", results[0]);
|
||||
for (i = 1; i < NR_RESULTS; i++)
|
||||
printf(", %u", results[i]);
|
||||
printf("]\n");
|
||||
|
||||
printf("expected: [");
|
||||
printf("%u", expected_results[0]);
|
||||
for (i = 1; i < NR_RESULTS; i++)
|
||||
printf(", %u", expected_results[i]);
|
||||
printf("]\n");
|
||||
|
||||
CHECK(expected_results[broken] != results[broken],
|
||||
"unexpected result",
|
||||
"expected_results[%u] != results[%u] bpf_prog_linum:%u\n",
|
||||
broken, broken, get_linum());
|
||||
}
|
||||
|
||||
static int send_data(int type, sa_family_t family, void *data, size_t len,
|
||||
enum result expected)
|
||||
{
|
||||
union sa46 cli_sa;
|
||||
int fd, err;
|
||||
|
||||
fd = socket(family, type, 0);
|
||||
CHECK(fd == -1, "socket()", "fd:%d errno:%d\n", fd, errno);
|
||||
|
||||
sa46_init_loopback(&cli_sa, family);
|
||||
err = bind(fd, (struct sockaddr *)&cli_sa, sizeof(cli_sa));
|
||||
CHECK(fd == -1, "bind(cli_sa)", "err:%d errno:%d\n", err, errno);
|
||||
|
||||
err = sendto(fd, data, len, MSG_FASTOPEN, (struct sockaddr *)&srv_sa,
|
||||
sizeof(srv_sa));
|
||||
CHECK(err != len && expected >= PASS,
|
||||
"sendto()", "family:%u err:%d errno:%d expected:%d\n",
|
||||
family, err, errno, expected);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void do_test(int type, sa_family_t family, struct cmd *cmd,
|
||||
enum result expected)
|
||||
{
|
||||
int nev, srv_fd, cli_fd;
|
||||
struct epoll_event ev;
|
||||
struct cmd rcv_cmd;
|
||||
ssize_t nread;
|
||||
|
||||
cli_fd = send_data(type, family, cmd, cmd ? sizeof(*cmd) : 0,
|
||||
expected);
|
||||
nev = epoll_wait(epfd, &ev, 1, expected >= PASS ? 5 : 0);
|
||||
CHECK((nev <= 0 && expected >= PASS) ||
|
||||
(nev > 0 && expected < PASS),
|
||||
"nev <> expected",
|
||||
"nev:%d expected:%d type:%d family:%d data:(%d, %d)\n",
|
||||
nev, expected, type, family,
|
||||
cmd ? cmd->reuseport_index : -1,
|
||||
cmd ? cmd->pass_on_failure : -1);
|
||||
check_results();
|
||||
check_data(type, family, cmd, cli_fd);
|
||||
|
||||
if (expected < PASS)
|
||||
return;
|
||||
|
||||
CHECK(expected != PASS_ERR_SK_SELECT_REUSEPORT &&
|
||||
cmd->reuseport_index != ev.data.u32,
|
||||
"check cmd->reuseport_index",
|
||||
"cmd:(%u, %u) ev.data.u32:%u\n",
|
||||
cmd->pass_on_failure, cmd->reuseport_index, ev.data.u32);
|
||||
|
||||
srv_fd = sk_fds[ev.data.u32];
|
||||
if (type == SOCK_STREAM) {
|
||||
int new_fd = accept(srv_fd, NULL, 0);
|
||||
|
||||
CHECK(new_fd == -1, "accept(srv_fd)",
|
||||
"ev.data.u32:%u new_fd:%d errno:%d\n",
|
||||
ev.data.u32, new_fd, errno);
|
||||
|
||||
nread = recv(new_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT);
|
||||
CHECK(nread != sizeof(rcv_cmd),
|
||||
"recv(new_fd)",
|
||||
"ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n",
|
||||
ev.data.u32, nread, sizeof(rcv_cmd), errno);
|
||||
|
||||
close(new_fd);
|
||||
} else {
|
||||
nread = recv(srv_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT);
|
||||
CHECK(nread != sizeof(rcv_cmd),
|
||||
"recv(sk_fds)",
|
||||
"ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n",
|
||||
ev.data.u32, nread, sizeof(rcv_cmd), errno);
|
||||
}
|
||||
|
||||
close(cli_fd);
|
||||
}
|
||||
|
||||
static void test_err_inner_map(int type, sa_family_t family)
|
||||
{
|
||||
struct cmd cmd = {
|
||||
.reuseport_index = 0,
|
||||
.pass_on_failure = 0,
|
||||
};
|
||||
|
||||
printf("%s: ", __func__);
|
||||
expected_results[DROP_ERR_INNER_MAP]++;
|
||||
do_test(type, family, &cmd, DROP_ERR_INNER_MAP);
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
static void test_err_skb_data(int type, sa_family_t family)
|
||||
{
|
||||
printf("%s: ", __func__);
|
||||
expected_results[DROP_ERR_SKB_DATA]++;
|
||||
do_test(type, family, NULL, DROP_ERR_SKB_DATA);
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
static void test_err_sk_select_port(int type, sa_family_t family)
|
||||
{
|
||||
struct cmd cmd = {
|
||||
.reuseport_index = REUSEPORT_ARRAY_SIZE,
|
||||
.pass_on_failure = 0,
|
||||
};
|
||||
|
||||
printf("%s: ", __func__);
|
||||
expected_results[DROP_ERR_SK_SELECT_REUSEPORT]++;
|
||||
do_test(type, family, &cmd, DROP_ERR_SK_SELECT_REUSEPORT);
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
static void test_pass(int type, sa_family_t family)
|
||||
{
|
||||
struct cmd cmd;
|
||||
int i;
|
||||
|
||||
printf("%s: ", __func__);
|
||||
cmd.pass_on_failure = 0;
|
||||
for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) {
|
||||
expected_results[PASS]++;
|
||||
cmd.reuseport_index = i;
|
||||
do_test(type, family, &cmd, PASS);
|
||||
}
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
static void test_syncookie(int type, sa_family_t family)
|
||||
{
|
||||
int err, tmp_index = 1;
|
||||
struct cmd cmd = {
|
||||
.reuseport_index = 0,
|
||||
.pass_on_failure = 0,
|
||||
};
|
||||
|
||||
if (type != SOCK_STREAM)
|
||||
return;
|
||||
|
||||
printf("%s: ", __func__);
|
||||
/*
|
||||
* +1 for TCP-SYN and
|
||||
* +1 for the TCP-ACK (ack the syncookie)
|
||||
*/
|
||||
expected_results[PASS] += 2;
|
||||
enable_syncookie();
|
||||
/*
|
||||
* Simulate TCP-SYN and TCP-ACK are handled by two different sk:
|
||||
* TCP-SYN: select sk_fds[tmp_index = 1] tmp_index is from the
|
||||
* tmp_index_ovr_map
|
||||
* TCP-ACK: select sk_fds[reuseport_index = 0] reuseport_index
|
||||
* is from the cmd.reuseport_index
|
||||
*/
|
||||
err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero,
|
||||
&tmp_index, BPF_ANY);
|
||||
CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, 1)",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
do_test(type, family, &cmd, PASS);
|
||||
err = bpf_map_lookup_elem(tmp_index_ovr_map, &index_zero,
|
||||
&tmp_index);
|
||||
CHECK(err == -1 || tmp_index != -1,
|
||||
"lookup_elem(tmp_index_ovr_map)",
|
||||
"err:%d errno:%d tmp_index:%d\n",
|
||||
err, errno, tmp_index);
|
||||
disable_syncookie();
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
static void test_pass_on_err(int type, sa_family_t family)
|
||||
{
|
||||
struct cmd cmd = {
|
||||
.reuseport_index = REUSEPORT_ARRAY_SIZE,
|
||||
.pass_on_failure = 1,
|
||||
};
|
||||
|
||||
printf("%s: ", __func__);
|
||||
expected_results[PASS_ERR_SK_SELECT_REUSEPORT] += 1;
|
||||
do_test(type, family, &cmd, PASS_ERR_SK_SELECT_REUSEPORT);
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
static void prepare_sk_fds(int type, sa_family_t family, bool inany)
|
||||
{
|
||||
const int first = REUSEPORT_ARRAY_SIZE - 1;
|
||||
int i, err, optval = 1;
|
||||
struct epoll_event ev;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (inany)
|
||||
sa46_init_inany(&srv_sa, family);
|
||||
else
|
||||
sa46_init_loopback(&srv_sa, family);
|
||||
addrlen = sizeof(srv_sa);
|
||||
|
||||
/*
|
||||
* The sk_fds[] is filled from the back such that the order
|
||||
* is exactly opposite to the (struct sock_reuseport *)reuse->socks[].
|
||||
*/
|
||||
for (i = first; i >= 0; i--) {
|
||||
sk_fds[i] = socket(family, type, 0);
|
||||
CHECK(sk_fds[i] == -1, "socket()", "sk_fds[%d]:%d errno:%d\n",
|
||||
i, sk_fds[i], errno);
|
||||
err = setsockopt(sk_fds[i], SOL_SOCKET, SO_REUSEPORT,
|
||||
&optval, sizeof(optval));
|
||||
CHECK(err == -1, "setsockopt(SO_REUSEPORT)",
|
||||
"sk_fds[%d] err:%d errno:%d\n",
|
||||
i, err, errno);
|
||||
|
||||
if (i == first) {
|
||||
err = setsockopt(sk_fds[i], SOL_SOCKET,
|
||||
SO_ATTACH_REUSEPORT_EBPF,
|
||||
&select_by_skb_data_prog,
|
||||
sizeof(select_by_skb_data_prog));
|
||||
CHECK(err == -1, "setsockopt(SO_ATTACH_REUEPORT_EBPF)",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
}
|
||||
|
||||
err = bind(sk_fds[i], (struct sockaddr *)&srv_sa, addrlen);
|
||||
CHECK(err == -1, "bind()", "sk_fds[%d] err:%d errno:%d\n",
|
||||
i, err, errno);
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
err = listen(sk_fds[i], 10);
|
||||
CHECK(err == -1, "listen()",
|
||||
"sk_fds[%d] err:%d errno:%d\n",
|
||||
i, err, errno);
|
||||
}
|
||||
|
||||
err = bpf_map_update_elem(reuseport_array, &i, &sk_fds[i],
|
||||
BPF_NOEXIST);
|
||||
CHECK(err == -1, "update_elem(reuseport_array)",
|
||||
"sk_fds[%d] err:%d errno:%d\n", i, err, errno);
|
||||
|
||||
if (i == first) {
|
||||
socklen_t addrlen = sizeof(srv_sa);
|
||||
|
||||
err = getsockname(sk_fds[i], (struct sockaddr *)&srv_sa,
|
||||
&addrlen);
|
||||
CHECK(err == -1, "getsockname()",
|
||||
"sk_fds[%d] err:%d errno:%d\n", i, err, errno);
|
||||
}
|
||||
}
|
||||
|
||||
epfd = epoll_create(1);
|
||||
CHECK(epfd == -1, "epoll_create(1)",
|
||||
"epfd:%d errno:%d\n", epfd, errno);
|
||||
|
||||
ev.events = EPOLLIN;
|
||||
for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) {
|
||||
ev.data.u32 = i;
|
||||
err = epoll_ctl(epfd, EPOLL_CTL_ADD, sk_fds[i], &ev);
|
||||
CHECK(err, "epoll_ctl(EPOLL_CTL_ADD)", "sk_fds[%d]\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_per_test(int type, unsigned short family, bool inany)
|
||||
{
|
||||
int ovr = -1, err;
|
||||
|
||||
prepare_sk_fds(type, family, inany);
|
||||
err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero, &ovr,
|
||||
BPF_ANY);
|
||||
CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, -1)",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
}
|
||||
|
||||
static void cleanup_per_test(void)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++)
|
||||
close(sk_fds[i]);
|
||||
close(epfd);
|
||||
|
||||
err = bpf_map_delete_elem(outer_map, &index_zero);
|
||||
CHECK(err == -1, "delete_elem(outer_map)",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
close(outer_map);
|
||||
close(reuseport_array);
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
|
||||
static void test_all(void)
|
||||
{
|
||||
/* Extra SOCK_STREAM to test bind_inany==true */
|
||||
const int types[] = { SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM };
|
||||
const char * const type_strings[] = { "TCP", "UDP", "TCP" };
|
||||
const char * const family_strings[] = { "IPv6", "IPv4" };
|
||||
const unsigned short families[] = { AF_INET6, AF_INET };
|
||||
const bool bind_inany[] = { false, false, true };
|
||||
int t, f, err;
|
||||
|
||||
for (f = 0; f < ARRAY_SIZE(families); f++) {
|
||||
unsigned short family = families[f];
|
||||
|
||||
for (t = 0; t < ARRAY_SIZE(types); t++) {
|
||||
bool inany = bind_inany[t];
|
||||
int type = types[t];
|
||||
|
||||
printf("######## %s/%s %s ########\n",
|
||||
family_strings[f], type_strings[t],
|
||||
inany ? " INANY " : "LOOPBACK");
|
||||
|
||||
setup_per_test(type, family, inany);
|
||||
|
||||
test_err_inner_map(type, family);
|
||||
|
||||
/* Install reuseport_array to the outer_map */
|
||||
err = bpf_map_update_elem(outer_map, &index_zero,
|
||||
&reuseport_array, BPF_ANY);
|
||||
CHECK(err == -1, "update_elem(outer_map)",
|
||||
"err:%d errno:%d\n", err, errno);
|
||||
|
||||
test_err_skb_data(type, family);
|
||||
test_err_sk_select_port(type, family);
|
||||
test_pass(type, family);
|
||||
test_syncookie(type, family);
|
||||
test_pass_on_err(type, family);
|
||||
|
||||
cleanup_per_test();
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
create_maps();
|
||||
prepare_bpf_obj();
|
||||
saved_tcp_fo = read_int_sysctl(TCP_FO_SYSCTL);
|
||||
saved_tcp_syncookie = read_int_sysctl(TCP_SYNCOOKIE_SYSCTL);
|
||||
enable_fastopen();
|
||||
disable_syncookie();
|
||||
atexit(restore_sysctls);
|
||||
|
||||
test_all();
|
||||
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
36
tools/testing/selftests/bpf/test_select_reuseport_common.h
Normal file
36
tools/testing/selftests/bpf/test_select_reuseport_common.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Facebook */
|
||||
|
||||
#ifndef __TEST_SELECT_REUSEPORT_COMMON_H
|
||||
#define __TEST_SELECT_REUSEPORT_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum result {
|
||||
DROP_ERR_INNER_MAP,
|
||||
DROP_ERR_SKB_DATA,
|
||||
DROP_ERR_SK_SELECT_REUSEPORT,
|
||||
DROP_MISC,
|
||||
PASS,
|
||||
PASS_ERR_SK_SELECT_REUSEPORT,
|
||||
NR_RESULTS,
|
||||
};
|
||||
|
||||
struct cmd {
|
||||
__u32 reuseport_index;
|
||||
__u32 pass_on_failure;
|
||||
};
|
||||
|
||||
struct data_check {
|
||||
__u32 ip_protocol;
|
||||
__u32 skb_addrs[8];
|
||||
__u16 skb_ports[2];
|
||||
__u16 eth_protocol;
|
||||
__u8 bind_inany;
|
||||
__u8 equal_check_end[0];
|
||||
|
||||
__u32 len;
|
||||
__u32 hash;
|
||||
};
|
||||
|
||||
#endif
|
180
tools/testing/selftests/bpf/test_select_reuseport_kern.c
Normal file
180
tools/testing/selftests/bpf/test_select_reuseport_kern.c
Normal file
@@ -0,0 +1,180 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Facebook */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "bpf_endian.h"
|
||||
#include "bpf_helpers.h"
|
||||
#include "test_select_reuseport_common.h"
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
struct bpf_map_def SEC("maps") outer_map = {
|
||||
.type = BPF_MAP_TYPE_ARRAY_OF_MAPS,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u32),
|
||||
.max_entries = 1,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") result_map = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u32),
|
||||
.max_entries = NR_RESULTS,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") tmp_index_ovr_map = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 1,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") linum_map = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u32),
|
||||
.max_entries = 1,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") data_check_map = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(struct data_check),
|
||||
.max_entries = 1,
|
||||
};
|
||||
|
||||
#define GOTO_DONE(_result) ({ \
|
||||
result = (_result); \
|
||||
linum = __LINE__; \
|
||||
goto done; \
|
||||
})
|
||||
|
||||
SEC("select_by_skb_data")
|
||||
int _select_by_skb_data(struct sk_reuseport_md *reuse_md)
|
||||
{
|
||||
__u32 linum, index = 0, flags = 0, index_zero = 0;
|
||||
__u32 *result_cnt, *linum_value;
|
||||
struct data_check data_check = {};
|
||||
struct cmd *cmd, cmd_copy;
|
||||
void *data, *data_end;
|
||||
void *reuseport_array;
|
||||
enum result result;
|
||||
int *index_ovr;
|
||||
int err;
|
||||
|
||||
data = reuse_md->data;
|
||||
data_end = reuse_md->data_end;
|
||||
data_check.len = reuse_md->len;
|
||||
data_check.eth_protocol = reuse_md->eth_protocol;
|
||||
data_check.ip_protocol = reuse_md->ip_protocol;
|
||||
data_check.hash = reuse_md->hash;
|
||||
data_check.bind_inany = reuse_md->bind_inany;
|
||||
if (data_check.eth_protocol == bpf_htons(ETH_P_IP)) {
|
||||
if (bpf_skb_load_bytes_relative(reuse_md,
|
||||
offsetof(struct iphdr, saddr),
|
||||
data_check.skb_addrs, 8,
|
||||
BPF_HDR_START_NET))
|
||||
GOTO_DONE(DROP_MISC);
|
||||
} else {
|
||||
if (bpf_skb_load_bytes_relative(reuse_md,
|
||||
offsetof(struct ipv6hdr, saddr),
|
||||
data_check.skb_addrs, 32,
|
||||
BPF_HDR_START_NET))
|
||||
GOTO_DONE(DROP_MISC);
|
||||
}
|
||||
|
||||
/*
|
||||
* The ip_protocol could be a compile time decision
|
||||
* if the bpf_prog.o is dedicated to either TCP or
|
||||
* UDP.
|
||||
*
|
||||
* Otherwise, reuse_md->ip_protocol or
|
||||
* the protocol field in the iphdr can be used.
|
||||
*/
|
||||
if (data_check.ip_protocol == IPPROTO_TCP) {
|
||||
struct tcphdr *th = data;
|
||||
|
||||
if (th + 1 > data_end)
|
||||
GOTO_DONE(DROP_MISC);
|
||||
|
||||
data_check.skb_ports[0] = th->source;
|
||||
data_check.skb_ports[1] = th->dest;
|
||||
|
||||
if ((th->doff << 2) + sizeof(*cmd) > data_check.len)
|
||||
GOTO_DONE(DROP_ERR_SKB_DATA);
|
||||
if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy,
|
||||
sizeof(cmd_copy)))
|
||||
GOTO_DONE(DROP_MISC);
|
||||
cmd = &cmd_copy;
|
||||
} else if (data_check.ip_protocol == IPPROTO_UDP) {
|
||||
struct udphdr *uh = data;
|
||||
|
||||
if (uh + 1 > data_end)
|
||||
GOTO_DONE(DROP_MISC);
|
||||
|
||||
data_check.skb_ports[0] = uh->source;
|
||||
data_check.skb_ports[1] = uh->dest;
|
||||
|
||||
if (sizeof(struct udphdr) + sizeof(*cmd) > data_check.len)
|
||||
GOTO_DONE(DROP_ERR_SKB_DATA);
|
||||
if (data + sizeof(struct udphdr) + sizeof(*cmd) > data_end) {
|
||||
if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr),
|
||||
&cmd_copy, sizeof(cmd_copy)))
|
||||
GOTO_DONE(DROP_MISC);
|
||||
cmd = &cmd_copy;
|
||||
} else {
|
||||
cmd = data + sizeof(struct udphdr);
|
||||
}
|
||||
} else {
|
||||
GOTO_DONE(DROP_MISC);
|
||||
}
|
||||
|
||||
reuseport_array = bpf_map_lookup_elem(&outer_map, &index_zero);
|
||||
if (!reuseport_array)
|
||||
GOTO_DONE(DROP_ERR_INNER_MAP);
|
||||
|
||||
index = cmd->reuseport_index;
|
||||
index_ovr = bpf_map_lookup_elem(&tmp_index_ovr_map, &index_zero);
|
||||
if (!index_ovr)
|
||||
GOTO_DONE(DROP_MISC);
|
||||
|
||||
if (*index_ovr != -1) {
|
||||
index = *index_ovr;
|
||||
*index_ovr = -1;
|
||||
}
|
||||
err = bpf_sk_select_reuseport(reuse_md, reuseport_array, &index,
|
||||
flags);
|
||||
if (!err)
|
||||
GOTO_DONE(PASS);
|
||||
|
||||
if (cmd->pass_on_failure)
|
||||
GOTO_DONE(PASS_ERR_SK_SELECT_REUSEPORT);
|
||||
else
|
||||
GOTO_DONE(DROP_ERR_SK_SELECT_REUSEPORT);
|
||||
|
||||
done:
|
||||
result_cnt = bpf_map_lookup_elem(&result_map, &result);
|
||||
if (!result_cnt)
|
||||
return SK_DROP;
|
||||
|
||||
bpf_map_update_elem(&linum_map, &index_zero, &linum, BPF_ANY);
|
||||
bpf_map_update_elem(&data_check_map, &index_zero, &data_check, BPF_ANY);
|
||||
|
||||
(*result_cnt)++;
|
||||
return result < PASS ? SK_DROP : SK_PASS;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
62
tools/testing/selftests/bpf/test_skb_cgroup_id.sh
Executable file
62
tools/testing/selftests/bpf/test_skb_cgroup_id.sh
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2018 Facebook
|
||||
|
||||
set -eu
|
||||
|
||||
wait_for_ip()
|
||||
{
|
||||
local _i
|
||||
echo -n "Wait for testing link-local IP to become available "
|
||||
for _i in $(seq ${MAX_PING_TRIES}); do
|
||||
echo -n "."
|
||||
if ping -6 -q -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then
|
||||
echo " OK"
|
||||
return
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo 1>&2 "ERROR: Timeout waiting for test IP to become available."
|
||||
exit 1
|
||||
}
|
||||
|
||||
setup()
|
||||
{
|
||||
# Create testing interfaces not to interfere with current environment.
|
||||
ip link add dev ${TEST_IF} type veth peer name ${TEST_IF_PEER}
|
||||
ip link set ${TEST_IF} up
|
||||
ip link set ${TEST_IF_PEER} up
|
||||
|
||||
wait_for_ip
|
||||
|
||||
tc qdisc add dev ${TEST_IF} clsact
|
||||
tc filter add dev ${TEST_IF} egress bpf obj ${BPF_PROG_OBJ} \
|
||||
sec ${BPF_PROG_SECTION} da
|
||||
|
||||
BPF_PROG_ID=$(tc filter show dev ${TEST_IF} egress | \
|
||||
awk '/ id / {sub(/.* id /, "", $0); print($1)}')
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
ip link del ${TEST_IF} 2>/dev/null || :
|
||||
ip link del ${TEST_IF_PEER} 2>/dev/null || :
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
trap cleanup EXIT 2 3 6 15
|
||||
setup
|
||||
${PROG} ${TEST_IF} ${BPF_PROG_ID}
|
||||
}
|
||||
|
||||
DIR=$(dirname $0)
|
||||
TEST_IF="test_cgid_1"
|
||||
TEST_IF_PEER="test_cgid_2"
|
||||
MAX_PING_TRIES=5
|
||||
BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o"
|
||||
BPF_PROG_SECTION="cgroup_id_logger"
|
||||
BPF_PROG_ID=0
|
||||
PROG="${DIR}/test_skb_cgroup_id_user"
|
||||
|
||||
main
|
47
tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c
Normal file
47
tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c
Normal file
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
#define NUM_CGROUP_LEVELS 4
|
||||
|
||||
struct bpf_map_def SEC("maps") cgroup_ids = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u64),
|
||||
.max_entries = NUM_CGROUP_LEVELS,
|
||||
};
|
||||
|
||||
static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level)
|
||||
{
|
||||
__u64 id;
|
||||
|
||||
/* [1] &level passed to external function that may change it, it's
|
||||
* incompatible with loop unroll.
|
||||
*/
|
||||
id = bpf_skb_ancestor_cgroup_id(skb, level);
|
||||
bpf_map_update_elem(&cgroup_ids, &level, &id, 0);
|
||||
}
|
||||
|
||||
SEC("cgroup_id_logger")
|
||||
int log_cgroup_id(struct __sk_buff *skb)
|
||||
{
|
||||
/* Loop unroll can't be used here due to [1]. Unrolling manually.
|
||||
* Number of calls should be in sync with NUM_CGROUP_LEVELS.
|
||||
*/
|
||||
log_nth_level(skb, 0);
|
||||
log_nth_level(skb, 1);
|
||||
log_nth_level(skb, 2);
|
||||
log_nth_level(skb, 3);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
187
tools/testing/selftests/bpf/test_skb_cgroup_id_user.c
Normal file
187
tools/testing/selftests/bpf/test_skb_cgroup_id_user.c
Normal file
@@ -0,0 +1,187 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018 Facebook
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
|
||||
#include "bpf_rlimit.h"
|
||||
#include "cgroup_helpers.h"
|
||||
|
||||
#define CGROUP_PATH "/skb_cgroup_test"
|
||||
#define NUM_CGROUP_LEVELS 4
|
||||
|
||||
/* RFC 4291, Section 2.7.1 */
|
||||
#define LINKLOCAL_MULTICAST "ff02::1"
|
||||
|
||||
static int mk_dst_addr(const char *ip, const char *iface,
|
||||
struct sockaddr_in6 *dst)
|
||||
{
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
|
||||
dst->sin6_family = AF_INET6;
|
||||
dst->sin6_port = htons(1025);
|
||||
|
||||
if (inet_pton(AF_INET6, ip, &dst->sin6_addr) != 1) {
|
||||
log_err("Invalid IPv6: %s", ip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dst->sin6_scope_id = if_nametoindex(iface);
|
||||
if (!dst->sin6_scope_id) {
|
||||
log_err("Failed to get index of iface: %s", iface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_packet(const char *iface)
|
||||
{
|
||||
struct sockaddr_in6 dst;
|
||||
char msg[] = "msg";
|
||||
int err = 0;
|
||||
int fd = -1;
|
||||
|
||||
if (mk_dst_addr(LINKLOCAL_MULTICAST, iface, &dst))
|
||||
goto err;
|
||||
|
||||
fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_err("Failed to create UDP socket");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sendto(fd, &msg, sizeof(msg), 0, (const struct sockaddr *)&dst,
|
||||
sizeof(dst)) == -1) {
|
||||
log_err("Failed to send datagram");
|
||||
goto err;
|
||||
}
|
||||
|
||||
goto out;
|
||||
err:
|
||||
err = -1;
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
int get_map_fd_by_prog_id(int prog_id)
|
||||
{
|
||||
struct bpf_prog_info info = {};
|
||||
__u32 info_len = sizeof(info);
|
||||
__u32 map_ids[1];
|
||||
int prog_fd = -1;
|
||||
int map_fd = -1;
|
||||
|
||||
prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
||||
if (prog_fd < 0) {
|
||||
log_err("Failed to get fd by prog id %d", prog_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
info.nr_map_ids = 1;
|
||||
info.map_ids = (__u64) (unsigned long) map_ids;
|
||||
|
||||
if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
|
||||
log_err("Failed to get info by prog fd %d", prog_fd);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!info.nr_map_ids) {
|
||||
log_err("No maps found for prog fd %d", prog_fd);
|
||||
goto err;
|
||||
}
|
||||
|
||||
map_fd = bpf_map_get_fd_by_id(map_ids[0]);
|
||||
if (map_fd < 0)
|
||||
log_err("Failed to get fd by map id %d", map_ids[0]);
|
||||
err:
|
||||
if (prog_fd >= 0)
|
||||
close(prog_fd);
|
||||
return map_fd;
|
||||
}
|
||||
|
||||
int check_ancestor_cgroup_ids(int prog_id)
|
||||
{
|
||||
__u64 actual_ids[NUM_CGROUP_LEVELS], expected_ids[NUM_CGROUP_LEVELS];
|
||||
__u32 level;
|
||||
int err = 0;
|
||||
int map_fd;
|
||||
|
||||
expected_ids[0] = 0x100000001; /* root cgroup */
|
||||
expected_ids[1] = get_cgroup_id("");
|
||||
expected_ids[2] = get_cgroup_id(CGROUP_PATH);
|
||||
expected_ids[3] = 0; /* non-existent cgroup */
|
||||
|
||||
map_fd = get_map_fd_by_prog_id(prog_id);
|
||||
if (map_fd < 0)
|
||||
goto err;
|
||||
|
||||
for (level = 0; level < NUM_CGROUP_LEVELS; ++level) {
|
||||
if (bpf_map_lookup_elem(map_fd, &level, &actual_ids[level])) {
|
||||
log_err("Failed to lookup key %d", level);
|
||||
goto err;
|
||||
}
|
||||
if (actual_ids[level] != expected_ids[level]) {
|
||||
log_err("%llx (actual) != %llx (expected), level: %u\n",
|
||||
actual_ids[level], expected_ids[level], level);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
err:
|
||||
err = -1;
|
||||
out:
|
||||
if (map_fd >= 0)
|
||||
close(map_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int cgfd = -1;
|
||||
int err = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s iface prog_id\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setup_cgroup_environment())
|
||||
goto err;
|
||||
|
||||
cgfd = create_and_get_cgroup(CGROUP_PATH);
|
||||
if (!cgfd)
|
||||
goto err;
|
||||
|
||||
if (join_cgroup(CGROUP_PATH))
|
||||
goto err;
|
||||
|
||||
if (send_packet(argv[1]))
|
||||
goto err;
|
||||
|
||||
if (check_ancestor_cgroup_ids(atoi(argv[2])))
|
||||
goto err;
|
||||
|
||||
goto out;
|
||||
err:
|
||||
err = -1;
|
||||
out:
|
||||
close(cgfd);
|
||||
cleanup_cgroup_environment();
|
||||
printf("[%s]\n", err ? "FAIL" : "PASS");
|
||||
return err;
|
||||
}
|
@@ -14,10 +14,7 @@
|
||||
|
||||
#include "cgroup_helpers.h"
|
||||
#include "bpf_rlimit.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
#include "bpf_util.h"
|
||||
|
||||
#define CG_PATH "/foo"
|
||||
#define MAX_INSNS 512
|
||||
|
@@ -20,15 +20,12 @@
|
||||
|
||||
#include "cgroup_helpers.h"
|
||||
#include "bpf_rlimit.h"
|
||||
#include "bpf_util.h"
|
||||
|
||||
#ifndef ENOTSUPP
|
||||
# define ENOTSUPP 524
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#define CG_PATH "/foo"
|
||||
#define CONNECT4_PROG_PATH "./connect4_prog.o"
|
||||
#define CONNECT6_PROG_PATH "./connect6_prog.o"
|
||||
@@ -998,8 +995,9 @@ int init_pktinfo(int domain, struct cmsghdr *cmsg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sendmsg_to_server(const struct sockaddr_storage *addr,
|
||||
socklen_t addr_len, int set_cmsg, int *syscall_err)
|
||||
static int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
|
||||
socklen_t addr_len, int set_cmsg, int flags,
|
||||
int *syscall_err)
|
||||
{
|
||||
union {
|
||||
char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
@@ -1022,7 +1020,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr,
|
||||
goto err;
|
||||
}
|
||||
|
||||
fd = socket(domain, SOCK_DGRAM, 0);
|
||||
fd = socket(domain, type, 0);
|
||||
if (fd == -1) {
|
||||
log_err("Failed to create client socket");
|
||||
goto err;
|
||||
@@ -1052,7 +1050,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr,
|
||||
}
|
||||
}
|
||||
|
||||
if (sendmsg(fd, &hdr, 0) != sizeof(data)) {
|
||||
if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
|
||||
log_err("Fail to send message to server");
|
||||
*syscall_err = errno;
|
||||
goto err;
|
||||
@@ -1066,6 +1064,15 @@ out:
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int fastconnect_to_server(const struct sockaddr_storage *addr,
|
||||
socklen_t addr_len)
|
||||
{
|
||||
int sendmsg_err;
|
||||
|
||||
return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
|
||||
MSG_FASTOPEN, &sendmsg_err);
|
||||
}
|
||||
|
||||
static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
|
||||
{
|
||||
struct timeval tv;
|
||||
@@ -1185,6 +1192,20 @@ static int run_connect_test_case(const struct sock_addr_test *test)
|
||||
if (cmp_local_ip(clientfd, &expected_src_addr))
|
||||
goto err;
|
||||
|
||||
if (test->type == SOCK_STREAM) {
|
||||
/* Test TCP Fast Open scenario */
|
||||
clientfd = fastconnect_to_server(&requested_addr, addr_len);
|
||||
if (clientfd == -1)
|
||||
goto err;
|
||||
|
||||
/* Make sure src and dst addrs were overridden properly */
|
||||
if (cmp_peer_addr(clientfd, &expected_addr))
|
||||
goto err;
|
||||
|
||||
if (cmp_local_ip(clientfd, &expected_src_addr))
|
||||
goto err;
|
||||
}
|
||||
|
||||
goto out;
|
||||
err:
|
||||
err = -1;
|
||||
@@ -1222,8 +1243,9 @@ static int run_sendmsg_test_case(const struct sock_addr_test *test)
|
||||
if (clientfd >= 0)
|
||||
close(clientfd);
|
||||
|
||||
clientfd = sendmsg_to_server(&requested_addr, addr_len,
|
||||
set_cmsg, &err);
|
||||
clientfd = sendmsg_to_server(test->type, &requested_addr,
|
||||
addr_len, set_cmsg, /*flags*/0,
|
||||
&err);
|
||||
if (err)
|
||||
goto out;
|
||||
else if (clientfd == -1)
|
||||
|
225
tools/testing/selftests/bpf/test_socket_cookie.c
Normal file
225
tools/testing/selftests/bpf/test_socket_cookie.c
Normal file
@@ -0,0 +1,225 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018 Facebook
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
|
||||
#include "bpf_rlimit.h"
|
||||
#include "cgroup_helpers.h"
|
||||
|
||||
#define CG_PATH "/foo"
|
||||
#define SOCKET_COOKIE_PROG "./socket_cookie_prog.o"
|
||||
|
||||
static int start_server(void)
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
int fd;
|
||||
|
||||
fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
log_err("Failed to create server socket");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_addr = in6addr_loopback;
|
||||
addr.sin6_port = 0;
|
||||
|
||||
if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
log_err("Failed to bind server socket");
|
||||
goto close_out;
|
||||
}
|
||||
|
||||
if (listen(fd, 128) == -1) {
|
||||
log_err("Failed to listen on server socket");
|
||||
goto close_out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
close_out:
|
||||
close(fd);
|
||||
fd = -1;
|
||||
out:
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int connect_to_server(int server_fd)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
int fd;
|
||||
|
||||
fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
log_err("Failed to create client socket");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) {
|
||||
log_err("Failed to get server addr");
|
||||
goto close_out;
|
||||
}
|
||||
|
||||
if (connect(fd, (const struct sockaddr *)&addr, len) == -1) {
|
||||
log_err("Fail to connect to server");
|
||||
goto close_out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
close_out:
|
||||
close(fd);
|
||||
fd = -1;
|
||||
out:
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int validate_map(struct bpf_map *map, int client_fd)
|
||||
{
|
||||
__u32 cookie_expected_value;
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
__u32 cookie_value;
|
||||
__u64 cookie_key;
|
||||
int err = 0;
|
||||
int map_fd;
|
||||
|
||||
if (!map) {
|
||||
log_err("Map not found in BPF object");
|
||||
goto err;
|
||||
}
|
||||
|
||||
map_fd = bpf_map__fd(map);
|
||||
|
||||
err = bpf_map_get_next_key(map_fd, NULL, &cookie_key);
|
||||
if (err) {
|
||||
log_err("Can't get cookie key from map");
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = bpf_map_lookup_elem(map_fd, &cookie_key, &cookie_value);
|
||||
if (err) {
|
||||
log_err("Can't get cookie value from map");
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = getsockname(client_fd, (struct sockaddr *)&addr, &len);
|
||||
if (err) {
|
||||
log_err("Can't get client local addr");
|
||||
goto out;
|
||||
}
|
||||
|
||||
cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF;
|
||||
if (cookie_value != cookie_expected_value) {
|
||||
log_err("Unexpected value in map: %x != %x", cookie_value,
|
||||
cookie_expected_value);
|
||||
goto err;
|
||||
}
|
||||
|
||||
goto out;
|
||||
err:
|
||||
err = -1;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int run_test(int cgfd)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
struct bpf_prog_load_attr attr;
|
||||
struct bpf_program *prog;
|
||||
struct bpf_object *pobj;
|
||||
const char *prog_name;
|
||||
int server_fd = -1;
|
||||
int client_fd = -1;
|
||||
int prog_fd = -1;
|
||||
int err = 0;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.file = SOCKET_COOKIE_PROG;
|
||||
attr.prog_type = BPF_PROG_TYPE_UNSPEC;
|
||||
|
||||
err = bpf_prog_load_xattr(&attr, &pobj, &prog_fd);
|
||||
if (err) {
|
||||
log_err("Failed to load %s", attr.file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bpf_object__for_each_program(prog, pobj) {
|
||||
prog_name = bpf_program__title(prog, /*needs_copy*/ false);
|
||||
|
||||
if (strcmp(prog_name, "cgroup/connect6") == 0) {
|
||||
attach_type = BPF_CGROUP_INET6_CONNECT;
|
||||
} else if (strcmp(prog_name, "sockops") == 0) {
|
||||
attach_type = BPF_CGROUP_SOCK_OPS;
|
||||
} else {
|
||||
log_err("Unexpected prog: %s", prog_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = bpf_prog_attach(bpf_program__fd(prog), cgfd, attach_type,
|
||||
BPF_F_ALLOW_OVERRIDE);
|
||||
if (err) {
|
||||
log_err("Failed to attach prog %s", prog_name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
server_fd = start_server();
|
||||
if (server_fd == -1)
|
||||
goto err;
|
||||
|
||||
client_fd = connect_to_server(server_fd);
|
||||
if (client_fd == -1)
|
||||
goto err;
|
||||
|
||||
if (validate_map(bpf_map__next(NULL, pobj), client_fd))
|
||||
goto err;
|
||||
|
||||
goto out;
|
||||
err:
|
||||
err = -1;
|
||||
out:
|
||||
close(client_fd);
|
||||
close(server_fd);
|
||||
bpf_object__close(pobj);
|
||||
printf("%s\n", err ? "FAILED" : "PASSED");
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int cgfd = -1;
|
||||
int err = 0;
|
||||
|
||||
if (setup_cgroup_environment())
|
||||
goto err;
|
||||
|
||||
cgfd = create_and_get_cgroup(CG_PATH);
|
||||
if (!cgfd)
|
||||
goto err;
|
||||
|
||||
if (join_cgroup(CG_PATH))
|
||||
goto err;
|
||||
|
||||
if (run_test(cgfd))
|
||||
goto err;
|
||||
|
||||
goto out;
|
||||
err:
|
||||
err = -1;
|
||||
out:
|
||||
close(cgfd);
|
||||
cleanup_cgroup_environment();
|
||||
return err;
|
||||
}
|
@@ -12,5 +12,6 @@ struct tcpbpf_globals {
|
||||
__u32 good_cb_test_rv;
|
||||
__u64 bytes_received;
|
||||
__u64 bytes_acked;
|
||||
__u32 num_listen;
|
||||
};
|
||||
#endif
|
||||
|
@@ -96,15 +96,22 @@ int bpf_testcb(struct bpf_sock_ops *skops)
|
||||
if (!gp)
|
||||
break;
|
||||
g = *gp;
|
||||
g.total_retrans = skops->total_retrans;
|
||||
g.data_segs_in = skops->data_segs_in;
|
||||
g.data_segs_out = skops->data_segs_out;
|
||||
g.bytes_received = skops->bytes_received;
|
||||
g.bytes_acked = skops->bytes_acked;
|
||||
if (skops->args[0] == BPF_TCP_LISTEN) {
|
||||
g.num_listen++;
|
||||
} else {
|
||||
g.total_retrans = skops->total_retrans;
|
||||
g.data_segs_in = skops->data_segs_in;
|
||||
g.data_segs_out = skops->data_segs_out;
|
||||
g.bytes_received = skops->bytes_received;
|
||||
g.bytes_acked = skops->bytes_acked;
|
||||
}
|
||||
bpf_map_update_elem(&global_map, &key, &g,
|
||||
BPF_ANY);
|
||||
}
|
||||
break;
|
||||
case BPF_SOCK_OPS_TCP_LISTEN_CB:
|
||||
bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
|
||||
break;
|
||||
default:
|
||||
rv = -1;
|
||||
}
|
||||
|
@@ -1,27 +1,59 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include "bpf_util.h"
|
||||
|
||||
#include "bpf_rlimit.h"
|
||||
#include <linux/perf_event.h>
|
||||
#include "bpf_util.h"
|
||||
#include "cgroup_helpers.h"
|
||||
|
||||
#include "test_tcpbpf.h"
|
||||
|
||||
#define EXPECT_EQ(expected, actual, fmt) \
|
||||
do { \
|
||||
if ((expected) != (actual)) { \
|
||||
printf(" Value of: " #actual "\n" \
|
||||
" Actual: %" fmt "\n" \
|
||||
" Expected: %" fmt "\n", \
|
||||
(actual), (expected)); \
|
||||
goto err; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int verify_result(const struct tcpbpf_globals *result)
|
||||
{
|
||||
__u32 expected_events;
|
||||
|
||||
expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) |
|
||||
(1 << BPF_SOCK_OPS_RWND_INIT) |
|
||||
(1 << BPF_SOCK_OPS_TCP_CONNECT_CB) |
|
||||
(1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) |
|
||||
(1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) |
|
||||
(1 << BPF_SOCK_OPS_NEEDS_ECN) |
|
||||
(1 << BPF_SOCK_OPS_STATE_CB) |
|
||||
(1 << BPF_SOCK_OPS_TCP_LISTEN_CB));
|
||||
|
||||
EXPECT_EQ(expected_events, result->event_map, "#" PRIx32);
|
||||
EXPECT_EQ(501ULL, result->bytes_received, "llu");
|
||||
EXPECT_EQ(1002ULL, result->bytes_acked, "llu");
|
||||
EXPECT_EQ(1, result->data_segs_in, PRIu32);
|
||||
EXPECT_EQ(1, result->data_segs_out, PRIu32);
|
||||
EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32);
|
||||
EXPECT_EQ(0, result->good_cb_test_rv, PRIu32);
|
||||
EXPECT_EQ(1, result->num_listen, PRIu32);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bpf_find_map(const char *test, struct bpf_object *obj,
|
||||
const char *name)
|
||||
{
|
||||
@@ -35,42 +67,28 @@ static int bpf_find_map(const char *test, struct bpf_object *obj,
|
||||
return bpf_map__fd(map);
|
||||
}
|
||||
|
||||
#define SYSTEM(CMD) \
|
||||
do { \
|
||||
if (system(CMD)) { \
|
||||
printf("system(%s) FAILS!\n", CMD); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *file = "test_tcpbpf_kern.o";
|
||||
struct tcpbpf_globals g = {0};
|
||||
int cg_fd, prog_fd, map_fd;
|
||||
bool debug_flag = false;
|
||||
const char *cg_path = "/foo";
|
||||
int error = EXIT_FAILURE;
|
||||
struct bpf_object *obj;
|
||||
char cmd[100], *dir;
|
||||
struct stat buffer;
|
||||
int prog_fd, map_fd;
|
||||
int cg_fd = -1;
|
||||
__u32 key = 0;
|
||||
int pid;
|
||||
int rv;
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "-d") == 0)
|
||||
debug_flag = true;
|
||||
if (setup_cgroup_environment())
|
||||
goto err;
|
||||
|
||||
dir = "/tmp/cgroupv2/foo";
|
||||
cg_fd = create_and_get_cgroup(cg_path);
|
||||
if (!cg_fd)
|
||||
goto err;
|
||||
|
||||
if (stat(dir, &buffer) != 0) {
|
||||
SYSTEM("mkdir -p /tmp/cgroupv2");
|
||||
SYSTEM("mount -t cgroup2 none /tmp/cgroupv2");
|
||||
SYSTEM("mkdir -p /tmp/cgroupv2/foo");
|
||||
}
|
||||
pid = (int) getpid();
|
||||
sprintf(cmd, "echo %d >> /tmp/cgroupv2/foo/cgroup.procs", pid);
|
||||
SYSTEM(cmd);
|
||||
if (join_cgroup(cg_path))
|
||||
goto err;
|
||||
|
||||
cg_fd = open(dir, O_DIRECTORY, O_RDONLY);
|
||||
if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) {
|
||||
printf("FAILED: load_bpf_file failed for: %s\n", file);
|
||||
goto err;
|
||||
@@ -83,7 +101,10 @@ int main(int argc, char **argv)
|
||||
goto err;
|
||||
}
|
||||
|
||||
SYSTEM("./tcp_server.py");
|
||||
if (system("./tcp_server.py")) {
|
||||
printf("FAILED: TCP server\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
map_fd = bpf_find_map(__func__, obj, "global_map");
|
||||
if (map_fd < 0)
|
||||
@@ -95,34 +116,16 @@ int main(int argc, char **argv)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (g.bytes_received != 501 || g.bytes_acked != 1002 ||
|
||||
g.data_segs_in != 1 || g.data_segs_out != 1 ||
|
||||
(g.event_map ^ 0x47e) != 0 || g.bad_cb_test_rv != 0x80 ||
|
||||
g.good_cb_test_rv != 0) {
|
||||
if (verify_result(&g)) {
|
||||
printf("FAILED: Wrong stats\n");
|
||||
if (debug_flag) {
|
||||
printf("\n");
|
||||
printf("bytes_received: %d (expecting 501)\n",
|
||||
(int)g.bytes_received);
|
||||
printf("bytes_acked: %d (expecting 1002)\n",
|
||||
(int)g.bytes_acked);
|
||||
printf("data_segs_in: %d (expecting 1)\n",
|
||||
g.data_segs_in);
|
||||
printf("data_segs_out: %d (expecting 1)\n",
|
||||
g.data_segs_out);
|
||||
printf("event_map: 0x%x (at least 0x47e)\n",
|
||||
g.event_map);
|
||||
printf("bad_cb_test_rv: 0x%x (expecting 0x80)\n",
|
||||
g.bad_cb_test_rv);
|
||||
printf("good_cb_test_rv:0x%x (expecting 0)\n",
|
||||
g.good_cb_test_rv);
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
printf("PASSED!\n");
|
||||
error = 0;
|
||||
err:
|
||||
bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS);
|
||||
close(cg_fd);
|
||||
cleanup_cgroup_environment();
|
||||
return error;
|
||||
|
||||
}
|
||||
|
@@ -42,15 +42,12 @@
|
||||
#endif
|
||||
#include "bpf_rlimit.h"
|
||||
#include "bpf_rand.h"
|
||||
#include "bpf_util.h"
|
||||
#include "../../../include/linux/filter.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#define MAX_INSNS BPF_MAXINSNS
|
||||
#define MAX_FIXUPS 8
|
||||
#define MAX_NR_MAPS 7
|
||||
#define MAX_NR_MAPS 8
|
||||
#define POINTER_VALUE 0xcafe4all
|
||||
#define TEST_DATA_LEN 64
|
||||
|
||||
@@ -70,6 +67,7 @@ struct bpf_test {
|
||||
int fixup_prog1[MAX_FIXUPS];
|
||||
int fixup_prog2[MAX_FIXUPS];
|
||||
int fixup_map_in_map[MAX_FIXUPS];
|
||||
int fixup_cgroup_storage[MAX_FIXUPS];
|
||||
const char *errstr;
|
||||
const char *errstr_unpriv;
|
||||
uint32_t retval;
|
||||
@@ -4630,6 +4628,121 @@ static struct bpf_test tests[] = {
|
||||
.result = REJECT,
|
||||
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
|
||||
},
|
||||
{
|
||||
"valid cgroup storage access",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_cgroup_storage = { 1 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"invalid cgroup storage access 1",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map1 = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "cannot pass map_type 1 into func bpf_get_local_storage",
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"invalid cgroup storage access 2",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 1),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = REJECT,
|
||||
.errstr = "fd 1 is not pointing to valid bpf_map",
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"invalid per-cgroup storage access 3",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 256),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_cgroup_storage = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=64 off=256 size=4",
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"invalid cgroup storage access 4",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, -2),
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_cgroup_storage = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=64 off=-2 size=4",
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"invalid cgroup storage access 5",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 7),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_cgroup_storage = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "get_local_storage() doesn't support non-zero flags",
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"invalid cgroup storage access 6",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_get_local_storage),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_cgroup_storage = { 1 },
|
||||
.result = REJECT,
|
||||
.errstr = "get_local_storage() doesn't support non-zero flags",
|
||||
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
|
||||
},
|
||||
{
|
||||
"multiple registers share map_lookup_elem result",
|
||||
.insns = {
|
||||
@@ -6997,7 +7110,7 @@ static struct bpf_test tests[] = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_REG(BPF_REG_0, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_in_map = { 3 },
|
||||
@@ -7020,7 +7133,7 @@ static struct bpf_test tests[] = {
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_REG(BPF_REG_0, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_in_map = { 3 },
|
||||
@@ -7042,7 +7155,7 @@ static struct bpf_test tests[] = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||
BPF_FUNC_map_lookup_elem),
|
||||
BPF_MOV64_REG(BPF_REG_0, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map_in_map = { 3 },
|
||||
@@ -12372,6 +12485,32 @@ static struct bpf_test tests[] = {
|
||||
.result = REJECT,
|
||||
.errstr = "variable ctx access var_off=(0x0; 0x4)",
|
||||
},
|
||||
{
|
||||
"mov64 src == dst",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_2),
|
||||
// Check bounds are OK
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
.result = ACCEPT,
|
||||
},
|
||||
{
|
||||
"mov64 src != dst",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_3),
|
||||
// Check bounds are OK
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
.result = ACCEPT,
|
||||
},
|
||||
};
|
||||
|
||||
static int probe_filter_length(const struct bpf_insn *fp)
|
||||
@@ -12476,6 +12615,19 @@ static int create_map_in_map(void)
|
||||
return outer_map_fd;
|
||||
}
|
||||
|
||||
static int create_cgroup_storage(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE,
|
||||
sizeof(struct bpf_cgroup_storage_key),
|
||||
TEST_DATA_LEN, 0, 0);
|
||||
if (fd < 0)
|
||||
printf("Failed to create array '%s'!\n", strerror(errno));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static char bpf_vlog[UINT_MAX >> 8];
|
||||
|
||||
static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
|
||||
@@ -12488,6 +12640,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
|
||||
int *fixup_prog1 = test->fixup_prog1;
|
||||
int *fixup_prog2 = test->fixup_prog2;
|
||||
int *fixup_map_in_map = test->fixup_map_in_map;
|
||||
int *fixup_cgroup_storage = test->fixup_cgroup_storage;
|
||||
|
||||
if (test->fill_helper)
|
||||
test->fill_helper(test);
|
||||
@@ -12555,6 +12708,14 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
|
||||
fixup_map_in_map++;
|
||||
} while (*fixup_map_in_map);
|
||||
}
|
||||
|
||||
if (*fixup_cgroup_storage) {
|
||||
map_fds[7] = create_cgroup_storage();
|
||||
do {
|
||||
prog[*fixup_cgroup_storage].imm = map_fds[7];
|
||||
fixup_cgroup_storage++;
|
||||
} while (*fixup_cgroup_storage);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||
|
@@ -88,7 +88,7 @@ static int page_size;
|
||||
static int page_cnt = 8;
|
||||
static struct perf_event_mmap_page *header;
|
||||
|
||||
int perf_event_mmap(int fd)
|
||||
int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header)
|
||||
{
|
||||
void *base;
|
||||
int mmap_size;
|
||||
@@ -102,10 +102,15 @@ int perf_event_mmap(int fd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
header = base;
|
||||
*header = base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_event_mmap(int fd)
|
||||
{
|
||||
return perf_event_mmap_header(fd, &header);
|
||||
}
|
||||
|
||||
static int perf_event_poll(int fd)
|
||||
{
|
||||
struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
||||
@@ -163,3 +168,42 @@ int perf_event_poller(int fd, perf_event_print_fn output_fn)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers,
|
||||
int num_fds, perf_event_print_fn output_fn)
|
||||
{
|
||||
enum bpf_perf_event_ret ret;
|
||||
struct pollfd *pfds;
|
||||
void *buf = NULL;
|
||||
size_t len = 0;
|
||||
int i;
|
||||
|
||||
pfds = calloc(num_fds, sizeof(*pfds));
|
||||
if (!pfds)
|
||||
return LIBBPF_PERF_EVENT_ERROR;
|
||||
|
||||
for (i = 0; i < num_fds; i++) {
|
||||
pfds[i].fd = fds[i];
|
||||
pfds[i].events = POLLIN;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
poll(pfds, num_fds, 1000);
|
||||
for (i = 0; i < num_fds; i++) {
|
||||
if (!pfds[i].revents)
|
||||
continue;
|
||||
|
||||
ret = bpf_perf_event_read_simple(headers[i],
|
||||
page_cnt * page_size,
|
||||
page_size, &buf, &len,
|
||||
bpf_perf_event_print,
|
||||
output_fn);
|
||||
if (ret != LIBBPF_PERF_EVENT_CONT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
free(pfds);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#define __TRACE_HELPER_H
|
||||
|
||||
#include <libbpf.h>
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
struct ksym {
|
||||
long addr;
|
||||
@@ -16,6 +17,9 @@ long ksym_get_addr(const char *name);
|
||||
typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size);
|
||||
|
||||
int perf_event_mmap(int fd);
|
||||
int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header);
|
||||
/* return LIBBPF_PERF_EVENT_DONE or LIBBPF_PERF_EVENT_ERROR */
|
||||
int perf_event_poller(int fd, perf_event_print_fn output_fn);
|
||||
int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers,
|
||||
int num_fds, perf_event_print_fn output_fn);
|
||||
#endif
|
||||
|
217
tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh
Executable file
217
tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh
Executable file
@@ -0,0 +1,217 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# This test uses standard topology for testing gretap. See
|
||||
# ../../../net/forwarding/mirror_gre_topo_lib.sh for more details.
|
||||
#
|
||||
# Test offloading various features of offloading gretap mirrors specific to
|
||||
# mlxsw.
|
||||
|
||||
lib_dir=$(dirname $0)/../../../net/forwarding
|
||||
|
||||
NUM_NETIFS=6
|
||||
source $lib_dir/lib.sh
|
||||
source $lib_dir/mirror_lib.sh
|
||||
source $lib_dir/mirror_gre_lib.sh
|
||||
source $lib_dir/mirror_gre_topo_lib.sh
|
||||
|
||||
setup_keyful()
|
||||
{
|
||||
tunnel_create gt6-key ip6gretap 2001:db8:3::1 2001:db8:3::2 \
|
||||
ttl 100 tos inherit allow-localremote \
|
||||
key 1234
|
||||
|
||||
tunnel_create h3-gt6-key ip6gretap 2001:db8:3::2 2001:db8:3::1 \
|
||||
key 1234
|
||||
ip link set h3-gt6-key vrf v$h3
|
||||
matchall_sink_create h3-gt6-key
|
||||
|
||||
ip address add dev $swp3 2001:db8:3::1/64
|
||||
ip address add dev $h3 2001:db8:3::2/64
|
||||
}
|
||||
|
||||
cleanup_keyful()
|
||||
{
|
||||
ip address del dev $h3 2001:db8:3::2/64
|
||||
ip address del dev $swp3 2001:db8:3::1/64
|
||||
|
||||
tunnel_destroy h3-gt6-key
|
||||
tunnel_destroy gt6-key
|
||||
}
|
||||
|
||||
setup_soft()
|
||||
{
|
||||
# Set up a topology for testing underlay routes that point at an
|
||||
# unsupported soft device.
|
||||
|
||||
tunnel_create gt6-soft ip6gretap 2001:db8:4::1 2001:db8:4::2 \
|
||||
ttl 100 tos inherit allow-localremote
|
||||
|
||||
tunnel_create h3-gt6-soft ip6gretap 2001:db8:4::2 2001:db8:4::1
|
||||
ip link set h3-gt6-soft vrf v$h3
|
||||
matchall_sink_create h3-gt6-soft
|
||||
|
||||
ip link add name v1 type veth peer name v2
|
||||
ip link set dev v1 up
|
||||
ip address add dev v1 2001:db8:4::1/64
|
||||
|
||||
ip link set dev v2 vrf v$h3
|
||||
ip link set dev v2 up
|
||||
ip address add dev v2 2001:db8:4::2/64
|
||||
}
|
||||
|
||||
cleanup_soft()
|
||||
{
|
||||
ip link del dev v1
|
||||
|
||||
tunnel_destroy h3-gt6-soft
|
||||
tunnel_destroy gt6-soft
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
swp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
mirror_gre_topo_create
|
||||
|
||||
ip address add dev $swp3 2001:db8:2::1/64
|
||||
ip address add dev $h3 2001:db8:2::2/64
|
||||
|
||||
ip address add dev $swp3 192.0.2.129/28
|
||||
ip address add dev $h3 192.0.2.130/28
|
||||
|
||||
setup_keyful
|
||||
setup_soft
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
cleanup_soft
|
||||
cleanup_keyful
|
||||
|
||||
ip address del dev $h3 2001:db8:2::2/64
|
||||
ip address del dev $swp3 2001:db8:2::1/64
|
||||
|
||||
ip address del dev $h3 192.0.2.130/28
|
||||
ip address del dev $swp3 192.0.2.129/28
|
||||
|
||||
mirror_gre_topo_destroy
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
test_span_gre_ttl_inherit()
|
||||
{
|
||||
local tundev=$1; shift
|
||||
local type=$1; shift
|
||||
local what=$1; shift
|
||||
|
||||
RET=0
|
||||
|
||||
ip link set dev $tundev type $type ttl inherit
|
||||
mirror_install $swp1 ingress $tundev "matchall $tcflags"
|
||||
fail_test_span_gre_dir $tundev ingress
|
||||
|
||||
ip link set dev $tundev type $type ttl 100
|
||||
|
||||
quick_test_span_gre_dir $tundev ingress
|
||||
mirror_uninstall $swp1 ingress
|
||||
|
||||
log_test "$what: no offload on TTL of inherit ($tcflags)"
|
||||
}
|
||||
|
||||
test_span_gre_tos_fixed()
|
||||
{
|
||||
local tundev=$1; shift
|
||||
local type=$1; shift
|
||||
local what=$1; shift
|
||||
|
||||
RET=0
|
||||
|
||||
ip link set dev $tundev type $type tos 0x10
|
||||
mirror_install $swp1 ingress $tundev "matchall $tcflags"
|
||||
fail_test_span_gre_dir $tundev ingress
|
||||
|
||||
ip link set dev $tundev type $type tos inherit
|
||||
quick_test_span_gre_dir $tundev ingress
|
||||
mirror_uninstall $swp1 ingress
|
||||
|
||||
log_test "$what: no offload on a fixed TOS ($tcflags)"
|
||||
}
|
||||
|
||||
test_span_failable()
|
||||
{
|
||||
local should_fail=$1; shift
|
||||
local tundev=$1; shift
|
||||
local what=$1; shift
|
||||
|
||||
RET=0
|
||||
|
||||
mirror_install $swp1 ingress $tundev "matchall $tcflags"
|
||||
if ((should_fail)); then
|
||||
fail_test_span_gre_dir $tundev ingress
|
||||
else
|
||||
quick_test_span_gre_dir $tundev ingress
|
||||
fi
|
||||
mirror_uninstall $swp1 ingress
|
||||
|
||||
log_test "$what: should_fail=$should_fail ($tcflags)"
|
||||
}
|
||||
|
||||
test_failable()
|
||||
{
|
||||
local should_fail=$1; shift
|
||||
|
||||
test_span_failable $should_fail gt6-key "mirror to keyful gretap"
|
||||
test_span_failable $should_fail gt6-soft "mirror to gretap w/ soft underlay"
|
||||
}
|
||||
|
||||
test_sw()
|
||||
{
|
||||
slow_path_trap_install $swp1 ingress
|
||||
slow_path_trap_install $swp1 egress
|
||||
|
||||
test_failable 0
|
||||
|
||||
slow_path_trap_uninstall $swp1 egress
|
||||
slow_path_trap_uninstall $swp1 ingress
|
||||
}
|
||||
|
||||
test_hw()
|
||||
{
|
||||
test_failable 1
|
||||
|
||||
test_span_gre_tos_fixed gt4 gretap "mirror to gretap"
|
||||
test_span_gre_tos_fixed gt6 ip6gretap "mirror to ip6gretap"
|
||||
|
||||
test_span_gre_ttl_inherit gt4 gretap "mirror to gretap"
|
||||
test_span_gre_ttl_inherit gt6 ip6gretap "mirror to ip6gretap"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
if ! tc_offload_check; then
|
||||
check_err 1 "Could not test offloaded functionality"
|
||||
log_test "mlxsw-specific tests for mirror to gretap"
|
||||
exit
|
||||
fi
|
||||
|
||||
tcflags="skip_hw"
|
||||
test_sw
|
||||
|
||||
tcflags="skip_sw"
|
||||
test_hw
|
||||
|
||||
exit $EXIT_STATUS
|
197
tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh
Normal file
197
tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh
Normal file
@@ -0,0 +1,197 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test offloading a number of mirrors-to-gretap. The test creates a number of
|
||||
# tunnels. Then it adds one flower mirror for each of the tunnels, matching a
|
||||
# given host IP. Then it generates traffic at each of the host IPs and checks
|
||||
# that the traffic has been mirrored at the appropriate tunnel.
|
||||
#
|
||||
# +--------------------------+ +--------------------------+
|
||||
# | H1 | | H2 |
|
||||
# | + $h1 | | $h2 + |
|
||||
# | | 2001:db8:1:X::1/64 | | 2001:db8:1:X::2/64 | |
|
||||
# +-----|--------------------+ +--------------------|-----+
|
||||
# | |
|
||||
# +-----|-------------------------------------------------------------|-----+
|
||||
# | SW o--> mirrors | |
|
||||
# | +---|-------------------------------------------------------------|---+ |
|
||||
# | | + $swp1 BR $swp2 + | |
|
||||
# | +---------------------------------------------------------------------+ |
|
||||
# | |
|
||||
# | + $swp3 + gt6-<X> (ip6gretap) |
|
||||
# | | 2001:db8:2:X::1/64 : loc=2001:db8:2:X::1 |
|
||||
# | | : rem=2001:db8:2:X::2 |
|
||||
# | | : ttl=100 |
|
||||
# | | : tos=inherit |
|
||||
# | | : |
|
||||
# +-----|--------------------------------:----------------------------------+
|
||||
# | :
|
||||
# +-----|--------------------------------:----------------------------------+
|
||||
# | H3 + $h3 + h3-gt6-<X> (ip6gretap) |
|
||||
# | 2001:db8:2:X::2/64 loc=2001:db8:2:X::2 |
|
||||
# | rem=2001:db8:2:X::1 |
|
||||
# | ttl=100 |
|
||||
# | tos=inherit |
|
||||
# | |
|
||||
# +-------------------------------------------------------------------------+
|
||||
|
||||
source ../../../../net/forwarding/mirror_lib.sh
|
||||
|
||||
MIRROR_NUM_NETIFS=6
|
||||
|
||||
mirror_gre_ipv6_addr()
|
||||
{
|
||||
local net=$1; shift
|
||||
local num=$1; shift
|
||||
|
||||
printf "2001:db8:%x:%x" $net $num
|
||||
}
|
||||
|
||||
mirror_gre_tunnels_create()
|
||||
{
|
||||
local count=$1; shift
|
||||
local should_fail=$1; shift
|
||||
|
||||
MIRROR_GRE_BATCH_FILE="$(mktemp)"
|
||||
for ((i=0; i < count; ++i)); do
|
||||
local match_dip=$(mirror_gre_ipv6_addr 1 $i)::2
|
||||
local htun=h3-gt6-$i
|
||||
local tun=gt6-$i
|
||||
|
||||
((mirror_gre_tunnels++))
|
||||
|
||||
ip address add dev $h1 $(mirror_gre_ipv6_addr 1 $i)::1/64
|
||||
ip address add dev $h2 $(mirror_gre_ipv6_addr 1 $i)::2/64
|
||||
|
||||
ip address add dev $swp3 $(mirror_gre_ipv6_addr 2 $i)::1/64
|
||||
ip address add dev $h3 $(mirror_gre_ipv6_addr 2 $i)::2/64
|
||||
|
||||
tunnel_create $tun ip6gretap \
|
||||
$(mirror_gre_ipv6_addr 2 $i)::1 \
|
||||
$(mirror_gre_ipv6_addr 2 $i)::2 \
|
||||
ttl 100 tos inherit allow-localremote
|
||||
|
||||
tunnel_create $htun ip6gretap \
|
||||
$(mirror_gre_ipv6_addr 2 $i)::2 \
|
||||
$(mirror_gre_ipv6_addr 2 $i)::1
|
||||
ip link set $htun vrf v$h3
|
||||
matchall_sink_create $htun
|
||||
|
||||
cat >> $MIRROR_GRE_BATCH_FILE <<-EOF
|
||||
filter add dev $swp1 ingress pref 1000 \
|
||||
protocol ipv6 \
|
||||
flower $tcflags dst_ip $match_dip \
|
||||
action mirred egress mirror dev $tun
|
||||
EOF
|
||||
done
|
||||
|
||||
tc -b $MIRROR_GRE_BATCH_FILE
|
||||
check_err_fail $should_fail $? "Mirror rule insertion"
|
||||
}
|
||||
|
||||
mirror_gre_tunnels_destroy()
|
||||
{
|
||||
local count=$1; shift
|
||||
|
||||
for ((i=0; i < count; ++i)); do
|
||||
local htun=h3-gt6-$i
|
||||
local tun=gt6-$i
|
||||
|
||||
ip address del dev $h3 $(mirror_gre_ipv6_addr 2 $i)::2/64
|
||||
ip address del dev $swp3 $(mirror_gre_ipv6_addr 2 $i)::1/64
|
||||
|
||||
ip address del dev $h2 $(mirror_gre_ipv6_addr 1 $i)::2/64
|
||||
ip address del dev $h1 $(mirror_gre_ipv6_addr 1 $i)::1/64
|
||||
|
||||
tunnel_destroy $htun
|
||||
tunnel_destroy $tun
|
||||
done
|
||||
}
|
||||
|
||||
__mirror_gre_test()
|
||||
{
|
||||
local count=$1; shift
|
||||
local should_fail=$1; shift
|
||||
|
||||
mirror_gre_tunnels_create $count $should_fail
|
||||
if ((should_fail)); then
|
||||
return
|
||||
fi
|
||||
|
||||
sleep 5
|
||||
|
||||
for ((i = 0; i < count; ++i)); do
|
||||
local dip=$(mirror_gre_ipv6_addr 1 $i)::2
|
||||
local htun=h3-gt6-$i
|
||||
local message
|
||||
|
||||
icmp6_capture_install $htun
|
||||
mirror_test v$h1 "" $dip $htun 100 10
|
||||
icmp6_capture_uninstall $htun
|
||||
done
|
||||
}
|
||||
|
||||
mirror_gre_test()
|
||||
{
|
||||
local count=$1; shift
|
||||
local should_fail=$1; shift
|
||||
|
||||
if ! tc_offload_check $TC_FLOWER_NUM_NETIFS; then
|
||||
check_err 1 "Could not test offloaded functionality"
|
||||
return
|
||||
fi
|
||||
|
||||
tcflags="skip_sw"
|
||||
__mirror_gre_test $count $should_fail
|
||||
}
|
||||
|
||||
mirror_gre_setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
swp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
mirror_gre_tunnels=0
|
||||
|
||||
vrf_prepare
|
||||
|
||||
simple_if_init $h1
|
||||
simple_if_init $h2
|
||||
simple_if_init $h3
|
||||
|
||||
ip link add name br1 type bridge vlan_filtering 1
|
||||
ip link set dev br1 up
|
||||
|
||||
ip link set dev $swp1 master br1
|
||||
ip link set dev $swp1 up
|
||||
tc qdisc add dev $swp1 clsact
|
||||
|
||||
ip link set dev $swp2 master br1
|
||||
ip link set dev $swp2 up
|
||||
|
||||
ip link set dev $swp3 up
|
||||
}
|
||||
|
||||
mirror_gre_cleanup()
|
||||
{
|
||||
mirror_gre_tunnels_destroy $mirror_gre_tunnels
|
||||
|
||||
ip link set dev $swp3 down
|
||||
|
||||
ip link set dev $swp2 down
|
||||
|
||||
tc qdisc del dev $swp1 clsact
|
||||
ip link set dev $swp1 down
|
||||
|
||||
ip link del dev br1
|
||||
|
||||
simple_if_fini $h3
|
||||
simple_if_fini $h2
|
||||
simple_if_fini $h1
|
||||
|
||||
vrf_cleanup
|
||||
}
|
189
tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh
Executable file
189
tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh
Executable file
@@ -0,0 +1,189 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test for DSCP prioritization and rewrite. Packets ingress $swp1 with a DSCP
|
||||
# tag and are prioritized according to the map at $swp1. They egress $swp2 and
|
||||
# the DSCP value is updated to match the map at that interface. The updated DSCP
|
||||
# tag is verified at $h2.
|
||||
#
|
||||
# ICMP responses are produced with the same DSCP tag that arrived at $h2. They
|
||||
# go through prioritization at $swp2 and DSCP retagging at $swp1. The tag is
|
||||
# verified at $h1--it should match the original tag.
|
||||
#
|
||||
# +----------------------+ +----------------------+
|
||||
# | H1 | | H2 |
|
||||
# | + $h1 | | $h2 + |
|
||||
# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
|
||||
# +----|-----------------+ +----------------|-----+
|
||||
# | |
|
||||
# +----|----------------------------------------------------------------|-----+
|
||||
# | SW | | |
|
||||
# | +-|----------------------------------------------------------------|-+ |
|
||||
# | | + $swp1 BR $swp2 + | |
|
||||
# | | APP=0,5,10 .. 7,5,17 APP=0,5,20 .. 7,5,27 | |
|
||||
# | +--------------------------------------------------------------------+ |
|
||||
# +---------------------------------------------------------------------------+
|
||||
|
||||
ALL_TESTS="
|
||||
ping_ipv4
|
||||
test_dscp
|
||||
"
|
||||
|
||||
lib_dir=$(dirname $0)/../../../net/forwarding
|
||||
|
||||
NUM_NETIFS=4
|
||||
source $lib_dir/lib.sh
|
||||
|
||||
h1_create()
|
||||
{
|
||||
local dscp;
|
||||
|
||||
simple_if_init $h1 192.0.2.1/28
|
||||
tc qdisc add dev $h1 clsact
|
||||
dscp_capture_install $h1 10
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
dscp_capture_uninstall $h1 10
|
||||
tc qdisc del dev $h1 clsact
|
||||
simple_if_fini $h1 192.0.2.1/28
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.2/28
|
||||
tc qdisc add dev $h2 clsact
|
||||
dscp_capture_install $h2 20
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
dscp_capture_uninstall $h2 20
|
||||
tc qdisc del dev $h2 clsact
|
||||
simple_if_fini $h2 192.0.2.2/28
|
||||
}
|
||||
|
||||
dscp_map()
|
||||
{
|
||||
local base=$1; shift
|
||||
|
||||
for prio in {0..7}; do
|
||||
echo app=$prio,5,$((base + prio))
|
||||
done
|
||||
}
|
||||
|
||||
switch_create()
|
||||
{
|
||||
ip link add name br1 type bridge vlan_filtering 1
|
||||
ip link set dev br1 up
|
||||
ip link set dev $swp1 master br1
|
||||
ip link set dev $swp1 up
|
||||
ip link set dev $swp2 master br1
|
||||
ip link set dev $swp2 up
|
||||
|
||||
lldptool -T -i $swp1 -V APP $(dscp_map 10) >/dev/null
|
||||
lldptool -T -i $swp2 -V APP $(dscp_map 20) >/dev/null
|
||||
lldpad_app_wait_set $swp1
|
||||
lldpad_app_wait_set $swp2
|
||||
}
|
||||
|
||||
switch_destroy()
|
||||
{
|
||||
lldptool -T -i $swp2 -V APP -d $(dscp_map 20) >/dev/null
|
||||
lldptool -T -i $swp1 -V APP -d $(dscp_map 10) >/dev/null
|
||||
lldpad_app_wait_del
|
||||
|
||||
ip link set dev $swp2 nomaster
|
||||
ip link set dev $swp1 nomaster
|
||||
ip link del dev br1
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
h1_create
|
||||
h2_create
|
||||
switch_create
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
switch_destroy
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
ping_ipv4()
|
||||
{
|
||||
ping_test $h1 192.0.2.2
|
||||
}
|
||||
|
||||
dscp_ping_test()
|
||||
{
|
||||
local vrf_name=$1; shift
|
||||
local sip=$1; shift
|
||||
local dip=$1; shift
|
||||
local prio=$1; shift
|
||||
local dev_10=$1; shift
|
||||
local dev_20=$1; shift
|
||||
|
||||
local dscp_10=$(((prio + 10) << 2))
|
||||
local dscp_20=$(((prio + 20) << 2))
|
||||
|
||||
RET=0
|
||||
|
||||
local -A t0s
|
||||
eval "t0s=($(dscp_fetch_stats $dev_10 10)
|
||||
$(dscp_fetch_stats $dev_20 20))"
|
||||
|
||||
ip vrf exec $vrf_name \
|
||||
${PING} -Q $dscp_10 ${sip:+-I $sip} $dip \
|
||||
-c 10 -i 0.1 -w 2 &> /dev/null
|
||||
|
||||
local -A t1s
|
||||
eval "t1s=($(dscp_fetch_stats $dev_10 10)
|
||||
$(dscp_fetch_stats $dev_20 20))"
|
||||
|
||||
for key in ${!t0s[@]}; do
|
||||
local expect
|
||||
if ((key == prio+10 || key == prio+20)); then
|
||||
expect=10
|
||||
else
|
||||
expect=0
|
||||
fi
|
||||
|
||||
local delta=$((t1s[$key] - t0s[$key]))
|
||||
((expect == delta))
|
||||
check_err $? "DSCP $key: Expected to capture $expect packets, got $delta."
|
||||
done
|
||||
|
||||
log_test "DSCP rewrite: $dscp_10-(prio $prio)-$dscp_20"
|
||||
}
|
||||
|
||||
test_dscp()
|
||||
{
|
||||
for prio in {0..7}; do
|
||||
dscp_ping_test v$h1 192.0.2.1 192.0.2.2 $prio $h1 $h2
|
||||
done
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
233
tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh
Executable file
233
tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh
Executable file
@@ -0,0 +1,233 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test for DSCP prioritization in the router.
|
||||
#
|
||||
# With ip_forward_update_priority disabled, the packets are expected to keep
|
||||
# their DSCP (which in this test uses only values 0..7) intact as they are
|
||||
# forwarded by the switch. That is verified at $h2. ICMP responses are formed
|
||||
# with the same DSCP as the requests, and likewise pass through the switch
|
||||
# intact, which is verified at $h1.
|
||||
#
|
||||
# With ip_forward_update_priority enabled, router reprioritizes the packets
|
||||
# according to the table in reprioritize(). Thus, say, DSCP 7 maps to priority
|
||||
# 4, which on egress maps back to DSCP 4. The response packet then gets
|
||||
# reprioritized to 6, getting DSCP 6 on egress.
|
||||
#
|
||||
# +----------------------+ +----------------------+
|
||||
# | H1 | | H2 |
|
||||
# | + $h1 | | $h2 + |
|
||||
# | | 192.0.2.1/28 | | 192.0.2.18/28 | |
|
||||
# +----|-----------------+ +----------------|-----+
|
||||
# | |
|
||||
# +----|----------------------------------------------------------------|-----+
|
||||
# | SW | | |
|
||||
# | + $swp1 $swp2 + |
|
||||
# | 192.0.2.2/28 192.0.2.17/28 |
|
||||
# | APP=0,5,0 .. 7,5,7 APP=0,5,0 .. 7,5,7 |
|
||||
# +---------------------------------------------------------------------------+
|
||||
|
||||
ALL_TESTS="
|
||||
ping_ipv4
|
||||
test_update
|
||||
test_no_update
|
||||
"
|
||||
|
||||
lib_dir=$(dirname $0)/../../../net/forwarding
|
||||
|
||||
NUM_NETIFS=4
|
||||
source $lib_dir/lib.sh
|
||||
|
||||
reprioritize()
|
||||
{
|
||||
local in=$1; shift
|
||||
|
||||
# This is based on rt_tos2priority in include/net/route.h. Assuming 1:1
|
||||
# mapping between priorities and TOS, it yields a new priority for a
|
||||
# packet with ingress priority of $in.
|
||||
local -a reprio=(0 0 2 2 6 6 4 4)
|
||||
|
||||
echo ${reprio[$in]}
|
||||
}
|
||||
|
||||
h1_create()
|
||||
{
|
||||
local dscp;
|
||||
|
||||
simple_if_init $h1 192.0.2.1/28
|
||||
tc qdisc add dev $h1 clsact
|
||||
dscp_capture_install $h1 0
|
||||
ip route add vrf v$h1 192.0.2.16/28 via 192.0.2.2
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip route del vrf v$h1 192.0.2.16/28 via 192.0.2.2
|
||||
dscp_capture_uninstall $h1 0
|
||||
tc qdisc del dev $h1 clsact
|
||||
simple_if_fini $h1 192.0.2.1/28
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.18/28
|
||||
tc qdisc add dev $h2 clsact
|
||||
dscp_capture_install $h2 0
|
||||
ip route add vrf v$h2 192.0.2.0/28 via 192.0.2.17
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
ip route del vrf v$h2 192.0.2.0/28 via 192.0.2.17
|
||||
dscp_capture_uninstall $h2 0
|
||||
tc qdisc del dev $h2 clsact
|
||||
simple_if_fini $h2 192.0.2.18/28
|
||||
}
|
||||
|
||||
dscp_map()
|
||||
{
|
||||
local base=$1; shift
|
||||
|
||||
for prio in {0..7}; do
|
||||
echo app=$prio,5,$((base + prio))
|
||||
done
|
||||
}
|
||||
|
||||
switch_create()
|
||||
{
|
||||
simple_if_init $swp1 192.0.2.2/28
|
||||
__simple_if_init $swp2 v$swp1 192.0.2.17/28
|
||||
|
||||
lldptool -T -i $swp1 -V APP $(dscp_map 0) >/dev/null
|
||||
lldptool -T -i $swp2 -V APP $(dscp_map 0) >/dev/null
|
||||
lldpad_app_wait_set $swp1
|
||||
lldpad_app_wait_set $swp2
|
||||
}
|
||||
|
||||
switch_destroy()
|
||||
{
|
||||
lldptool -T -i $swp2 -V APP -d $(dscp_map 0) >/dev/null
|
||||
lldptool -T -i $swp1 -V APP -d $(dscp_map 0) >/dev/null
|
||||
lldpad_app_wait_del
|
||||
|
||||
__simple_if_fini $swp2 192.0.2.17/28
|
||||
simple_if_fini $swp1 192.0.2.2/28
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
sysctl_set net.ipv4.ip_forward_update_priority 1
|
||||
h1_create
|
||||
h2_create
|
||||
switch_create
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
switch_destroy
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
sysctl_restore net.ipv4.ip_forward_update_priority
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
ping_ipv4()
|
||||
{
|
||||
ping_test $h1 192.0.2.18
|
||||
}
|
||||
|
||||
dscp_ping_test()
|
||||
{
|
||||
local vrf_name=$1; shift
|
||||
local sip=$1; shift
|
||||
local dip=$1; shift
|
||||
local prio=$1; shift
|
||||
local reprio=$1; shift
|
||||
local dev1=$1; shift
|
||||
local dev2=$1; shift
|
||||
|
||||
local prio2=$($reprio $prio) # ICMP Request egress prio
|
||||
local prio3=$($reprio $prio2) # ICMP Response egress prio
|
||||
|
||||
local dscp=$((prio << 2)) # ICMP Request ingress DSCP
|
||||
local dscp2=$((prio2 << 2)) # ICMP Request egress DSCP
|
||||
local dscp3=$((prio3 << 2)) # ICMP Response egress DSCP
|
||||
|
||||
RET=0
|
||||
|
||||
eval "local -A dev1_t0s=($(dscp_fetch_stats $dev1 0))"
|
||||
eval "local -A dev2_t0s=($(dscp_fetch_stats $dev2 0))"
|
||||
|
||||
ip vrf exec $vrf_name \
|
||||
${PING} -Q $dscp ${sip:+-I $sip} $dip \
|
||||
-c 10 -i 0.1 -w 2 &> /dev/null
|
||||
|
||||
eval "local -A dev1_t1s=($(dscp_fetch_stats $dev1 0))"
|
||||
eval "local -A dev2_t1s=($(dscp_fetch_stats $dev2 0))"
|
||||
|
||||
for i in {0..7}; do
|
||||
local dscpi=$((i << 2))
|
||||
local expect2=0
|
||||
local expect3=0
|
||||
|
||||
if ((i == prio2)); then
|
||||
expect2=10
|
||||
fi
|
||||
if ((i == prio3)); then
|
||||
expect3=10
|
||||
fi
|
||||
|
||||
local delta=$((dev2_t1s[$i] - dev2_t0s[$i]))
|
||||
((expect2 == delta))
|
||||
check_err $? "DSCP $dscpi@$dev2: Expected to capture $expect2 packets, got $delta."
|
||||
|
||||
delta=$((dev1_t1s[$i] - dev1_t0s[$i]))
|
||||
((expect3 == delta))
|
||||
check_err $? "DSCP $dscpi@$dev1: Expected to capture $expect3 packets, got $delta."
|
||||
done
|
||||
|
||||
log_test "DSCP rewrite: $dscp-(prio $prio2)-$dscp2-(prio $prio3)-$dscp3"
|
||||
}
|
||||
|
||||
__test_update()
|
||||
{
|
||||
local update=$1; shift
|
||||
local reprio=$1; shift
|
||||
|
||||
sysctl_restore net.ipv4.ip_forward_update_priority
|
||||
sysctl_set net.ipv4.ip_forward_update_priority $update
|
||||
|
||||
for prio in {0..7}; do
|
||||
dscp_ping_test v$h1 192.0.2.1 192.0.2.18 $prio $reprio $h1 $h2
|
||||
done
|
||||
}
|
||||
|
||||
test_update()
|
||||
{
|
||||
__test_update 1 reprioritize
|
||||
}
|
||||
|
||||
test_no_update()
|
||||
{
|
||||
__test_update 0 echo
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
167
tools/testing/selftests/drivers/net/mlxsw/router_scale.sh
Normal file
167
tools/testing/selftests/drivers/net/mlxsw/router_scale.sh
Normal file
@@ -0,0 +1,167 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ROUTER_NUM_NETIFS=4
|
||||
|
||||
router_h1_create()
|
||||
{
|
||||
simple_if_init $h1 192.0.1.1/24
|
||||
ip route add 193.0.0.0/8 via 192.0.1.2 dev $h1
|
||||
}
|
||||
|
||||
router_h1_destroy()
|
||||
{
|
||||
ip route del 193.0.0.0/8 via 192.0.1.2 dev $h1
|
||||
simple_if_fini $h1 192.0.1.1/24
|
||||
}
|
||||
|
||||
router_h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.1/24
|
||||
tc qdisc add dev $h2 handle ffff: ingress
|
||||
}
|
||||
|
||||
router_h2_destroy()
|
||||
{
|
||||
tc qdisc del dev $h2 handle ffff: ingress
|
||||
simple_if_fini $h2 192.0.2.1/24
|
||||
}
|
||||
|
||||
router_create()
|
||||
{
|
||||
ip link set dev $rp1 up
|
||||
ip link set dev $rp2 up
|
||||
|
||||
ip address add 192.0.1.2/24 dev $rp1
|
||||
ip address add 192.0.2.2/24 dev $rp2
|
||||
}
|
||||
|
||||
router_destroy()
|
||||
{
|
||||
ip address del 192.0.2.2/24 dev $rp2
|
||||
ip address del 192.0.1.2/24 dev $rp1
|
||||
|
||||
ip link set dev $rp2 down
|
||||
ip link set dev $rp1 down
|
||||
}
|
||||
|
||||
router_setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
rp1=${NETIFS[p2]}
|
||||
|
||||
rp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
h1mac=$(mac_get $h1)
|
||||
rp1mac=$(mac_get $rp1)
|
||||
|
||||
vrf_prepare
|
||||
|
||||
router_h1_create
|
||||
router_h2_create
|
||||
|
||||
router_create
|
||||
}
|
||||
|
||||
router_offload_validate()
|
||||
{
|
||||
local route_count=$1
|
||||
local offloaded_count
|
||||
|
||||
offloaded_count=$(ip route | grep -o 'offload' | wc -l)
|
||||
[[ $offloaded_count -ge $route_count ]]
|
||||
}
|
||||
|
||||
router_routes_create()
|
||||
{
|
||||
local route_count=$1
|
||||
local count=0
|
||||
|
||||
ROUTE_FILE="$(mktemp)"
|
||||
|
||||
for i in {0..255}
|
||||
do
|
||||
for j in {0..255}
|
||||
do
|
||||
for k in {0..255}
|
||||
do
|
||||
if [[ $count -eq $route_count ]]; then
|
||||
break 3
|
||||
fi
|
||||
|
||||
echo route add 193.${i}.${j}.${k}/32 via \
|
||||
192.0.2.1 dev $rp2 >> $ROUTE_FILE
|
||||
((count++))
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
ip -b $ROUTE_FILE &> /dev/null
|
||||
}
|
||||
|
||||
router_routes_destroy()
|
||||
{
|
||||
if [[ -v ROUTE_FILE ]]; then
|
||||
rm -f $ROUTE_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
router_test()
|
||||
{
|
||||
local route_count=$1
|
||||
local should_fail=$2
|
||||
local count=0
|
||||
|
||||
RET=0
|
||||
|
||||
router_routes_create $route_count
|
||||
|
||||
router_offload_validate $route_count
|
||||
check_err_fail $should_fail $? "Offload of $route_count routes"
|
||||
if [[ $RET -ne 0 ]] || [[ $should_fail -eq 1 ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 flower \
|
||||
skip_sw dst_ip 193.0.0.0/8 action drop
|
||||
|
||||
for i in {0..255}
|
||||
do
|
||||
for j in {0..255}
|
||||
do
|
||||
for k in {0..255}
|
||||
do
|
||||
if [[ $count -eq $route_count ]]; then
|
||||
break 3
|
||||
fi
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $rp1mac \
|
||||
-A 192.0.1.1 -B 193.${i}.${j}.${k} \
|
||||
-t ip -q
|
||||
((count++))
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 1 $route_count
|
||||
check_err $? "Offload mismatch"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 flower \
|
||||
skip_sw dst_ip 193.0.0.0/8 action drop
|
||||
|
||||
router_routes_destroy
|
||||
}
|
||||
|
||||
router_cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
router_routes_destroy
|
||||
router_destroy
|
||||
|
||||
router_h2_destroy
|
||||
router_h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
}
|
366
tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh
Executable file
366
tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh
Executable file
@@ -0,0 +1,366 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# This test is for checking the A-TCAM and C-TCAM operation in Spectrum-2.
|
||||
# It tries to exercise as many code paths in the eRP state machine as
|
||||
# possible.
|
||||
|
||||
lib_dir=$(dirname $0)/../../../../net/forwarding
|
||||
|
||||
ALL_TESTS="single_mask_test identical_filters_test two_masks_test \
|
||||
multiple_masks_test ctcam_edge_cases_test"
|
||||
NUM_NETIFS=2
|
||||
source $lib_dir/tc_common.sh
|
||||
source $lib_dir/lib.sh
|
||||
|
||||
tcflags="skip_hw"
|
||||
|
||||
h1_create()
|
||||
{
|
||||
simple_if_init $h1 192.0.2.1/24 198.51.100.1/24
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.2/24 198.51.100.2/24
|
||||
tc qdisc add dev $h2 clsact
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
tc qdisc del dev $h2 clsact
|
||||
simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24
|
||||
}
|
||||
|
||||
single_mask_test()
|
||||
{
|
||||
# When only a single mask is required, the device uses the master
|
||||
# mask and not the eRP table. Verify that under this mode the right
|
||||
# filter is matched
|
||||
|
||||
RET=0
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 101 1
|
||||
check_err $? "Single filter - did not match"
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
|
||||
$tcflags dst_ip 198.51.100.2 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 101 2
|
||||
check_err $? "Two filters - did not match highest priority"
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 102 1
|
||||
check_err $? "Two filters - did not match lowest priority"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 102 2
|
||||
check_err $? "Single filter - did not match after delete"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
|
||||
|
||||
log_test "single mask test ($tcflags)"
|
||||
}
|
||||
|
||||
identical_filters_test()
|
||||
{
|
||||
# When two filters that only differ in their priority are used,
|
||||
# one needs to be inserted into the C-TCAM. This test verifies
|
||||
# that filters are correctly spilled to C-TCAM and that the right
|
||||
# filter is matched
|
||||
|
||||
RET=0
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 101 1
|
||||
check_err $? "Did not match A-TCAM filter"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 102 1
|
||||
check_err $? "Did not match C-TCAM filter after A-TCAM delete"
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 102 2
|
||||
check_err $? "Did not match C-TCAM filter after A-TCAM add"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 103 1
|
||||
check_err $? "Did not match A-TCAM filter after C-TCAM delete"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
|
||||
|
||||
log_test "identical filters test ($tcflags)"
|
||||
}
|
||||
|
||||
two_masks_test()
|
||||
{
|
||||
# When more than one mask is required, the eRP table is used. This
|
||||
# test verifies that the eRP table is correctly allocated and used
|
||||
|
||||
RET=0
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
|
||||
$tcflags dst_ip 192.0.0.0/16 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 101 1
|
||||
check_err $? "Two filters - did not match highest priority"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 103 1
|
||||
check_err $? "Single filter - did not match"
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
|
||||
$tcflags dst_ip 192.0.2.0/24 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 102 1
|
||||
check_err $? "Two filters - did not match highest priority after add"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
|
||||
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
|
||||
|
||||
log_test "two masks test ($tcflags)"
|
||||
}
|
||||
|
||||
multiple_masks_test()
|
||||
{
|
||||
# The number of masks in a region is limited. Once the maximum
|
||||
# number of masks has been reached filters that require new
|
||||
# masks are spilled to the C-TCAM. This test verifies that
|
||||
# spillage is performed correctly and that the right filter is
|
||||
# matched
|
||||
|
||||
local index
|
||||
|
||||
RET=0
|
||||
|
||||
NUM_MASKS=32
|
||||
BASE_INDEX=100
|
||||
|
||||
for i in $(eval echo {1..$NUM_MASKS}); do
|
||||
index=$((BASE_INDEX - i))
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref $index \
|
||||
handle $index \
|
||||
flower $tcflags dst_ip 192.0.2.2/${i} src_ip 192.0.2.1 \
|
||||
action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
|
||||
-B 192.0.2.2 -t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" $index 1
|
||||
check_err $? "$i filters - did not match highest priority (add)"
|
||||
done
|
||||
|
||||
for i in $(eval echo {$NUM_MASKS..1}); do
|
||||
index=$((BASE_INDEX - i))
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
|
||||
-B 192.0.2.2 -t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" $index 2
|
||||
check_err $? "$i filters - did not match highest priority (del)"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref $index \
|
||||
handle $index flower
|
||||
done
|
||||
|
||||
log_test "multiple masks test ($tcflags)"
|
||||
}
|
||||
|
||||
ctcam_two_atcam_masks_test()
|
||||
{
|
||||
RET=0
|
||||
|
||||
# First case: C-TCAM is disabled when there are two A-TCAM masks.
|
||||
# We push a filter into the C-TCAM by using two identical filters
|
||||
# as in identical_filters_test()
|
||||
|
||||
# Filter goes into A-TCAM
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
# Filter goes into C-TCAM
|
||||
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
# Filter goes into A-TCAM
|
||||
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
|
||||
$tcflags dst_ip 192.0.2.0/24 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 101 1
|
||||
check_err $? "Did not match A-TCAM filter"
|
||||
|
||||
# Delete both A-TCAM and C-TCAM filters and make sure the remaining
|
||||
# A-TCAM filter still works
|
||||
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 103 1
|
||||
check_err $? "Did not match A-TCAM filter"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
|
||||
|
||||
log_test "ctcam with two atcam masks test ($tcflags)"
|
||||
}
|
||||
|
||||
ctcam_one_atcam_mask_test()
|
||||
{
|
||||
RET=0
|
||||
|
||||
# Second case: C-TCAM is disabled when there is one A-TCAM mask.
|
||||
# The test is similar to identical_filters_test()
|
||||
|
||||
# Filter goes into A-TCAM
|
||||
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
# Filter goes into C-TCAM
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 101 1
|
||||
check_err $? "Did not match C-TCAM filter"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
|
||||
|
||||
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
||||
-t ip -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 102 1
|
||||
check_err $? "Did not match A-TCAM filter"
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
|
||||
|
||||
log_test "ctcam with one atcam mask test ($tcflags)"
|
||||
}
|
||||
|
||||
ctcam_no_atcam_masks_test()
|
||||
{
|
||||
RET=0
|
||||
|
||||
# Third case: C-TCAM is disabled when there are no A-TCAM masks
|
||||
# This test exercises the code path that transitions the eRP table
|
||||
# to its initial state after deleting the last C-TCAM mask
|
||||
|
||||
# Filter goes into A-TCAM
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
# Filter goes into C-TCAM
|
||||
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
|
||||
$tcflags dst_ip 192.0.2.2 action drop
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
|
||||
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
|
||||
|
||||
log_test "ctcam with no atcam masks test ($tcflags)"
|
||||
}
|
||||
|
||||
ctcam_edge_cases_test()
|
||||
{
|
||||
# When the C-TCAM is disabled after deleting the last C-TCAM
|
||||
# mask, we want to make sure the eRP state machine is put in
|
||||
# the correct state
|
||||
|
||||
ctcam_two_atcam_masks_test
|
||||
ctcam_one_atcam_mask_test
|
||||
ctcam_no_atcam_masks_test
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
h2=${NETIFS[p2]}
|
||||
h1mac=$(mac_get $h1)
|
||||
h2mac=$(mac_get $h2)
|
||||
|
||||
vrf_prepare
|
||||
|
||||
h1_create
|
||||
h2_create
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
if ! tc_offload_check; then
|
||||
check_err 1 "Could not test offloaded functionality"
|
||||
log_test "mlxsw-specific tests for tc flower"
|
||||
exit
|
||||
else
|
||||
tcflags="skip_sw"
|
||||
tests_run
|
||||
fi
|
||||
|
||||
exit $EXIT_STATUS
|
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source "../../../../net/forwarding/devlink_lib.sh"
|
||||
|
||||
if [ "$DEVLINK_VIDDID" != "15b3:cb84" ]; then
|
||||
echo "SKIP: test is tailored for Mellanox Spectrum"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Needed for returning to default
|
||||
declare -A KVD_DEFAULTS
|
||||
|
||||
KVD_CHILDREN="linear hash_single hash_double"
|
||||
KVDL_CHILDREN="singles chunks large_chunks"
|
||||
|
||||
devlink_sp_resource_minimize()
|
||||
{
|
||||
local size
|
||||
local i
|
||||
|
||||
for i in $KVD_CHILDREN; do
|
||||
size=$(devlink_resource_get kvd "$i" | jq '.["size_min"]')
|
||||
devlink_resource_size_set "$size" kvd "$i"
|
||||
done
|
||||
|
||||
for i in $KVDL_CHILDREN; do
|
||||
size=$(devlink_resource_get kvd linear "$i" | \
|
||||
jq '.["size_min"]')
|
||||
devlink_resource_size_set "$size" kvd linear "$i"
|
||||
done
|
||||
}
|
||||
|
||||
devlink_sp_size_kvd_to_default()
|
||||
{
|
||||
local need_reload=0
|
||||
local i
|
||||
|
||||
for i in $KVD_CHILDREN; do
|
||||
local size=$(echo "${KVD_DEFAULTS[kvd_$i]}" | jq '.["size"]')
|
||||
current_size=$(devlink_resource_size_get kvd "$i")
|
||||
|
||||
if [ "$size" -ne "$current_size" ]; then
|
||||
devlink_resource_size_set "$size" kvd "$i"
|
||||
need_reload=1
|
||||
fi
|
||||
done
|
||||
|
||||
for i in $KVDL_CHILDREN; do
|
||||
local size=$(echo "${KVD_DEFAULTS[kvd_linear_$i]}" | \
|
||||
jq '.["size"]')
|
||||
current_size=$(devlink_resource_size_get kvd linear "$i")
|
||||
|
||||
if [ "$size" -ne "$current_size" ]; then
|
||||
devlink_resource_size_set "$size" kvd linear "$i"
|
||||
need_reload=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$need_reload" -ne "0" ]; then
|
||||
devlink_reload
|
||||
fi
|
||||
}
|
||||
|
||||
devlink_sp_read_kvd_defaults()
|
||||
{
|
||||
local key
|
||||
local i
|
||||
|
||||
KVD_DEFAULTS[kvd]=$(devlink_resource_get "kvd")
|
||||
for i in $KVD_CHILDREN; do
|
||||
key=kvd_$i
|
||||
KVD_DEFAULTS[$key]=$(devlink_resource_get kvd "$i")
|
||||
done
|
||||
|
||||
for i in $KVDL_CHILDREN; do
|
||||
key=kvd_linear_$i
|
||||
KVD_DEFAULTS[$key]=$(devlink_resource_get kvd linear "$i")
|
||||
done
|
||||
}
|
||||
|
||||
KVD_PROFILES="default scale ipv4_max"
|
||||
|
||||
devlink_sp_resource_kvd_profile_set()
|
||||
{
|
||||
local profile=$1
|
||||
|
||||
case "$profile" in
|
||||
scale)
|
||||
devlink_resource_size_set 64000 kvd linear
|
||||
devlink_resource_size_set 15616 kvd linear singles
|
||||
devlink_resource_size_set 32000 kvd linear chunks
|
||||
devlink_resource_size_set 16384 kvd linear large_chunks
|
||||
devlink_resource_size_set 128000 kvd hash_single
|
||||
devlink_resource_size_set 48000 kvd hash_double
|
||||
devlink_reload
|
||||
;;
|
||||
ipv4_max)
|
||||
devlink_resource_size_set 64000 kvd linear
|
||||
devlink_resource_size_set 15616 kvd linear singles
|
||||
devlink_resource_size_set 32000 kvd linear chunks
|
||||
devlink_resource_size_set 16384 kvd linear large_chunks
|
||||
devlink_resource_size_set 144000 kvd hash_single
|
||||
devlink_resource_size_set 32768 kvd hash_double
|
||||
devlink_reload
|
||||
;;
|
||||
default)
|
||||
devlink_resource_size_set 98304 kvd linear
|
||||
devlink_resource_size_set 16384 kvd linear singles
|
||||
devlink_resource_size_set 49152 kvd linear chunks
|
||||
devlink_resource_size_set 32768 kvd linear large_chunks
|
||||
devlink_resource_size_set 87040 kvd hash_single
|
||||
devlink_resource_size_set 60416 kvd hash_double
|
||||
devlink_reload
|
||||
;;
|
||||
*)
|
||||
check_err 1 "Unknown profile $profile"
|
||||
esac
|
||||
}
|
117
tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh
Executable file
117
tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
NUM_NETIFS=1
|
||||
source devlink_lib_spectrum.sh
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
devlink_sp_read_kvd_defaults
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
devlink_sp_size_kvd_to_default
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
|
||||
profiles_test()
|
||||
{
|
||||
local i
|
||||
|
||||
log_info "Running profile tests"
|
||||
|
||||
for i in $KVD_PROFILES; do
|
||||
RET=0
|
||||
devlink_sp_resource_kvd_profile_set $i
|
||||
log_test "'$i' profile"
|
||||
done
|
||||
|
||||
# Default is explicitly tested at end to ensure it's actually applied
|
||||
RET=0
|
||||
devlink_sp_resource_kvd_profile_set "default"
|
||||
log_test "'default' profile"
|
||||
}
|
||||
|
||||
resources_min_test()
|
||||
{
|
||||
local size
|
||||
local i
|
||||
local j
|
||||
|
||||
log_info "Running KVD-minimum tests"
|
||||
|
||||
for i in $KVD_CHILDREN; do
|
||||
RET=0
|
||||
size=$(devlink_resource_get kvd "$i" | jq '.["size_min"]')
|
||||
devlink_resource_size_set "$size" kvd "$i"
|
||||
|
||||
# In case of linear, need to minimize sub-resources as well
|
||||
if [[ "$i" == "linear" ]]; then
|
||||
for j in $KVDL_CHILDREN; do
|
||||
devlink_resource_size_set 0 kvd linear "$j"
|
||||
done
|
||||
fi
|
||||
|
||||
devlink_reload
|
||||
devlink_sp_size_kvd_to_default
|
||||
log_test "'$i' minimize [$size]"
|
||||
done
|
||||
}
|
||||
|
||||
resources_max_test()
|
||||
{
|
||||
local min_size
|
||||
local size
|
||||
local i
|
||||
local j
|
||||
|
||||
log_info "Running KVD-maximum tests"
|
||||
for i in $KVD_CHILDREN; do
|
||||
RET=0
|
||||
devlink_sp_resource_minimize
|
||||
|
||||
# Calculate the maximum possible size for the given partition
|
||||
size=$(devlink_resource_size_get kvd)
|
||||
for j in $KVD_CHILDREN; do
|
||||
if [ "$i" != "$j" ]; then
|
||||
min_size=$(devlink_resource_get kvd "$j" | \
|
||||
jq '.["size_min"]')
|
||||
size=$((size - min_size))
|
||||
fi
|
||||
done
|
||||
|
||||
# Test almost maximum size
|
||||
devlink_resource_size_set "$((size - 128))" kvd "$i"
|
||||
devlink_reload
|
||||
log_test "'$i' almost maximize [$((size - 128))]"
|
||||
|
||||
# Test above maximum size
|
||||
devlink resource set "$DEVLINK_DEV" \
|
||||
path "kvd/$i" size $((size + 128)) &> /dev/null
|
||||
check_fail $? "Set kvd/$i to size $((size + 128)) should fail"
|
||||
log_test "'$i' Overflow rejection [$((size + 128))]"
|
||||
|
||||
# Test maximum size
|
||||
if [ "$i" == "hash_single" ] || [ "$i" == "hash_double" ]; then
|
||||
echo "SKIP: Observed problem with exact max $i"
|
||||
continue
|
||||
fi
|
||||
|
||||
devlink_resource_size_set "$size" kvd "$i"
|
||||
devlink_reload
|
||||
log_test "'$i' maximize [$size]"
|
||||
|
||||
devlink_sp_size_kvd_to_default
|
||||
done
|
||||
}
|
||||
|
||||
profiles_test
|
||||
resources_min_test
|
||||
resources_max_test
|
||||
|
||||
exit "$RET"
|
@@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
source ../mirror_gre_scale.sh
|
||||
|
||||
mirror_gre_get_target()
|
||||
{
|
||||
local should_fail=$1; shift
|
||||
|
||||
if ((! should_fail)); then
|
||||
echo 3
|
||||
else
|
||||
echo 4
|
||||
fi
|
||||
}
|
55
tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh
Executable file
55
tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
NUM_NETIFS=6
|
||||
source ../../../../net/forwarding/lib.sh
|
||||
source ../../../../net/forwarding/tc_common.sh
|
||||
source devlink_lib_spectrum.sh
|
||||
|
||||
current_test=""
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
if [ ! -z $current_test ]; then
|
||||
${current_test}_cleanup
|
||||
fi
|
||||
devlink_sp_size_kvd_to_default
|
||||
}
|
||||
|
||||
devlink_sp_read_kvd_defaults
|
||||
trap cleanup EXIT
|
||||
|
||||
ALL_TESTS="router tc_flower mirror_gre"
|
||||
for current_test in ${TESTS:-$ALL_TESTS}; do
|
||||
source ${current_test}_scale.sh
|
||||
|
||||
num_netifs_var=${current_test^^}_NUM_NETIFS
|
||||
num_netifs=${!num_netifs_var:-$NUM_NETIFS}
|
||||
|
||||
for profile in $KVD_PROFILES; do
|
||||
RET=0
|
||||
devlink_sp_resource_kvd_profile_set $profile
|
||||
if [[ $RET -gt 0 ]]; then
|
||||
log_test "'$current_test' [$profile] setting"
|
||||
continue
|
||||
fi
|
||||
|
||||
for should_fail in 0 1; do
|
||||
RET=0
|
||||
target=$(${current_test}_get_target "$should_fail")
|
||||
${current_test}_setup_prepare
|
||||
setup_wait $num_netifs
|
||||
${current_test}_test "$target" "$should_fail"
|
||||
${current_test}_cleanup
|
||||
if [[ "$should_fail" -eq 0 ]]; then
|
||||
log_test "'$current_test' [$profile] $target"
|
||||
else
|
||||
log_test "'$current_test' [$profile] overflow $target"
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
current_test=""
|
||||
|
||||
exit "$RET"
|
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
source ../router_scale.sh
|
||||
|
||||
router_get_target()
|
||||
{
|
||||
local should_fail=$1
|
||||
local target
|
||||
|
||||
target=$(devlink_resource_size_get kvd hash_single)
|
||||
|
||||
if [[ $should_fail -eq 0 ]]; then
|
||||
target=$((target * 85 / 100))
|
||||
else
|
||||
target=$((target + 1))
|
||||
fi
|
||||
|
||||
echo $target
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
source ../tc_flower_scale.sh
|
||||
|
||||
tc_flower_get_target()
|
||||
{
|
||||
local should_fail=$1; shift
|
||||
|
||||
# 6144 (6x1024) is the theoretical maximum.
|
||||
# One bank of 512 rules is taken by the 18-byte MC router rule.
|
||||
# One rule is the ACL catch-all.
|
||||
# 6144 - 512 - 1 = 5631
|
||||
local target=5631
|
||||
|
||||
if ((! should_fail)); then
|
||||
echo $target
|
||||
else
|
||||
echo $((target + 1))
|
||||
fi
|
||||
}
|
134
tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh
Normal file
134
tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test for resource limit of offloaded flower rules. The test adds a given
|
||||
# number of flower matches for different IPv6 addresses, then generates traffic,
|
||||
# and ensures each was hit exactly once. This file contains functions to set up
|
||||
# a testing topology and run the test, and is meant to be sourced from a test
|
||||
# script that calls the testing routine with a given number of rules.
|
||||
|
||||
TC_FLOWER_NUM_NETIFS=2
|
||||
|
||||
tc_flower_h1_create()
|
||||
{
|
||||
simple_if_init $h1
|
||||
tc qdisc add dev $h1 clsact
|
||||
}
|
||||
|
||||
tc_flower_h1_destroy()
|
||||
{
|
||||
tc qdisc del dev $h1 clsact
|
||||
simple_if_fini $h1
|
||||
}
|
||||
|
||||
tc_flower_h2_create()
|
||||
{
|
||||
simple_if_init $h2
|
||||
tc qdisc add dev $h2 clsact
|
||||
}
|
||||
|
||||
tc_flower_h2_destroy()
|
||||
{
|
||||
tc qdisc del dev $h2 clsact
|
||||
simple_if_fini $h2
|
||||
}
|
||||
|
||||
tc_flower_setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
h2=${NETIFS[p2]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
tc_flower_h1_create
|
||||
tc_flower_h2_create
|
||||
}
|
||||
|
||||
tc_flower_cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
tc_flower_h2_destroy
|
||||
tc_flower_h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
|
||||
if [[ -v TC_FLOWER_BATCH_FILE ]]; then
|
||||
rm -f $TC_FLOWER_BATCH_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
tc_flower_addr()
|
||||
{
|
||||
local num=$1; shift
|
||||
|
||||
printf "2001:db8:1::%x" $num
|
||||
}
|
||||
|
||||
tc_flower_rules_create()
|
||||
{
|
||||
local count=$1; shift
|
||||
local should_fail=$1; shift
|
||||
|
||||
TC_FLOWER_BATCH_FILE="$(mktemp)"
|
||||
|
||||
for ((i = 0; i < count; ++i)); do
|
||||
cat >> $TC_FLOWER_BATCH_FILE <<-EOF
|
||||
filter add dev $h2 ingress \
|
||||
prot ipv6 \
|
||||
pref 1000 \
|
||||
flower $tcflags dst_ip $(tc_flower_addr $i) \
|
||||
action drop
|
||||
EOF
|
||||
done
|
||||
|
||||
tc -b $TC_FLOWER_BATCH_FILE
|
||||
check_err_fail $should_fail $? "Rule insertion"
|
||||
}
|
||||
|
||||
__tc_flower_test()
|
||||
{
|
||||
local count=$1; shift
|
||||
local should_fail=$1; shift
|
||||
local last=$((count - 1))
|
||||
|
||||
tc_flower_rules_create $count $should_fail
|
||||
|
||||
for ((i = 0; i < count; ++i)); do
|
||||
$MZ $h1 -q -c 1 -t ip -p 20 -b bc -6 \
|
||||
-A 2001:db8:2::1 \
|
||||
-B $(tc_flower_addr $i)
|
||||
done
|
||||
|
||||
MISMATCHES=$(
|
||||
tc -j -s filter show dev $h2 ingress |
|
||||
jq -r '[ .[] | select(.kind == "flower") | .options |
|
||||
values as $rule | .actions[].stats.packets |
|
||||
select(. != 1) | "\(.) on \($rule.keys.dst_ip)" ] |
|
||||
join(", ")'
|
||||
)
|
||||
|
||||
test -z "$MISMATCHES"
|
||||
check_err $? "Expected to capture 1 packet for each IP, but got $MISMATCHES"
|
||||
}
|
||||
|
||||
tc_flower_test()
|
||||
{
|
||||
local count=$1; shift
|
||||
local should_fail=$1; shift
|
||||
|
||||
# We use lower 16 bits of IPv6 address for match. Also there are only 16
|
||||
# bits of rule priority space.
|
||||
if ((count > 65536)); then
|
||||
check_err 1 "Invalid count of $count. At most 65536 rules supported"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! tc_offload_check $TC_FLOWER_NUM_NETIFS; then
|
||||
check_err 1 "Could not test offloaded functionality"
|
||||
return
|
||||
fi
|
||||
|
||||
tcflags="skip_sw"
|
||||
__tc_flower_test $count $should_fail
|
||||
}
|
1
tools/testing/selftests/net/.gitignore
vendored
1
tools/testing/selftests/net/.gitignore
vendored
@@ -13,3 +13,4 @@ udpgso
|
||||
udpgso_bench_rx
|
||||
udpgso_bench_tx
|
||||
tcp_inq
|
||||
tls
|
||||
|
@@ -13,7 +13,7 @@ TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy
|
||||
TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd
|
||||
TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx
|
||||
TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
|
||||
TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict
|
||||
TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls
|
||||
|
||||
include ../lib.mk
|
||||
|
||||
|
@@ -46,6 +46,8 @@ Guidelines for Writing Tests
|
||||
|
||||
o Where possible, reuse an existing topology for different tests instead
|
||||
of recreating the same topology.
|
||||
o Tests that use anything but the most trivial topologies should include
|
||||
an ASCII art showing the topology.
|
||||
o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and
|
||||
RFC 5737, respectively.
|
||||
o Where possible, tests shall be written so that they can be reused by
|
||||
|
151
tools/testing/selftests/net/forwarding/bridge_port_isolation.sh
Executable file
151
tools/testing/selftests/net/forwarding/bridge_port_isolation.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ALL_TESTS="ping_ipv4 ping_ipv6 flooding"
|
||||
NUM_NETIFS=6
|
||||
CHECK_TC="yes"
|
||||
source lib.sh
|
||||
|
||||
h1_create()
|
||||
{
|
||||
simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
|
||||
}
|
||||
|
||||
h3_create()
|
||||
{
|
||||
simple_if_init $h3 192.0.2.3/24 2001:db8:1::3/64
|
||||
}
|
||||
|
||||
h3_destroy()
|
||||
{
|
||||
simple_if_fini $h3 192.0.2.3/24 2001:db8:1::3/64
|
||||
}
|
||||
|
||||
switch_create()
|
||||
{
|
||||
ip link add dev br0 type bridge
|
||||
|
||||
ip link set dev $swp1 master br0
|
||||
ip link set dev $swp2 master br0
|
||||
ip link set dev $swp3 master br0
|
||||
|
||||
ip link set dev $swp1 type bridge_slave isolated on
|
||||
check_err $? "Can't set isolation on port $swp1"
|
||||
ip link set dev $swp2 type bridge_slave isolated on
|
||||
check_err $? "Can't set isolation on port $swp2"
|
||||
ip link set dev $swp3 type bridge_slave isolated off
|
||||
check_err $? "Can't disable isolation on port $swp3"
|
||||
|
||||
ip link set dev br0 up
|
||||
ip link set dev $swp1 up
|
||||
ip link set dev $swp2 up
|
||||
ip link set dev $swp3 up
|
||||
}
|
||||
|
||||
switch_destroy()
|
||||
{
|
||||
ip link set dev $swp3 down
|
||||
ip link set dev $swp2 down
|
||||
ip link set dev $swp1 down
|
||||
|
||||
ip link del dev br0
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
swp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
h1_create
|
||||
h2_create
|
||||
h3_create
|
||||
|
||||
switch_create
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
switch_destroy
|
||||
|
||||
h3_destroy
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
ping_ipv4()
|
||||
{
|
||||
RET=0
|
||||
ping_do $h1 192.0.2.2
|
||||
check_fail $? "Ping worked when it should not have"
|
||||
|
||||
RET=0
|
||||
ping_do $h3 192.0.2.2
|
||||
check_err $? "Ping didn't work when it should have"
|
||||
|
||||
log_test "Isolated port ping"
|
||||
}
|
||||
|
||||
ping_ipv6()
|
||||
{
|
||||
RET=0
|
||||
ping6_do $h1 2001:db8:1::2
|
||||
check_fail $? "Ping6 worked when it should not have"
|
||||
|
||||
RET=0
|
||||
ping6_do $h3 2001:db8:1::2
|
||||
check_err $? "Ping6 didn't work when it should have"
|
||||
|
||||
log_test "Isolated port ping6"
|
||||
}
|
||||
|
||||
flooding()
|
||||
{
|
||||
local mac=de:ad:be:ef:13:37
|
||||
local ip=192.0.2.100
|
||||
|
||||
RET=0
|
||||
flood_test_do false $mac $ip $h1 $h2
|
||||
check_err $? "Packet was flooded when it should not have been"
|
||||
|
||||
RET=0
|
||||
flood_test_do true $mac $ip $h3 $h2
|
||||
check_err $? "Packet was not flooded when it should have been"
|
||||
|
||||
log_test "Isolated port flooding"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
108
tools/testing/selftests/net/forwarding/devlink_lib.sh
Normal file
108
tools/testing/selftests/net/forwarding/devlink_lib.sh
Normal file
@@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
##############################################################################
|
||||
# Source library
|
||||
|
||||
relative_path="${BASH_SOURCE%/*}"
|
||||
if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
|
||||
relative_path="."
|
||||
fi
|
||||
|
||||
source "$relative_path/lib.sh"
|
||||
|
||||
##############################################################################
|
||||
# Defines
|
||||
|
||||
DEVLINK_DEV=$(devlink port show | grep "${NETIFS[p1]}" | \
|
||||
grep -v "${NETIFS[p1]}[0-9]" | cut -d" " -f1 | \
|
||||
rev | cut -d"/" -f2- | rev)
|
||||
if [ -z "$DEVLINK_DEV" ]; then
|
||||
echo "SKIP: ${NETIFS[p1]} has no devlink device registered for it"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$(echo $DEVLINK_DEV | grep -c pci)" -eq 0 ]]; then
|
||||
echo "SKIP: devlink device's bus is not PCI"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEVLINK_VIDDID=$(lspci -s $(echo $DEVLINK_DEV | cut -d"/" -f2) \
|
||||
-n | cut -d" " -f3)
|
||||
|
||||
##############################################################################
|
||||
# Sanity checks
|
||||
|
||||
devlink -j resource show "$DEVLINK_DEV" &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: iproute2 too old, missing devlink resource support"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##############################################################################
|
||||
# Devlink helpers
|
||||
|
||||
devlink_resource_names_to_path()
|
||||
{
|
||||
local resource
|
||||
local path=""
|
||||
|
||||
for resource in "${@}"; do
|
||||
if [ "$path" == "" ]; then
|
||||
path="$resource"
|
||||
else
|
||||
path="${path}/$resource"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "$path"
|
||||
}
|
||||
|
||||
devlink_resource_get()
|
||||
{
|
||||
local name=$1
|
||||
local resource_name=.[][\"$DEVLINK_DEV\"]
|
||||
|
||||
resource_name="$resource_name | .[] | select (.name == \"$name\")"
|
||||
|
||||
shift
|
||||
for resource in "${@}"; do
|
||||
resource_name="${resource_name} | .[\"resources\"][] | \
|
||||
select (.name == \"$resource\")"
|
||||
done
|
||||
|
||||
devlink -j resource show "$DEVLINK_DEV" | jq "$resource_name"
|
||||
}
|
||||
|
||||
devlink_resource_size_get()
|
||||
{
|
||||
local size=$(devlink_resource_get "$@" | jq '.["size_new"]')
|
||||
|
||||
if [ "$size" == "null" ]; then
|
||||
devlink_resource_get "$@" | jq '.["size"]'
|
||||
else
|
||||
echo "$size"
|
||||
fi
|
||||
}
|
||||
|
||||
devlink_resource_size_set()
|
||||
{
|
||||
local new_size=$1
|
||||
local path
|
||||
|
||||
shift
|
||||
path=$(devlink_resource_names_to_path "$@")
|
||||
devlink resource set "$DEVLINK_DEV" path "$path" size "$new_size"
|
||||
check_err $? "Failed setting path $path to size $size"
|
||||
}
|
||||
|
||||
devlink_reload()
|
||||
{
|
||||
local still_pending
|
||||
|
||||
devlink dev reload "$DEVLINK_DEV" &> /dev/null
|
||||
check_err $? "Failed reload"
|
||||
|
||||
still_pending=$(devlink resource show "$DEVLINK_DEV" | \
|
||||
grep -c "size_new")
|
||||
check_err $still_pending "Failed reload - There are still unset sizes"
|
||||
}
|
253
tools/testing/selftests/net/forwarding/gre_multipath.sh
Executable file
253
tools/testing/selftests/net/forwarding/gre_multipath.sh
Executable file
@@ -0,0 +1,253 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test traffic distribution when a wECMP route forwards traffic to two GRE
|
||||
# tunnels.
|
||||
#
|
||||
# +-------------------------+
|
||||
# | H1 |
|
||||
# | $h1 + |
|
||||
# | 192.0.2.1/28 | |
|
||||
# +-------------------|-----+
|
||||
# |
|
||||
# +-------------------|------------------------+
|
||||
# | SW1 | |
|
||||
# | $ol1 + |
|
||||
# | 192.0.2.2/28 |
|
||||
# | |
|
||||
# | + g1a (gre) + g1b (gre) |
|
||||
# | loc=192.0.2.65 loc=192.0.2.81 |
|
||||
# | rem=192.0.2.66 --. rem=192.0.2.82 --. |
|
||||
# | tos=inherit | tos=inherit | |
|
||||
# | .------------------' | |
|
||||
# | | .------------------' |
|
||||
# | v v |
|
||||
# | + $ul1.111 (vlan) + $ul1.222 (vlan) |
|
||||
# | | 192.0.2.129/28 | 192.0.2.145/28 |
|
||||
# | \ / |
|
||||
# | \________________/ |
|
||||
# | | |
|
||||
# | + $ul1 |
|
||||
# +------------|-------------------------------+
|
||||
# |
|
||||
# +------------|-------------------------------+
|
||||
# | SW2 + $ul2 |
|
||||
# | _______|________ |
|
||||
# | / \ |
|
||||
# | / \ |
|
||||
# | + $ul2.111 (vlan) + $ul2.222 (vlan) |
|
||||
# | ^ 192.0.2.130/28 ^ 192.0.2.146/28 |
|
||||
# | | | |
|
||||
# | | '------------------. |
|
||||
# | '------------------. | |
|
||||
# | + g2a (gre) | + g2b (gre) | |
|
||||
# | loc=192.0.2.66 | loc=192.0.2.82 | |
|
||||
# | rem=192.0.2.65 --' rem=192.0.2.81 --' |
|
||||
# | tos=inherit tos=inherit |
|
||||
# | |
|
||||
# | $ol2 + |
|
||||
# | 192.0.2.17/28 | |
|
||||
# +-------------------|------------------------+
|
||||
# |
|
||||
# +-------------------|-----+
|
||||
# | H2 | |
|
||||
# | $h2 + |
|
||||
# | 192.0.2.18/28 |
|
||||
# +-------------------------+
|
||||
|
||||
ALL_TESTS="
|
||||
ping_ipv4
|
||||
multipath_ipv4
|
||||
"
|
||||
|
||||
NUM_NETIFS=6
|
||||
source lib.sh
|
||||
|
||||
h1_create()
|
||||
{
|
||||
simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
|
||||
ip route add vrf v$h1 192.0.2.16/28 via 192.0.2.2
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip route del vrf v$h1 192.0.2.16/28 via 192.0.2.2
|
||||
simple_if_fini $h1 192.0.2.1/28
|
||||
}
|
||||
|
||||
sw1_create()
|
||||
{
|
||||
simple_if_init $ol1 192.0.2.2/28
|
||||
__simple_if_init $ul1 v$ol1
|
||||
vlan_create $ul1 111 v$ol1 192.0.2.129/28
|
||||
vlan_create $ul1 222 v$ol1 192.0.2.145/28
|
||||
|
||||
tunnel_create g1a gre 192.0.2.65 192.0.2.66 tos inherit dev v$ol1
|
||||
__simple_if_init g1a v$ol1 192.0.2.65/32
|
||||
ip route add vrf v$ol1 192.0.2.66/32 via 192.0.2.130
|
||||
|
||||
tunnel_create g1b gre 192.0.2.81 192.0.2.82 tos inherit dev v$ol1
|
||||
__simple_if_init g1b v$ol1 192.0.2.81/32
|
||||
ip route add vrf v$ol1 192.0.2.82/32 via 192.0.2.146
|
||||
|
||||
ip route add vrf v$ol1 192.0.2.16/28 \
|
||||
nexthop dev g1a \
|
||||
nexthop dev g1b
|
||||
|
||||
tc qdisc add dev $ul1 clsact
|
||||
tc filter add dev $ul1 egress pref 111 prot ipv4 \
|
||||
flower dst_ip 192.0.2.66 action pass
|
||||
tc filter add dev $ul1 egress pref 222 prot ipv4 \
|
||||
flower dst_ip 192.0.2.82 action pass
|
||||
}
|
||||
|
||||
sw1_destroy()
|
||||
{
|
||||
tc qdisc del dev $ul1 clsact
|
||||
|
||||
ip route del vrf v$ol1 192.0.2.16/28
|
||||
|
||||
ip route del vrf v$ol1 192.0.2.82/32 via 192.0.2.146
|
||||
__simple_if_fini g1b 192.0.2.81/32
|
||||
tunnel_destroy g1b
|
||||
|
||||
ip route del vrf v$ol1 192.0.2.66/32 via 192.0.2.130
|
||||
__simple_if_fini g1a 192.0.2.65/32
|
||||
tunnel_destroy g1a
|
||||
|
||||
vlan_destroy $ul1 222
|
||||
vlan_destroy $ul1 111
|
||||
__simple_if_fini $ul1
|
||||
simple_if_fini $ol1 192.0.2.2/28
|
||||
}
|
||||
|
||||
sw2_create()
|
||||
{
|
||||
simple_if_init $ol2 192.0.2.17/28
|
||||
__simple_if_init $ul2 v$ol2
|
||||
vlan_create $ul2 111 v$ol2 192.0.2.130/28
|
||||
vlan_create $ul2 222 v$ol2 192.0.2.146/28
|
||||
|
||||
tunnel_create g2a gre 192.0.2.66 192.0.2.65 tos inherit dev v$ol2
|
||||
__simple_if_init g2a v$ol2 192.0.2.66/32
|
||||
ip route add vrf v$ol2 192.0.2.65/32 via 192.0.2.129
|
||||
|
||||
tunnel_create g2b gre 192.0.2.82 192.0.2.81 tos inherit dev v$ol2
|
||||
__simple_if_init g2b v$ol2 192.0.2.82/32
|
||||
ip route add vrf v$ol2 192.0.2.81/32 via 192.0.2.145
|
||||
|
||||
ip route add vrf v$ol2 192.0.2.0/28 \
|
||||
nexthop dev g2a \
|
||||
nexthop dev g2b
|
||||
}
|
||||
|
||||
sw2_destroy()
|
||||
{
|
||||
ip route del vrf v$ol2 192.0.2.0/28
|
||||
|
||||
ip route del vrf v$ol2 192.0.2.81/32 via 192.0.2.145
|
||||
__simple_if_fini g2b 192.0.2.82/32
|
||||
tunnel_destroy g2b
|
||||
|
||||
ip route del vrf v$ol2 192.0.2.65/32 via 192.0.2.129
|
||||
__simple_if_fini g2a 192.0.2.66/32
|
||||
tunnel_destroy g2a
|
||||
|
||||
vlan_destroy $ul2 222
|
||||
vlan_destroy $ul2 111
|
||||
__simple_if_fini $ul2
|
||||
simple_if_fini $ol2 192.0.2.17/28
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.18/28
|
||||
ip route add vrf v$h2 192.0.2.0/28 via 192.0.2.17
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
ip route del vrf v$h2 192.0.2.0/28 via 192.0.2.17
|
||||
simple_if_fini $h2 192.0.2.18/28
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
ol1=${NETIFS[p2]}
|
||||
|
||||
ul1=${NETIFS[p3]}
|
||||
ul2=${NETIFS[p4]}
|
||||
|
||||
ol2=${NETIFS[p5]}
|
||||
h2=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
h1_create
|
||||
sw1_create
|
||||
sw2_create
|
||||
h2_create
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
h2_destroy
|
||||
sw2_destroy
|
||||
sw1_destroy
|
||||
h1_destroy
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
multipath4_test()
|
||||
{
|
||||
local what=$1; shift
|
||||
local weight1=$1; shift
|
||||
local weight2=$1; shift
|
||||
|
||||
sysctl_set net.ipv4.fib_multipath_hash_policy 1
|
||||
ip route replace vrf v$ol1 192.0.2.16/28 \
|
||||
nexthop dev g1a weight $weight1 \
|
||||
nexthop dev g1b weight $weight2
|
||||
|
||||
local t0_111=$(tc_rule_stats_get $ul1 111 egress)
|
||||
local t0_222=$(tc_rule_stats_get $ul1 222 egress)
|
||||
|
||||
ip vrf exec v$h1 \
|
||||
$MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \
|
||||
-d 1msec -t udp "sp=1024,dp=0-32768"
|
||||
|
||||
local t1_111=$(tc_rule_stats_get $ul1 111 egress)
|
||||
local t1_222=$(tc_rule_stats_get $ul1 222 egress)
|
||||
|
||||
local d111=$((t1_111 - t0_111))
|
||||
local d222=$((t1_222 - t0_222))
|
||||
multipath_eval "$what" $weight1 $weight2 $d111 $d222
|
||||
|
||||
ip route replace vrf v$ol1 192.0.2.16/28 \
|
||||
nexthop dev g1a \
|
||||
nexthop dev g1b
|
||||
sysctl_restore net.ipv4.fib_multipath_hash_policy
|
||||
}
|
||||
|
||||
ping_ipv4()
|
||||
{
|
||||
ping_test $h1 192.0.2.18
|
||||
}
|
||||
|
||||
multipath_ipv4()
|
||||
{
|
||||
log_info "Running IPv4 multipath tests"
|
||||
multipath4_test "ECMP" 1 1
|
||||
multipath4_test "Weighted MP 2:1" 2 1
|
||||
multipath4_test "Weighted MP 11:45" 11 45
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
@@ -8,14 +8,21 @@
|
||||
PING=${PING:=ping}
|
||||
PING6=${PING6:=ping6}
|
||||
MZ=${MZ:=mausezahn}
|
||||
ARPING=${ARPING:=arping}
|
||||
TEAMD=${TEAMD:=teamd}
|
||||
WAIT_TIME=${WAIT_TIME:=5}
|
||||
PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
|
||||
PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no}
|
||||
NETIF_TYPE=${NETIF_TYPE:=veth}
|
||||
NETIF_CREATE=${NETIF_CREATE:=yes}
|
||||
|
||||
if [[ -f forwarding.config ]]; then
|
||||
source forwarding.config
|
||||
relative_path="${BASH_SOURCE%/*}"
|
||||
if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
|
||||
relative_path="."
|
||||
fi
|
||||
|
||||
if [[ -f $relative_path/forwarding.config ]]; then
|
||||
source "$relative_path/forwarding.config"
|
||||
fi
|
||||
|
||||
##############################################################################
|
||||
@@ -28,7 +35,10 @@ check_tc_version()
|
||||
echo "SKIP: iproute2 too old; tc is missing JSON support"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_tc_shblock_support()
|
||||
{
|
||||
tc filter help 2>&1 | grep block &> /dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "SKIP: iproute2 too old; tc is missing shared block support"
|
||||
@@ -36,6 +46,15 @@ check_tc_version()
|
||||
fi
|
||||
}
|
||||
|
||||
check_tc_chain_support()
|
||||
{
|
||||
tc help 2>&1|grep chain &> /dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "SKIP: iproute2 too old; tc is missing chain support"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "SKIP: need root privileges"
|
||||
exit 0
|
||||
@@ -45,15 +64,18 @@ if [[ "$CHECK_TC" = "yes" ]]; then
|
||||
check_tc_version
|
||||
fi
|
||||
|
||||
if [[ ! -x "$(command -v jq)" ]]; then
|
||||
echo "SKIP: jq not installed"
|
||||
exit 1
|
||||
fi
|
||||
require_command()
|
||||
{
|
||||
local cmd=$1; shift
|
||||
|
||||
if [[ ! -x "$(command -v $MZ)" ]]; then
|
||||
echo "SKIP: $MZ not installed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -x "$(command -v "$cmd")" ]]; then
|
||||
echo "SKIP: $cmd not installed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_command jq
|
||||
require_command $MZ
|
||||
|
||||
if [[ ! -v NUM_NETIFS ]]; then
|
||||
echo "SKIP: importer does not define \"NUM_NETIFS\""
|
||||
@@ -151,6 +173,19 @@ check_fail()
|
||||
fi
|
||||
}
|
||||
|
||||
check_err_fail()
|
||||
{
|
||||
local should_fail=$1; shift
|
||||
local err=$1; shift
|
||||
local what=$1; shift
|
||||
|
||||
if ((should_fail)); then
|
||||
check_fail $err "$what succeeded, but should have failed"
|
||||
else
|
||||
check_err $err "$what failed"
|
||||
fi
|
||||
}
|
||||
|
||||
log_test()
|
||||
{
|
||||
local test_name=$1
|
||||
@@ -185,24 +220,54 @@ log_info()
|
||||
echo "INFO: $msg"
|
||||
}
|
||||
|
||||
setup_wait_dev()
|
||||
{
|
||||
local dev=$1; shift
|
||||
|
||||
while true; do
|
||||
ip link show dev $dev up \
|
||||
| grep 'state UP' &> /dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
sleep 1
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
setup_wait()
|
||||
{
|
||||
for i in $(eval echo {1..$NUM_NETIFS}); do
|
||||
while true; do
|
||||
ip link show dev ${NETIFS[p$i]} up \
|
||||
| grep 'state UP' &> /dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
sleep 1
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
local num_netifs=${1:-$NUM_NETIFS}
|
||||
|
||||
for ((i = 1; i <= num_netifs; ++i)); do
|
||||
setup_wait_dev ${NETIFS[p$i]}
|
||||
done
|
||||
|
||||
# Make sure links are ready.
|
||||
sleep $WAIT_TIME
|
||||
}
|
||||
|
||||
lldpad_app_wait_set()
|
||||
{
|
||||
local dev=$1; shift
|
||||
|
||||
while lldptool -t -i $dev -V APP -c app | grep -q pending; do
|
||||
echo "$dev: waiting for lldpad to push pending APP updates"
|
||||
sleep 5
|
||||
done
|
||||
}
|
||||
|
||||
lldpad_app_wait_del()
|
||||
{
|
||||
# Give lldpad a chance to push down the changes. If the device is downed
|
||||
# too soon, the updates will be left pending. However, they will have
|
||||
# been struck off the lldpad's DB already, so we won't be able to tell
|
||||
# they are pending. Then on next test iteration this would cause
|
||||
# weirdness as newly-added APP rules conflict with the old ones,
|
||||
# sometimes getting stuck in an "unknown" state.
|
||||
sleep 5
|
||||
}
|
||||
|
||||
pre_cleanup()
|
||||
{
|
||||
if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
|
||||
@@ -287,6 +352,29 @@ __addr_add_del()
|
||||
done
|
||||
}
|
||||
|
||||
__simple_if_init()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local vrf_name=$1; shift
|
||||
local addrs=("${@}")
|
||||
|
||||
ip link set dev $if_name master $vrf_name
|
||||
ip link set dev $if_name up
|
||||
|
||||
__addr_add_del $if_name add "${addrs[@]}"
|
||||
}
|
||||
|
||||
__simple_if_fini()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local addrs=("${@}")
|
||||
|
||||
__addr_add_del $if_name del "${addrs[@]}"
|
||||
|
||||
ip link set dev $if_name down
|
||||
ip link set dev $if_name nomaster
|
||||
}
|
||||
|
||||
simple_if_init()
|
||||
{
|
||||
local if_name=$1
|
||||
@@ -298,11 +386,8 @@ simple_if_init()
|
||||
array=("${@}")
|
||||
|
||||
vrf_create $vrf_name
|
||||
ip link set dev $if_name master $vrf_name
|
||||
ip link set dev $vrf_name up
|
||||
ip link set dev $if_name up
|
||||
|
||||
__addr_add_del $if_name add "${array[@]}"
|
||||
__simple_if_init $if_name $vrf_name "${array[@]}"
|
||||
}
|
||||
|
||||
simple_if_fini()
|
||||
@@ -315,9 +400,7 @@ simple_if_fini()
|
||||
vrf_name=v$if_name
|
||||
array=("${@}")
|
||||
|
||||
__addr_add_del $if_name del "${array[@]}"
|
||||
|
||||
ip link set dev $if_name down
|
||||
__simple_if_fini $if_name "${array[@]}"
|
||||
vrf_destroy $vrf_name
|
||||
}
|
||||
|
||||
@@ -365,6 +448,28 @@ vlan_destroy()
|
||||
ip link del dev $name
|
||||
}
|
||||
|
||||
team_create()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local mode=$1; shift
|
||||
|
||||
require_command $TEAMD
|
||||
$TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
|
||||
for slave in "$@"; do
|
||||
ip link set dev $slave down
|
||||
ip link set dev $slave master $if_name
|
||||
ip link set dev $slave up
|
||||
done
|
||||
ip link set dev $if_name up
|
||||
}
|
||||
|
||||
team_destroy()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
|
||||
$TEAMD -t $if_name -k
|
||||
}
|
||||
|
||||
master_name_get()
|
||||
{
|
||||
local if_name=$1
|
||||
@@ -383,9 +488,10 @@ tc_rule_stats_get()
|
||||
{
|
||||
local dev=$1; shift
|
||||
local pref=$1; shift
|
||||
local dir=$1; shift
|
||||
|
||||
tc -j -s filter show dev $dev ingress pref $pref |
|
||||
jq '.[1].options.actions[].stats.packets'
|
||||
tc -j -s filter show dev $dev ${dir:-ingress} pref $pref \
|
||||
| jq '.[1].options.actions[].stats.packets'
|
||||
}
|
||||
|
||||
mac_get()
|
||||
@@ -437,7 +543,9 @@ forwarding_restore()
|
||||
|
||||
tc_offload_check()
|
||||
{
|
||||
for i in $(eval echo {1..$NUM_NETIFS}); do
|
||||
local num_netifs=${1:-$NUM_NETIFS}
|
||||
|
||||
for ((i = 1; i <= num_netifs; ++i)); do
|
||||
ethtool -k ${NETIFS[p$i]} \
|
||||
| grep "hw-tc-offload: on" &> /dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
@@ -453,9 +561,15 @@ trap_install()
|
||||
local dev=$1; shift
|
||||
local direction=$1; shift
|
||||
|
||||
# For slow-path testing, we need to install a trap to get to
|
||||
# slow path the packets that would otherwise be switched in HW.
|
||||
tc filter add dev $dev $direction pref 1 flower skip_sw action trap
|
||||
# Some devices may not support or need in-hardware trapping of traffic
|
||||
# (e.g. the veth pairs that this library creates for non-existent
|
||||
# loopbacks). Use continue instead, so that there is a filter in there
|
||||
# (some tests check counters), and so that other filters are still
|
||||
# processed.
|
||||
tc filter add dev $dev $direction pref 1 \
|
||||
flower skip_sw action trap 2>/dev/null \
|
||||
|| tc filter add dev $dev $direction pref 1 \
|
||||
flower action continue
|
||||
}
|
||||
|
||||
trap_uninstall()
|
||||
@@ -463,11 +577,13 @@ trap_uninstall()
|
||||
local dev=$1; shift
|
||||
local direction=$1; shift
|
||||
|
||||
tc filter del dev $dev $direction pref 1 flower skip_sw
|
||||
tc filter del dev $dev $direction pref 1 flower
|
||||
}
|
||||
|
||||
slow_path_trap_install()
|
||||
{
|
||||
# For slow-path testing, we need to install a trap to get to
|
||||
# slow path the packets that would otherwise be switched in HW.
|
||||
if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
|
||||
trap_install "$@"
|
||||
fi
|
||||
@@ -537,6 +653,48 @@ vlan_capture_uninstall()
|
||||
__vlan_capture_add_del del 100 "$@"
|
||||
}
|
||||
|
||||
__dscp_capture_add_del()
|
||||
{
|
||||
local add_del=$1; shift
|
||||
local dev=$1; shift
|
||||
local base=$1; shift
|
||||
local dscp;
|
||||
|
||||
for prio in {0..7}; do
|
||||
dscp=$((base + prio))
|
||||
__icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
|
||||
"skip_hw ip_tos $((dscp << 2))"
|
||||
done
|
||||
}
|
||||
|
||||
dscp_capture_install()
|
||||
{
|
||||
local dev=$1; shift
|
||||
local base=$1; shift
|
||||
|
||||
__dscp_capture_add_del add $dev $base
|
||||
}
|
||||
|
||||
dscp_capture_uninstall()
|
||||
{
|
||||
local dev=$1; shift
|
||||
local base=$1; shift
|
||||
|
||||
__dscp_capture_add_del del $dev $base
|
||||
}
|
||||
|
||||
dscp_fetch_stats()
|
||||
{
|
||||
local dev=$1; shift
|
||||
local base=$1; shift
|
||||
|
||||
for prio in {0..7}; do
|
||||
local dscp=$((base + prio))
|
||||
local t=$(tc_rule_stats_get $dev $((dscp + 100)))
|
||||
echo "[$dscp]=$t "
|
||||
done
|
||||
}
|
||||
|
||||
matchall_sink_create()
|
||||
{
|
||||
local dev=$1; shift
|
||||
@@ -557,33 +715,86 @@ tests_run()
|
||||
done
|
||||
}
|
||||
|
||||
multipath_eval()
|
||||
{
|
||||
local desc="$1"
|
||||
local weight_rp12=$2
|
||||
local weight_rp13=$3
|
||||
local packets_rp12=$4
|
||||
local packets_rp13=$5
|
||||
local weights_ratio packets_ratio diff
|
||||
|
||||
RET=0
|
||||
|
||||
if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
|
||||
weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
|
||||
| bc -l)
|
||||
else
|
||||
weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
|
||||
| bc -l)
|
||||
fi
|
||||
|
||||
if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
|
||||
check_err 1 "Packet difference is 0"
|
||||
log_test "Multipath"
|
||||
log_info "Expected ratio $weights_ratio"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
|
||||
packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
|
||||
| bc -l)
|
||||
else
|
||||
packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
|
||||
| bc -l)
|
||||
fi
|
||||
|
||||
diff=$(echo $weights_ratio - $packets_ratio | bc -l)
|
||||
diff=${diff#-}
|
||||
|
||||
test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
|
||||
check_err $? "Too large discrepancy between expected and measured ratios"
|
||||
log_test "$desc"
|
||||
log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# Tests
|
||||
|
||||
ping_test()
|
||||
ping_do()
|
||||
{
|
||||
local if_name=$1
|
||||
local dip=$2
|
||||
local vrf_name
|
||||
|
||||
RET=0
|
||||
|
||||
vrf_name=$(master_name_get $if_name)
|
||||
ip vrf exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev/null
|
||||
}
|
||||
|
||||
ping_test()
|
||||
{
|
||||
RET=0
|
||||
|
||||
ping_do $1 $2
|
||||
check_err $?
|
||||
log_test "ping"
|
||||
}
|
||||
|
||||
ping6_test()
|
||||
ping6_do()
|
||||
{
|
||||
local if_name=$1
|
||||
local dip=$2
|
||||
local vrf_name
|
||||
|
||||
RET=0
|
||||
|
||||
vrf_name=$(master_name_get $if_name)
|
||||
ip vrf exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev/null
|
||||
}
|
||||
|
||||
ping6_test()
|
||||
{
|
||||
RET=0
|
||||
|
||||
ping6_do $1 $2
|
||||
check_err $?
|
||||
log_test "ping6"
|
||||
}
|
||||
|
132
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh
Executable file
132
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test for "tc action mirred egress mirror" when the underlay route points at a
|
||||
# bridge device without vlan filtering (802.1d).
|
||||
#
|
||||
# This test uses standard topology for testing mirror-to-gretap. See
|
||||
# mirror_gre_topo_lib.sh for more details. The full topology is as follows:
|
||||
#
|
||||
# +---------------------+ +---------------------+
|
||||
# | H1 | | H2 |
|
||||
# | + $h1 | | $h2 + |
|
||||
# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
|
||||
# +-----|---------------+ +---------------|-----+
|
||||
# | |
|
||||
# +-----|-------------------------------------------------------------|-----+
|
||||
# | SW o---> mirror | |
|
||||
# | +---|-------------------------------------------------------------|---+ |
|
||||
# | | + $swp1 + br1 (802.1q bridge) $swp2 + | |
|
||||
# | +---------------------------------------------------------------------+ |
|
||||
# | |
|
||||
# | +---------------------------------------------------------------------+ |
|
||||
# | | + br2 (802.1d bridge) | |
|
||||
# | | 192.0.2.129/28 | |
|
||||
# | | + $swp3 2001:db8:2::1/64 | |
|
||||
# | +---|-----------------------------------------------------------------+ |
|
||||
# | | ^ ^ |
|
||||
# | | + gt6 (ip6gretap) | + gt4 (gretap) | |
|
||||
# | | : loc=2001:db8:2::1 | : loc=192.0.2.129 | |
|
||||
# | | : rem=2001:db8:2::2 -+ : rem=192.0.2.130 -+ |
|
||||
# | | : ttl=100 : ttl=100 |
|
||||
# | | : tos=inherit : tos=inherit |
|
||||
# +-----|---------------------:----------------------:----------------------+
|
||||
# | : :
|
||||
# +-----|---------------------:----------------------:----------------------+
|
||||
# | H3 + $h3 + h3-gt6(ip6gretap) + h3-gt4 (gretap) |
|
||||
# | 192.0.2.130/28 loc=2001:db8:2::2 loc=192.0.2.130 |
|
||||
# | 2001:db8:2::2/64 rem=2001:db8:2::1 rem=192.0.2.129 |
|
||||
# | ttl=100 ttl=100 |
|
||||
# | tos=inherit tos=inherit |
|
||||
# +-------------------------------------------------------------------------+
|
||||
|
||||
ALL_TESTS="
|
||||
test_gretap
|
||||
test_ip6gretap
|
||||
"
|
||||
|
||||
NUM_NETIFS=6
|
||||
source lib.sh
|
||||
source mirror_lib.sh
|
||||
source mirror_gre_lib.sh
|
||||
source mirror_gre_topo_lib.sh
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
swp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
mirror_gre_topo_create
|
||||
|
||||
ip link add name br2 type bridge vlan_filtering 0
|
||||
ip link set dev br2 up
|
||||
|
||||
ip link set dev $swp3 master br2
|
||||
ip route add 192.0.2.130/32 dev br2
|
||||
ip -6 route add 2001:db8:2::2/128 dev br2
|
||||
|
||||
ip address add dev br2 192.0.2.129/28
|
||||
ip address add dev br2 2001:db8:2::1/64
|
||||
|
||||
ip address add dev $h3 192.0.2.130/28
|
||||
ip address add dev $h3 2001:db8:2::2/64
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
ip address del dev $h3 2001:db8:2::2/64
|
||||
ip address del dev $h3 192.0.2.130/28
|
||||
ip link del dev br2
|
||||
|
||||
mirror_gre_topo_destroy
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
test_gretap()
|
||||
{
|
||||
full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
|
||||
full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
|
||||
}
|
||||
|
||||
test_ip6gretap()
|
||||
{
|
||||
full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
|
||||
full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
|
||||
}
|
||||
|
||||
test_all()
|
||||
{
|
||||
slow_path_trap_install $swp1 ingress
|
||||
slow_path_trap_install $swp1 egress
|
||||
|
||||
tests_run
|
||||
|
||||
slow_path_trap_uninstall $swp1 egress
|
||||
slow_path_trap_uninstall $swp1 ingress
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tcflags="skip_hw"
|
||||
test_all
|
||||
|
||||
if ! tc_offload_check; then
|
||||
echo "WARN: Could not test offloaded functionality"
|
||||
else
|
||||
tcflags="skip_sw"
|
||||
test_all
|
||||
fi
|
||||
|
||||
exit $EXIT_STATUS
|
@@ -74,12 +74,14 @@ test_vlan_match()
|
||||
|
||||
test_gretap()
|
||||
{
|
||||
test_vlan_match gt4 'vlan_id 555 vlan_ethtype ip' "mirror to gretap"
|
||||
test_vlan_match gt4 'skip_hw vlan_id 555 vlan_ethtype ip' \
|
||||
"mirror to gretap"
|
||||
}
|
||||
|
||||
test_ip6gretap()
|
||||
{
|
||||
test_vlan_match gt6 'vlan_id 555 vlan_ethtype ipv6' "mirror to ip6gretap"
|
||||
test_vlan_match gt6 'skip_hw vlan_id 555 vlan_ethtype ip' \
|
||||
"mirror to ip6gretap"
|
||||
}
|
||||
|
||||
test_gretap_stp()
|
||||
|
126
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh
Executable file
126
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test for "tc action mirred egress mirror" when the underlay route points at a
|
||||
# bridge device with vlan filtering (802.1q).
|
||||
#
|
||||
# This test uses standard topology for testing mirror-to-gretap. See
|
||||
# mirror_gre_topo_lib.sh for more details. The full topology is as follows:
|
||||
#
|
||||
# +---------------------+ +---------------------+
|
||||
# | H1 | | H2 |
|
||||
# | + $h1 | | $h2 + |
|
||||
# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
|
||||
# +-----|---------------+ +---------------|-----+
|
||||
# | |
|
||||
# +-----|---------------------------------------------------------------|-----+
|
||||
# | SW o---> mirror | |
|
||||
# | +---|---------------------------------------------------------------|---+ |
|
||||
# | | + $swp1 + br1 (802.1q bridge) $swp2 + | |
|
||||
# | | 192.0.2.129/28 | |
|
||||
# | | + $swp3 2001:db8:2::1/64 | |
|
||||
# | | | vid555 vid555[pvid,untagged] | |
|
||||
# | +---|-------------------------------------------------------------------+ |
|
||||
# | | ^ ^ |
|
||||
# | | + gt6 (ip6gretap) | + gt4 (gretap) | |
|
||||
# | | : loc=2001:db8:2::1 | : loc=192.0.2.129 | |
|
||||
# | | : rem=2001:db8:2::2 -+ : rem=192.0.2.130 -+ |
|
||||
# | | : ttl=100 : ttl=100 |
|
||||
# | | : tos=inherit : tos=inherit |
|
||||
# +-----|---------------------:------------------------:----------------------+
|
||||
# | : :
|
||||
# +-----|---------------------:------------------------:----------------------+
|
||||
# | H3 + $h3 + h3-gt6(ip6gretap) + h3-gt4 (gretap) |
|
||||
# | | loc=2001:db8:2::2 loc=192.0.2.130 |
|
||||
# | + $h3.555 rem=2001:db8:2::1 rem=192.0.2.129 |
|
||||
# | 192.0.2.130/28 ttl=100 ttl=100 |
|
||||
# | 2001:db8:2::2/64 tos=inherit tos=inherit |
|
||||
# +---------------------------------------------------------------------------+
|
||||
|
||||
ALL_TESTS="
|
||||
test_gretap
|
||||
test_ip6gretap
|
||||
"
|
||||
|
||||
NUM_NETIFS=6
|
||||
source lib.sh
|
||||
source mirror_lib.sh
|
||||
source mirror_gre_lib.sh
|
||||
source mirror_gre_topo_lib.sh
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
swp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
mirror_gre_topo_create
|
||||
|
||||
ip link set dev $swp3 master br1
|
||||
bridge vlan add dev br1 vid 555 pvid untagged self
|
||||
ip address add dev br1 192.0.2.129/28
|
||||
ip address add dev br1 2001:db8:2::1/64
|
||||
|
||||
ip -4 route add 192.0.2.130/32 dev br1
|
||||
ip -6 route add 2001:db8:2::2/128 dev br1
|
||||
|
||||
vlan_create $h3 555 v$h3 192.0.2.130/28 2001:db8:2::2/64
|
||||
bridge vlan add dev $swp3 vid 555
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
ip link set dev $swp3 nomaster
|
||||
vlan_destroy $h3 555
|
||||
|
||||
mirror_gre_topo_destroy
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
test_gretap()
|
||||
{
|
||||
full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
|
||||
full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
|
||||
}
|
||||
|
||||
test_ip6gretap()
|
||||
{
|
||||
full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
|
||||
full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
|
||||
}
|
||||
|
||||
tests()
|
||||
{
|
||||
slow_path_trap_install $swp1 ingress
|
||||
slow_path_trap_install $swp1 egress
|
||||
|
||||
tests_run
|
||||
|
||||
slow_path_trap_uninstall $swp1 egress
|
||||
slow_path_trap_uninstall $swp1 ingress
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tcflags="skip_hw"
|
||||
tests
|
||||
|
||||
if ! tc_offload_check; then
|
||||
echo "WARN: Could not test offloaded functionality"
|
||||
else
|
||||
tcflags="skip_sw"
|
||||
tests
|
||||
fi
|
||||
|
||||
exit $EXIT_STATUS
|
283
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
Executable file
283
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
Executable file
@@ -0,0 +1,283 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test for "tc action mirred egress mirror" when the underlay route points at a
|
||||
# bridge device with vlan filtering (802.1q), and the egress device is a team
|
||||
# device.
|
||||
#
|
||||
# +----------------------+ +----------------------+
|
||||
# | H1 | | H2 |
|
||||
# | + $h1.333 | | $h1.555 + |
|
||||
# | | 192.0.2.1/28 | | 192.0.2.18/28 | |
|
||||
# +-----|----------------+ +----------------|-----+
|
||||
# | $h1 |
|
||||
# +--------------------------------+------------------------------+
|
||||
# |
|
||||
# +--------------------------------------|------------------------------------+
|
||||
# | SW o---> mirror |
|
||||
# | | |
|
||||
# | +--------------------------------+------------------------------+ |
|
||||
# | | $swp1 | |
|
||||
# | + $swp1.333 $swp1.555 + |
|
||||
# | 192.0.2.2/28 192.0.2.17/28 |
|
||||
# | |
|
||||
# | +-----------------------------------------------------------------------+ |
|
||||
# | | BR1 (802.1q) | |
|
||||
# | | + lag (team) 192.0.2.129/28 | |
|
||||
# | | / \ 2001:db8:2::1/64 | |
|
||||
# | +---/---\---------------------------------------------------------------+ |
|
||||
# | / \ ^ |
|
||||
# | | \ + gt4 (gretap) | |
|
||||
# | | \ loc=192.0.2.129 | |
|
||||
# | | \ rem=192.0.2.130 -+ |
|
||||
# | | \ ttl=100 |
|
||||
# | | \ tos=inherit |
|
||||
# | | \ |
|
||||
# | | \_________________________________ |
|
||||
# | | \ |
|
||||
# | + $swp3 + $swp4 |
|
||||
# +---|------------------------------------------------|----------------------+
|
||||
# | |
|
||||
# +---|----------------------+ +---|----------------------+
|
||||
# | + $h3 H3 | | + $h4 H4 |
|
||||
# | 192.0.2.130/28 | | 192.0.2.130/28 |
|
||||
# | 2001:db8:2::2/64 | | 2001:db8:2::2/64 |
|
||||
# +--------------------------+ +--------------------------+
|
||||
|
||||
ALL_TESTS="
|
||||
test_mirror_gretap_first
|
||||
test_mirror_gretap_second
|
||||
"
|
||||
|
||||
NUM_NETIFS=6
|
||||
source lib.sh
|
||||
source mirror_lib.sh
|
||||
source mirror_gre_lib.sh
|
||||
|
||||
require_command $ARPING
|
||||
|
||||
vlan_host_create()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local vid=$1; shift
|
||||
local vrf_name=$1; shift
|
||||
local ips=("${@}")
|
||||
|
||||
vrf_create $vrf_name
|
||||
ip link set dev $vrf_name up
|
||||
vlan_create $if_name $vid $vrf_name "${ips[@]}"
|
||||
}
|
||||
|
||||
vlan_host_destroy()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local vid=$1; shift
|
||||
local vrf_name=$1; shift
|
||||
|
||||
vlan_destroy $if_name $vid
|
||||
ip link set dev $vrf_name down
|
||||
vrf_destroy $vrf_name
|
||||
}
|
||||
|
||||
h1_create()
|
||||
{
|
||||
vlan_host_create $h1 333 vrf-h1 192.0.2.1/28
|
||||
ip -4 route add 192.0.2.16/28 vrf vrf-h1 nexthop via 192.0.2.2
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip -4 route del 192.0.2.16/28 vrf vrf-h1
|
||||
vlan_host_destroy $h1 333 vrf-h1
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
vlan_host_create $h1 555 vrf-h2 192.0.2.18/28
|
||||
ip -4 route add 192.0.2.0/28 vrf vrf-h2 nexthop via 192.0.2.17
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
ip -4 route del 192.0.2.0/28 vrf vrf-h2
|
||||
vlan_host_destroy $h1 555 vrf-h2
|
||||
}
|
||||
|
||||
h3_create()
|
||||
{
|
||||
simple_if_init $h3 192.0.2.130/28
|
||||
tc qdisc add dev $h3 clsact
|
||||
}
|
||||
|
||||
h3_destroy()
|
||||
{
|
||||
tc qdisc del dev $h3 clsact
|
||||
simple_if_fini $h3 192.0.2.130/28
|
||||
}
|
||||
|
||||
h4_create()
|
||||
{
|
||||
simple_if_init $h4 192.0.2.130/28
|
||||
tc qdisc add dev $h4 clsact
|
||||
}
|
||||
|
||||
h4_destroy()
|
||||
{
|
||||
tc qdisc del dev $h4 clsact
|
||||
simple_if_fini $h4 192.0.2.130/28
|
||||
}
|
||||
|
||||
switch_create()
|
||||
{
|
||||
ip link set dev $swp1 up
|
||||
tc qdisc add dev $swp1 clsact
|
||||
vlan_create $swp1 333 "" 192.0.2.2/28
|
||||
vlan_create $swp1 555 "" 192.0.2.17/28
|
||||
|
||||
tunnel_create gt4 gretap 192.0.2.129 192.0.2.130 \
|
||||
ttl 100 tos inherit
|
||||
|
||||
ip link set dev $swp3 up
|
||||
ip link set dev $swp4 up
|
||||
|
||||
ip link add name br1 type bridge vlan_filtering 1
|
||||
ip link set dev br1 up
|
||||
__addr_add_del br1 add 192.0.2.129/32
|
||||
ip -4 route add 192.0.2.130/32 dev br1
|
||||
|
||||
team_create lag loadbalance $swp3 $swp4
|
||||
ip link set dev lag master br1
|
||||
}
|
||||
|
||||
switch_destroy()
|
||||
{
|
||||
ip link set dev lag nomaster
|
||||
team_destroy lag
|
||||
|
||||
ip -4 route del 192.0.2.130/32 dev br1
|
||||
__addr_add_del br1 del 192.0.2.129/32
|
||||
ip link set dev br1 down
|
||||
ip link del dev br1
|
||||
|
||||
ip link set dev $swp4 down
|
||||
ip link set dev $swp3 down
|
||||
|
||||
tunnel_destroy gt4
|
||||
|
||||
vlan_destroy $swp1 555
|
||||
vlan_destroy $swp1 333
|
||||
tc qdisc del dev $swp1 clsact
|
||||
ip link set dev $swp1 down
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp3=${NETIFS[p3]}
|
||||
h3=${NETIFS[p4]}
|
||||
|
||||
swp4=${NETIFS[p5]}
|
||||
h4=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
ip link set dev $h1 up
|
||||
h1_create
|
||||
h2_create
|
||||
h3_create
|
||||
h4_create
|
||||
switch_create
|
||||
|
||||
trap_install $h3 ingress
|
||||
trap_install $h4 ingress
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
trap_uninstall $h4 ingress
|
||||
trap_uninstall $h3 ingress
|
||||
|
||||
switch_destroy
|
||||
h4_destroy
|
||||
h3_destroy
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
ip link set dev $h1 down
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
test_lag_slave()
|
||||
{
|
||||
local host_dev=$1; shift
|
||||
local up_dev=$1; shift
|
||||
local down_dev=$1; shift
|
||||
local what=$1; shift
|
||||
|
||||
RET=0
|
||||
|
||||
mirror_install $swp1 ingress gt4 \
|
||||
"proto 802.1q flower vlan_id 333 $tcflags"
|
||||
|
||||
# Test connectivity through $up_dev when $down_dev is set down.
|
||||
ip link set dev $down_dev down
|
||||
setup_wait_dev $up_dev
|
||||
setup_wait_dev $host_dev
|
||||
$ARPING -I br1 192.0.2.130 -qfc 1
|
||||
sleep 2
|
||||
mirror_test vrf-h1 192.0.2.1 192.0.2.18 $host_dev 1 10
|
||||
|
||||
# Test lack of connectivity when both slaves are down.
|
||||
ip link set dev $up_dev down
|
||||
sleep 2
|
||||
mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h3 1 0
|
||||
mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h4 1 0
|
||||
|
||||
ip link set dev $up_dev up
|
||||
ip link set dev $down_dev up
|
||||
mirror_uninstall $swp1 ingress
|
||||
|
||||
log_test "$what ($tcflags)"
|
||||
}
|
||||
|
||||
test_mirror_gretap_first()
|
||||
{
|
||||
test_lag_slave $h3 $swp3 $swp4 "mirror to gretap: LAG first slave"
|
||||
}
|
||||
|
||||
test_mirror_gretap_second()
|
||||
{
|
||||
test_lag_slave $h4 $swp4 $swp3 "mirror to gretap: LAG second slave"
|
||||
}
|
||||
|
||||
test_all()
|
||||
{
|
||||
slow_path_trap_install $swp1 ingress
|
||||
slow_path_trap_install $swp1 egress
|
||||
|
||||
tests_run
|
||||
|
||||
slow_path_trap_uninstall $swp1 egress
|
||||
slow_path_trap_uninstall $swp1 ingress
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tcflags="skip_hw"
|
||||
test_all
|
||||
|
||||
if ! tc_offload_check; then
|
||||
echo "WARN: Could not test offloaded functionality"
|
||||
else
|
||||
tcflags="skip_sw"
|
||||
test_all
|
||||
fi
|
||||
|
||||
exit $EXIT_STATUS
|
@@ -122,15 +122,8 @@ test_span_gre_egress_up()
|
||||
# After setting the device up, wait for neighbor to get resolved so that
|
||||
# we can expect mirroring to work.
|
||||
ip link set dev $swp3 up
|
||||
while true; do
|
||||
ip neigh sh dev $swp3 $remote_ip nud reachable |
|
||||
grep -q ^
|
||||
if [[ $? -ne 0 ]]; then
|
||||
sleep 1
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
setup_wait_dev $swp3
|
||||
ping -c 1 -I $swp3 $remote_ip &>/dev/null
|
||||
|
||||
quick_test_span_gre_dir $tundev ingress
|
||||
mirror_uninstall $swp1 ingress
|
||||
|
285
tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh
Executable file
285
tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh
Executable file
@@ -0,0 +1,285 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Test for "tc action mirred egress mirror" when the underlay route points at a
|
||||
# team device.
|
||||
#
|
||||
# +----------------------+ +----------------------+
|
||||
# | H1 | | H2 |
|
||||
# | + $h1.333 | | $h1.555 + |
|
||||
# | | 192.0.2.1/28 | | 192.0.2.18/28 | |
|
||||
# +----|-----------------+ +----------------|-----+
|
||||
# | $h1 |
|
||||
# +---------------------------------+------------------------------+
|
||||
# |
|
||||
# +--------------------------------------|------------------------------------+
|
||||
# | SW o---> mirror |
|
||||
# | | |
|
||||
# | +----------------------------------+------------------------------+ |
|
||||
# | | $swp1 | |
|
||||
# | + $swp1.333 $swp1.555 + |
|
||||
# | 192.0.2.2/28 192.0.2.17/28 |
|
||||
# | |
|
||||
# | |
|
||||
# | + gt4 (gretap) ,-> + lag1 (team) |
|
||||
# | loc=192.0.2.129 | | 192.0.2.129/28 |
|
||||
# | rem=192.0.2.130 --' | |
|
||||
# | ttl=100 | |
|
||||
# | tos=inherit | |
|
||||
# | _____________________|______________________ |
|
||||
# | / \ |
|
||||
# | / \ |
|
||||
# | + $swp3 + $swp4 |
|
||||
# +---|------------------------------------------------|----------------------+
|
||||
# | |
|
||||
# +---|------------------------------------------------|----------------------+
|
||||
# | + $h3 + $h4 H3 |
|
||||
# | \ / |
|
||||
# | \____________________________________________/ |
|
||||
# | | |
|
||||
# | + lag2 (team) |
|
||||
# | 192.0.2.130/28 |
|
||||
# | |
|
||||
# +---------------------------------------------------------------------------+
|
||||
|
||||
ALL_TESTS="
|
||||
test_mirror_gretap_first
|
||||
test_mirror_gretap_second
|
||||
"
|
||||
|
||||
NUM_NETIFS=6
|
||||
source lib.sh
|
||||
source mirror_lib.sh
|
||||
source mirror_gre_lib.sh
|
||||
|
||||
require_command $ARPING
|
||||
|
||||
vlan_host_create()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local vid=$1; shift
|
||||
local vrf_name=$1; shift
|
||||
local ips=("${@}")
|
||||
|
||||
vrf_create $vrf_name
|
||||
ip link set dev $vrf_name up
|
||||
vlan_create $if_name $vid $vrf_name "${ips[@]}"
|
||||
}
|
||||
|
||||
vlan_host_destroy()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local vid=$1; shift
|
||||
local vrf_name=$1; shift
|
||||
|
||||
vlan_destroy $if_name $vid
|
||||
ip link set dev $vrf_name down
|
||||
vrf_destroy $vrf_name
|
||||
}
|
||||
|
||||
h1_create()
|
||||
{
|
||||
vlan_host_create $h1 333 vrf-h1 192.0.2.1/28
|
||||
ip -4 route add 192.0.2.16/28 vrf vrf-h1 nexthop via 192.0.2.2
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip -4 route del 192.0.2.16/28 vrf vrf-h1
|
||||
vlan_host_destroy $h1 333 vrf-h1
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
vlan_host_create $h1 555 vrf-h2 192.0.2.18/28
|
||||
ip -4 route add 192.0.2.0/28 vrf vrf-h2 nexthop via 192.0.2.17
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
ip -4 route del 192.0.2.0/28 vrf vrf-h2
|
||||
vlan_host_destroy $h1 555 vrf-h2
|
||||
}
|
||||
|
||||
h3_create_team()
|
||||
{
|
||||
team_create lag2 lacp $h3 $h4
|
||||
__simple_if_init lag2 vrf-h3 192.0.2.130/32
|
||||
ip -4 route add vrf vrf-h3 192.0.2.129/32 dev lag2
|
||||
}
|
||||
|
||||
h3_destroy_team()
|
||||
{
|
||||
ip -4 route del vrf vrf-h3 192.0.2.129/32 dev lag2
|
||||
__simple_if_fini lag2 192.0.2.130/32
|
||||
team_destroy lag2
|
||||
|
||||
ip link set dev $h3 down
|
||||
ip link set dev $h4 down
|
||||
}
|
||||
|
||||
h3_create()
|
||||
{
|
||||
vrf_create vrf-h3
|
||||
ip link set dev vrf-h3 up
|
||||
tc qdisc add dev $h3 clsact
|
||||
tc qdisc add dev $h4 clsact
|
||||
h3_create_team
|
||||
}
|
||||
|
||||
h3_destroy()
|
||||
{
|
||||
h3_destroy_team
|
||||
tc qdisc del dev $h4 clsact
|
||||
tc qdisc del dev $h3 clsact
|
||||
ip link set dev vrf-h3 down
|
||||
vrf_destroy vrf-h3
|
||||
}
|
||||
|
||||
switch_create()
|
||||
{
|
||||
ip link set dev $swp1 up
|
||||
tc qdisc add dev $swp1 clsact
|
||||
vlan_create $swp1 333 "" 192.0.2.2/28
|
||||
vlan_create $swp1 555 "" 192.0.2.17/28
|
||||
|
||||
tunnel_create gt4 gretap 192.0.2.129 192.0.2.130 \
|
||||
ttl 100 tos inherit
|
||||
|
||||
ip link set dev $swp3 up
|
||||
ip link set dev $swp4 up
|
||||
team_create lag1 lacp $swp3 $swp4
|
||||
__addr_add_del lag1 add 192.0.2.129/32
|
||||
ip -4 route add 192.0.2.130/32 dev lag1
|
||||
}
|
||||
|
||||
switch_destroy()
|
||||
{
|
||||
ip -4 route del 192.0.2.130/32 dev lag1
|
||||
__addr_add_del lag1 del 192.0.2.129/32
|
||||
team_destroy lag1
|
||||
|
||||
ip link set dev $swp4 down
|
||||
ip link set dev $swp3 down
|
||||
|
||||
tunnel_destroy gt4
|
||||
|
||||
vlan_destroy $swp1 555
|
||||
vlan_destroy $swp1 333
|
||||
tc qdisc del dev $swp1 clsact
|
||||
ip link set dev $swp1 down
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp3=${NETIFS[p3]}
|
||||
h3=${NETIFS[p4]}
|
||||
|
||||
swp4=${NETIFS[p5]}
|
||||
h4=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
ip link set dev $h1 up
|
||||
h1_create
|
||||
h2_create
|
||||
h3_create
|
||||
switch_create
|
||||
|
||||
trap_install $h3 ingress
|
||||
trap_install $h4 ingress
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
trap_uninstall $h4 ingress
|
||||
trap_uninstall $h3 ingress
|
||||
|
||||
switch_destroy
|
||||
h3_destroy
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
ip link set dev $h1 down
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
test_lag_slave()
|
||||
{
|
||||
local up_dev=$1; shift
|
||||
local down_dev=$1; shift
|
||||
local what=$1; shift
|
||||
|
||||
RET=0
|
||||
|
||||
mirror_install $swp1 ingress gt4 \
|
||||
"proto 802.1q flower vlan_id 333 $tcflags"
|
||||
|
||||
# Move $down_dev away from the team. That will prompt change in
|
||||
# txability of the connected device, without changing its upness. The
|
||||
# driver should notice the txability change and move the traffic to the
|
||||
# other slave.
|
||||
ip link set dev $down_dev nomaster
|
||||
sleep 2
|
||||
mirror_test vrf-h1 192.0.2.1 192.0.2.18 $up_dev 1 10
|
||||
|
||||
# Test lack of connectivity when neither slave is txable.
|
||||
ip link set dev $up_dev nomaster
|
||||
sleep 2
|
||||
mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h3 1 0
|
||||
mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h4 1 0
|
||||
mirror_uninstall $swp1 ingress
|
||||
|
||||
# Recreate H3's team device, because mlxsw, which this test is
|
||||
# predominantly mean to test, requires a bottom-up construction and
|
||||
# doesn't allow enslavement to a device that already has an upper.
|
||||
h3_destroy_team
|
||||
h3_create_team
|
||||
# Wait for ${h,swp}{3,4}.
|
||||
setup_wait
|
||||
|
||||
log_test "$what ($tcflags)"
|
||||
}
|
||||
|
||||
test_mirror_gretap_first()
|
||||
{
|
||||
test_lag_slave $h3 $h4 "mirror to gretap: LAG first slave"
|
||||
}
|
||||
|
||||
test_mirror_gretap_second()
|
||||
{
|
||||
test_lag_slave $h4 $h3 "mirror to gretap: LAG second slave"
|
||||
}
|
||||
|
||||
test_all()
|
||||
{
|
||||
slow_path_trap_install $swp1 ingress
|
||||
slow_path_trap_install $swp1 egress
|
||||
|
||||
tests_run
|
||||
|
||||
slow_path_trap_uninstall $swp1 egress
|
||||
slow_path_trap_uninstall $swp1 ingress
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tcflags="skip_hw"
|
||||
test_all
|
||||
|
||||
if ! tc_offload_check; then
|
||||
echo "WARN: Could not test offloaded functionality"
|
||||
else
|
||||
tcflags="skip_sw"
|
||||
test_all
|
||||
fi
|
||||
|
||||
exit $EXIT_STATUS
|
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source mirror_lib.sh
|
||||
source "$relative_path/mirror_lib.sh"
|
||||
|
||||
quick_test_span_gre_dir_ips()
|
||||
{
|
||||
@@ -62,7 +62,7 @@ full_test_span_gre_dir_vlan_ips()
|
||||
"$backward_type" "$ip1" "$ip2"
|
||||
|
||||
tc filter add dev $h3 ingress pref 77 prot 802.1q \
|
||||
flower $vlan_match ip_proto 0x2f \
|
||||
flower $vlan_match \
|
||||
action pass
|
||||
mirror_test v$h1 $ip1 $ip2 $h3 77 10
|
||||
tc filter del dev $h3 ingress pref 77
|
||||
|
@@ -35,6 +35,8 @@ setup_prepare()
|
||||
vrf_prepare
|
||||
mirror_gre_topo_create
|
||||
|
||||
sysctl_set net.ipv4.conf.v$h3.rp_filter 0
|
||||
|
||||
ip address add dev $swp3 192.0.2.161/28
|
||||
ip address add dev $h3 192.0.2.162/28
|
||||
ip address add dev gt4 192.0.2.129/32
|
||||
@@ -61,6 +63,8 @@ cleanup()
|
||||
ip address del dev $h3 192.0.2.162/28
|
||||
ip address del dev $swp3 192.0.2.161/28
|
||||
|
||||
sysctl_restore net.ipv4.conf.v$h3.rp_filter 0
|
||||
|
||||
mirror_gre_topo_destroy
|
||||
vrf_cleanup
|
||||
|
||||
|
@@ -33,7 +33,7 @@
|
||||
# | |
|
||||
# +-------------------------------------------------------------------------+
|
||||
|
||||
source mirror_topo_lib.sh
|
||||
source "$relative_path/mirror_topo_lib.sh"
|
||||
|
||||
mirror_gre_topo_h3_create()
|
||||
{
|
||||
|
@@ -28,6 +28,8 @@ source mirror_lib.sh
|
||||
source mirror_gre_lib.sh
|
||||
source mirror_gre_topo_lib.sh
|
||||
|
||||
require_command $ARPING
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
@@ -39,6 +41,12 @@ setup_prepare()
|
||||
swp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
# gt4's remote address is at $h3.555, not $h3. Thus the packets arriving
|
||||
# directly to $h3 for test_gretap_untagged_egress() are rejected by
|
||||
# rp_filter and the test spuriously fails.
|
||||
sysctl_set net.ipv4.conf.all.rp_filter 0
|
||||
sysctl_set net.ipv4.conf.$h3.rp_filter 0
|
||||
|
||||
vrf_prepare
|
||||
mirror_gre_topo_create
|
||||
|
||||
@@ -65,6 +73,9 @@ cleanup()
|
||||
|
||||
mirror_gre_topo_destroy
|
||||
vrf_cleanup
|
||||
|
||||
sysctl_restore net.ipv4.conf.$h3.rp_filter
|
||||
sysctl_restore net.ipv4.conf.all.rp_filter
|
||||
}
|
||||
|
||||
test_vlan_match()
|
||||
@@ -79,12 +90,14 @@ test_vlan_match()
|
||||
|
||||
test_gretap()
|
||||
{
|
||||
test_vlan_match gt4 'vlan_id 555 vlan_ethtype ip' "mirror to gretap"
|
||||
test_vlan_match gt4 'skip_hw vlan_id 555 vlan_ethtype ip' \
|
||||
"mirror to gretap"
|
||||
}
|
||||
|
||||
test_ip6gretap()
|
||||
{
|
||||
test_vlan_match gt6 'vlan_id 555 vlan_ethtype ipv6' "mirror to ip6gretap"
|
||||
test_vlan_match gt6 'skip_hw vlan_id 555 vlan_ethtype ip' \
|
||||
"mirror to ip6gretap"
|
||||
}
|
||||
|
||||
test_span_gre_forbidden_cpu()
|
||||
@@ -138,7 +151,7 @@ test_span_gre_forbidden_egress()
|
||||
|
||||
bridge vlan add dev $swp3 vid 555
|
||||
# Re-prime FDB
|
||||
arping -I br1.555 192.0.2.130 -fqc 1
|
||||
$ARPING -I br1.555 192.0.2.130 -fqc 1
|
||||
sleep 1
|
||||
quick_test_span_gre_dir $tundev ingress
|
||||
|
||||
@@ -212,7 +225,7 @@ test_span_gre_fdb_roaming()
|
||||
|
||||
bridge fdb del dev $swp2 $h3mac vlan 555 master
|
||||
# Re-prime FDB
|
||||
arping -I br1.555 192.0.2.130 -fqc 1
|
||||
$ARPING -I br1.555 192.0.2.130 -fqc 1
|
||||
sleep 1
|
||||
quick_test_span_gre_dir $tundev ingress
|
||||
|
||||
|
@@ -105,7 +105,7 @@ do_test_span_vlan_dir_ips()
|
||||
# Install the capture as skip_hw to avoid double-counting of packets.
|
||||
# The traffic is meant for local box anyway, so will be trapped to
|
||||
# kernel.
|
||||
vlan_capture_install $dev "skip_hw vlan_id $vid"
|
||||
vlan_capture_install $dev "skip_hw vlan_id $vid vlan_ethtype ip"
|
||||
mirror_test v$h1 $ip1 $ip2 $dev 100 $expect
|
||||
mirror_test v$h2 $ip2 $ip1 $dev 100 $expect
|
||||
vlan_capture_uninstall $dev
|
||||
|
113
tools/testing/selftests/net/forwarding/router_bridge.sh
Executable file
113
tools/testing/selftests/net/forwarding/router_bridge.sh
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ALL_TESTS="
|
||||
ping_ipv4
|
||||
ping_ipv6
|
||||
"
|
||||
NUM_NETIFS=4
|
||||
source lib.sh
|
||||
|
||||
h1_create()
|
||||
{
|
||||
simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
|
||||
ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2
|
||||
ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip -6 route del 2001:db8:2::/64 vrf v$h1
|
||||
ip -4 route del 192.0.2.128/28 vrf v$h1
|
||||
simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64
|
||||
ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129
|
||||
ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
ip -6 route del 2001:db8:1::/64 vrf v$h2
|
||||
ip -4 route del 192.0.2.0/28 vrf v$h2
|
||||
simple_if_fini $h2 192.0.2.130/28 2001:db8:2::2/64
|
||||
}
|
||||
|
||||
router_create()
|
||||
{
|
||||
ip link add name br1 type bridge vlan_filtering 1
|
||||
ip link set dev br1 up
|
||||
|
||||
ip link set dev $swp1 master br1
|
||||
ip link set dev $swp1 up
|
||||
__addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64
|
||||
|
||||
ip link set dev $swp2 up
|
||||
__addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
|
||||
}
|
||||
|
||||
router_destroy()
|
||||
{
|
||||
__addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64
|
||||
ip link set dev $swp2 down
|
||||
|
||||
__addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64
|
||||
ip link set dev $swp1 down
|
||||
ip link set dev $swp1 nomaster
|
||||
|
||||
ip link del dev br1
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
h1_create
|
||||
h2_create
|
||||
|
||||
router_create
|
||||
|
||||
forwarding_enable
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
forwarding_restore
|
||||
|
||||
router_destroy
|
||||
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
ping_ipv4()
|
||||
{
|
||||
ping_test $h1 192.0.2.130
|
||||
}
|
||||
|
||||
ping_ipv6()
|
||||
{
|
||||
ping6_test $h1 2001:db8:2::2
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
132
tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
Executable file
132
tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ALL_TESTS="
|
||||
ping_ipv4
|
||||
ping_ipv6
|
||||
vlan
|
||||
"
|
||||
NUM_NETIFS=4
|
||||
source lib.sh
|
||||
|
||||
h1_create()
|
||||
{
|
||||
simple_if_init $h1
|
||||
vlan_create $h1 555 v$h1 192.0.2.1/28 2001:db8:1::1/64
|
||||
ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2
|
||||
ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip -6 route del 2001:db8:2::/64 vrf v$h1
|
||||
ip -4 route del 192.0.2.128/28 vrf v$h1
|
||||
vlan_destroy $h1 555
|
||||
simple_if_fini $h1
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64
|
||||
ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129
|
||||
ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
ip -6 route del 2001:db8:1::/64 vrf v$h2
|
||||
ip -4 route del 192.0.2.0/28 vrf v$h2
|
||||
simple_if_fini $h2 192.0.2.130/28
|
||||
}
|
||||
|
||||
router_create()
|
||||
{
|
||||
ip link add name br1 type bridge vlan_filtering 1
|
||||
ip link set dev br1 up
|
||||
|
||||
ip link set dev $swp1 master br1
|
||||
ip link set dev $swp1 up
|
||||
|
||||
bridge vlan add dev br1 vid 555 self pvid untagged
|
||||
bridge vlan add dev $swp1 vid 555
|
||||
|
||||
__addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64
|
||||
|
||||
ip link set dev $swp2 up
|
||||
__addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
|
||||
}
|
||||
|
||||
router_destroy()
|
||||
{
|
||||
__addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64
|
||||
ip link set dev $swp2 down
|
||||
|
||||
__addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64
|
||||
ip link set dev $swp1 down
|
||||
ip link set dev $swp1 nomaster
|
||||
|
||||
ip link del dev br1
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
swp1=${NETIFS[p2]}
|
||||
|
||||
swp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
h1_create
|
||||
h2_create
|
||||
|
||||
router_create
|
||||
|
||||
forwarding_enable
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
forwarding_restore
|
||||
|
||||
router_destroy
|
||||
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
vlan()
|
||||
{
|
||||
RET=0
|
||||
|
||||
bridge vlan add dev br1 vid 333 self
|
||||
check_err $? "Can't add a non-PVID VLAN"
|
||||
bridge vlan del dev br1 vid 333 self
|
||||
check_err $? "Can't remove a non-PVID VLAN"
|
||||
|
||||
log_test "vlan"
|
||||
}
|
||||
|
||||
ping_ipv4()
|
||||
{
|
||||
ping_test $h1 192.0.2.130
|
||||
}
|
||||
|
||||
ping_ipv6()
|
||||
{
|
||||
ping6_test $h1 2001:db8:2::2
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
233
tools/testing/selftests/net/forwarding/router_broadcast.sh
Executable file
233
tools/testing/selftests/net/forwarding/router_broadcast.sh
Executable file
@@ -0,0 +1,233 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ALL_TESTS="ping_ipv4"
|
||||
NUM_NETIFS=6
|
||||
source lib.sh
|
||||
|
||||
h1_create()
|
||||
{
|
||||
vrf_create "vrf-h1"
|
||||
ip link set dev $h1 master vrf-h1
|
||||
|
||||
ip link set dev vrf-h1 up
|
||||
ip link set dev $h1 up
|
||||
|
||||
ip address add 192.0.2.2/24 dev $h1
|
||||
|
||||
ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1
|
||||
ip route add 198.51.200.0/24 vrf vrf-h1 nexthop via 192.0.2.1
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip route del 198.51.200.0/24 vrf vrf-h1
|
||||
ip route del 198.51.100.0/24 vrf vrf-h1
|
||||
|
||||
ip address del 192.0.2.2/24 dev $h1
|
||||
|
||||
ip link set dev $h1 down
|
||||
vrf_destroy "vrf-h1"
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
vrf_create "vrf-h2"
|
||||
ip link set dev $h2 master vrf-h2
|
||||
|
||||
ip link set dev vrf-h2 up
|
||||
ip link set dev $h2 up
|
||||
|
||||
ip address add 198.51.100.2/24 dev $h2
|
||||
|
||||
ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1
|
||||
ip route add 198.51.200.0/24 vrf vrf-h2 nexthop via 198.51.100.1
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
ip route del 198.51.200.0/24 vrf vrf-h2
|
||||
ip route del 192.0.2.0/24 vrf vrf-h2
|
||||
|
||||
ip address del 198.51.100.2/24 dev $h2
|
||||
|
||||
ip link set dev $h2 down
|
||||
vrf_destroy "vrf-h2"
|
||||
}
|
||||
|
||||
h3_create()
|
||||
{
|
||||
vrf_create "vrf-h3"
|
||||
ip link set dev $h3 master vrf-h3
|
||||
|
||||
ip link set dev vrf-h3 up
|
||||
ip link set dev $h3 up
|
||||
|
||||
ip address add 198.51.200.2/24 dev $h3
|
||||
|
||||
ip route add 192.0.2.0/24 vrf vrf-h3 nexthop via 198.51.200.1
|
||||
ip route add 198.51.100.0/24 vrf vrf-h3 nexthop via 198.51.200.1
|
||||
}
|
||||
|
||||
h3_destroy()
|
||||
{
|
||||
ip route del 198.51.100.0/24 vrf vrf-h3
|
||||
ip route del 192.0.2.0/24 vrf vrf-h3
|
||||
|
||||
ip address del 198.51.200.2/24 dev $h3
|
||||
|
||||
ip link set dev $h3 down
|
||||
vrf_destroy "vrf-h3"
|
||||
}
|
||||
|
||||
router_create()
|
||||
{
|
||||
ip link set dev $rp1 up
|
||||
ip link set dev $rp2 up
|
||||
ip link set dev $rp3 up
|
||||
|
||||
ip address add 192.0.2.1/24 dev $rp1
|
||||
|
||||
ip address add 198.51.100.1/24 dev $rp2
|
||||
ip address add 198.51.200.1/24 dev $rp3
|
||||
}
|
||||
|
||||
router_destroy()
|
||||
{
|
||||
ip address del 198.51.200.1/24 dev $rp3
|
||||
ip address del 198.51.100.1/24 dev $rp2
|
||||
|
||||
ip address del 192.0.2.1/24 dev $rp1
|
||||
|
||||
ip link set dev $rp3 down
|
||||
ip link set dev $rp2 down
|
||||
ip link set dev $rp1 down
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
rp1=${NETIFS[p2]}
|
||||
|
||||
rp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
rp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
vrf_prepare
|
||||
|
||||
h1_create
|
||||
h2_create
|
||||
h3_create
|
||||
|
||||
router_create
|
||||
|
||||
forwarding_enable
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
forwarding_restore
|
||||
|
||||
router_destroy
|
||||
|
||||
h3_destroy
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
bc_forwarding_disable()
|
||||
{
|
||||
sysctl_set net.ipv4.conf.all.bc_forwarding 0
|
||||
sysctl_set net.ipv4.conf.$rp1.bc_forwarding 0
|
||||
}
|
||||
|
||||
bc_forwarding_enable()
|
||||
{
|
||||
sysctl_set net.ipv4.conf.all.bc_forwarding 1
|
||||
sysctl_set net.ipv4.conf.$rp1.bc_forwarding 1
|
||||
}
|
||||
|
||||
bc_forwarding_restore()
|
||||
{
|
||||
sysctl_restore net.ipv4.conf.$rp1.bc_forwarding
|
||||
sysctl_restore net.ipv4.conf.all.bc_forwarding
|
||||
}
|
||||
|
||||
ping_test_from()
|
||||
{
|
||||
local oif=$1
|
||||
local dip=$2
|
||||
local from=$3
|
||||
local fail=${4:-0}
|
||||
|
||||
RET=0
|
||||
|
||||
log_info "ping $dip, expected reply from $from"
|
||||
ip vrf exec $(master_name_get $oif) \
|
||||
$PING -I $oif $dip -c 10 -i 0.1 -w 2 -b 2>&1 | grep $from &> /dev/null
|
||||
check_err_fail $fail $?
|
||||
}
|
||||
|
||||
ping_ipv4()
|
||||
{
|
||||
sysctl_set net.ipv4.icmp_echo_ignore_broadcasts 0
|
||||
|
||||
bc_forwarding_disable
|
||||
log_info "bc_forwarding disabled on r1 =>"
|
||||
ping_test_from $h1 198.51.100.255 192.0.2.1
|
||||
log_test "h1 -> net2: reply from r1 (not forwarding)"
|
||||
ping_test_from $h1 198.51.200.255 192.0.2.1
|
||||
log_test "h1 -> net3: reply from r1 (not forwarding)"
|
||||
ping_test_from $h1 192.0.2.255 192.0.2.1
|
||||
log_test "h1 -> net1: reply from r1 (not dropping)"
|
||||
ping_test_from $h1 255.255.255.255 192.0.2.1
|
||||
log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)"
|
||||
|
||||
ping_test_from $h2 192.0.2.255 198.51.100.1
|
||||
log_test "h2 -> net1: reply from r1 (not forwarding)"
|
||||
ping_test_from $h2 198.51.200.255 198.51.100.1
|
||||
log_test "h2 -> net3: reply from r1 (not forwarding)"
|
||||
ping_test_from $h2 198.51.100.255 198.51.100.1
|
||||
log_test "h2 -> net2: reply from r1 (not dropping)"
|
||||
ping_test_from $h2 255.255.255.255 198.51.100.1
|
||||
log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)"
|
||||
bc_forwarding_restore
|
||||
|
||||
bc_forwarding_enable
|
||||
log_info "bc_forwarding enabled on r1 =>"
|
||||
ping_test_from $h1 198.51.100.255 198.51.100.2
|
||||
log_test "h1 -> net2: reply from h2 (forwarding)"
|
||||
ping_test_from $h1 198.51.200.255 198.51.200.2
|
||||
log_test "h1 -> net3: reply from h3 (forwarding)"
|
||||
ping_test_from $h1 192.0.2.255 192.0.2.1 1
|
||||
log_test "h1 -> net1: no reply (dropping)"
|
||||
ping_test_from $h1 255.255.255.255 192.0.2.1
|
||||
log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)"
|
||||
|
||||
ping_test_from $h2 192.0.2.255 192.0.2.2
|
||||
log_test "h2 -> net1: reply from h1 (forwarding)"
|
||||
ping_test_from $h2 198.51.200.255 198.51.200.2
|
||||
log_test "h2 -> net3: reply from h3 (forwarding)"
|
||||
ping_test_from $h2 198.51.100.255 198.51.100.1 1
|
||||
log_test "h2 -> net2: no reply (dropping)"
|
||||
ping_test_from $h2 255.255.255.255 198.51.100.1
|
||||
log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)"
|
||||
bc_forwarding_restore
|
||||
|
||||
sysctl_restore net.ipv4.icmp_echo_ignore_broadcasts
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
@@ -159,45 +159,6 @@ router2_destroy()
|
||||
vrf_destroy "vrf-r2"
|
||||
}
|
||||
|
||||
multipath_eval()
|
||||
{
|
||||
local desc="$1"
|
||||
local weight_rp12=$2
|
||||
local weight_rp13=$3
|
||||
local packets_rp12=$4
|
||||
local packets_rp13=$5
|
||||
local weights_ratio packets_ratio diff
|
||||
|
||||
RET=0
|
||||
|
||||
if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
|
||||
check_err 1 "Packet difference is 0"
|
||||
log_test "Multipath"
|
||||
log_info "Expected ratio $weights_ratio"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
|
||||
weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
|
||||
| bc -l)
|
||||
packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
|
||||
| bc -l)
|
||||
else
|
||||
weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" | \
|
||||
bc -l)
|
||||
packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" | \
|
||||
bc -l)
|
||||
fi
|
||||
|
||||
diff=$(echo $weights_ratio - $packets_ratio | bc -l)
|
||||
diff=${diff#-}
|
||||
|
||||
test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
|
||||
check_err $? "Too large discrepancy between expected and measured ratios"
|
||||
log_test "$desc"
|
||||
log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
|
||||
}
|
||||
|
||||
multipath4_test()
|
||||
{
|
||||
local desc="$1"
|
||||
|
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ALL_TESTS="unreachable_chain_test gact_goto_chain_test"
|
||||
ALL_TESTS="unreachable_chain_test gact_goto_chain_test create_destroy_chain \
|
||||
template_filter_fits"
|
||||
NUM_NETIFS=2
|
||||
source tc_common.sh
|
||||
source lib.sh
|
||||
@@ -80,6 +81,87 @@ gact_goto_chain_test()
|
||||
log_test "gact goto chain ($tcflags)"
|
||||
}
|
||||
|
||||
create_destroy_chain()
|
||||
{
|
||||
RET=0
|
||||
|
||||
tc chain add dev $h2 ingress
|
||||
check_err $? "Failed to create default chain"
|
||||
|
||||
output="$(tc -j chain get dev $h2 ingress)"
|
||||
check_err $? "Failed to get default chain"
|
||||
|
||||
echo $output | jq -e ".[] | select(.chain == 0)" &> /dev/null
|
||||
check_err $? "Unexpected output for default chain"
|
||||
|
||||
tc chain add dev $h2 ingress chain 1
|
||||
check_err $? "Failed to create chain 1"
|
||||
|
||||
output="$(tc -j chain get dev $h2 ingress chain 1)"
|
||||
check_err $? "Failed to get chain 1"
|
||||
|
||||
echo $output | jq -e ".[] | select(.chain == 1)" &> /dev/null
|
||||
check_err $? "Unexpected output for chain 1"
|
||||
|
||||
output="$(tc -j chain show dev $h2 ingress)"
|
||||
check_err $? "Failed to dump chains"
|
||||
|
||||
echo $output | jq -e ".[] | select(.chain == 0)" &> /dev/null
|
||||
check_err $? "Can't find default chain in dump"
|
||||
|
||||
echo $output | jq -e ".[] | select(.chain == 1)" &> /dev/null
|
||||
check_err $? "Can't find chain 1 in dump"
|
||||
|
||||
tc chain del dev $h2 ingress
|
||||
check_err $? "Failed to destroy default chain"
|
||||
|
||||
tc chain del dev $h2 ingress chain 1
|
||||
check_err $? "Failed to destroy chain 1"
|
||||
|
||||
log_test "create destroy chain"
|
||||
}
|
||||
|
||||
template_filter_fits()
|
||||
{
|
||||
RET=0
|
||||
|
||||
tc chain add dev $h2 ingress protocol ip \
|
||||
flower dst_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null
|
||||
tc chain add dev $h2 ingress chain 1 protocol ip \
|
||||
flower src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 1101 \
|
||||
flower dst_mac $h2mac action drop
|
||||
check_err $? "Failed to insert filter which fits template"
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 1102 \
|
||||
flower src_mac $h2mac action drop &> /dev/null
|
||||
check_fail $? "Incorrectly succeded to insert filter which does not template"
|
||||
|
||||
tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \
|
||||
flower src_mac $h2mac action drop
|
||||
check_err $? "Failed to insert filter which fits template"
|
||||
|
||||
tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \
|
||||
flower dst_mac $h2mac action drop &> /dev/null
|
||||
check_fail $? "Incorrectly succeded to insert filter which does not template"
|
||||
|
||||
tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \
|
||||
flower &> /dev/null
|
||||
tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \
|
||||
flower &> /dev/null
|
||||
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 1102 \
|
||||
flower &> /dev/null
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 1101 \
|
||||
flower &> /dev/null
|
||||
|
||||
tc chain del dev $h2 ingress chain 1
|
||||
tc chain del dev $h2 ingress
|
||||
|
||||
log_test "template filter fits"
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
@@ -103,6 +185,8 @@ cleanup()
|
||||
vrf_cleanup
|
||||
}
|
||||
|
||||
check_tc_chain_support
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
|
@@ -105,6 +105,8 @@ cleanup()
|
||||
ip link set $swp2 address $swp2origmac
|
||||
}
|
||||
|
||||
check_tc_shblock_support
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
|
65
tools/testing/selftests/net/ip6_gre_headroom.sh
Executable file
65
tools/testing/selftests/net/ip6_gre_headroom.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Test that enough headroom is reserved for the first packet passing through an
|
||||
# IPv6 GRE-like netdevice.
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
ip link add h1 type veth peer name swp1
|
||||
ip link add h3 type veth peer name swp3
|
||||
|
||||
ip link set dev h1 up
|
||||
ip address add 192.0.2.1/28 dev h1
|
||||
|
||||
ip link add dev vh3 type vrf table 20
|
||||
ip link set dev h3 master vh3
|
||||
ip link set dev vh3 up
|
||||
ip link set dev h3 up
|
||||
|
||||
ip link set dev swp3 up
|
||||
ip address add dev swp3 2001:db8:2::1/64
|
||||
ip address add dev swp3 2001:db8:2::3/64
|
||||
|
||||
ip link set dev swp1 up
|
||||
tc qdisc add dev swp1 clsact
|
||||
|
||||
ip link add name er6 type ip6erspan \
|
||||
local 2001:db8:2::1 remote 2001:db8:2::2 oseq okey 123
|
||||
ip link set dev er6 up
|
||||
|
||||
ip link add name gt6 type ip6gretap \
|
||||
local 2001:db8:2::3 remote 2001:db8:2::4
|
||||
ip link set dev gt6 up
|
||||
|
||||
sleep 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
ip link del dev gt6
|
||||
ip link del dev er6
|
||||
ip link del dev swp1
|
||||
ip link del dev swp3
|
||||
ip link del dev vh3
|
||||
}
|
||||
|
||||
test_headroom()
|
||||
{
|
||||
local type=$1; shift
|
||||
local tundev=$1; shift
|
||||
|
||||
tc filter add dev swp1 ingress pref 1000 matchall skip_hw \
|
||||
action mirred egress mirror dev $tundev
|
||||
ping -I h1 192.0.2.2 -c 1 -w 2 &> /dev/null
|
||||
tc filter del dev swp1 ingress pref 1000
|
||||
|
||||
# If it doesn't panic, it passes.
|
||||
printf "TEST: %-60s [PASS]\n" "$type headroom"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
test_headroom ip6gretap gt6
|
||||
test_headroom ip6erspan er6
|
@@ -525,18 +525,21 @@ kci_test_macsec()
|
||||
#-------------------------------------------------------------------
|
||||
kci_test_ipsec()
|
||||
{
|
||||
srcip="14.0.0.52"
|
||||
dstip="14.0.0.70"
|
||||
ret=0
|
||||
algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128"
|
||||
srcip=192.168.123.1
|
||||
dstip=192.168.123.2
|
||||
spi=7
|
||||
|
||||
ip addr add $srcip dev $devdummy
|
||||
|
||||
# flush to be sure there's nothing configured
|
||||
ip x s flush ; ip x p flush
|
||||
check_err $?
|
||||
|
||||
# start the monitor in the background
|
||||
tmpfile=`mktemp ipsectestXXX`
|
||||
ip x m > $tmpfile &
|
||||
mpid=$!
|
||||
tmpfile=`mktemp /var/run/ipsectestXXX`
|
||||
mpid=`(ip x m > $tmpfile & echo $!) 2>/dev/null`
|
||||
sleep 0.2
|
||||
|
||||
ipsecid="proto esp src $srcip dst $dstip spi 0x07"
|
||||
@@ -599,6 +602,7 @@ kci_test_ipsec()
|
||||
check_err $?
|
||||
ip x p flush
|
||||
check_err $?
|
||||
ip addr del $srcip/32 dev $devdummy
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "FAIL: ipsec"
|
||||
@@ -607,6 +611,119 @@ kci_test_ipsec()
|
||||
echo "PASS: ipsec"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# Example commands
|
||||
# ip x s add proto esp src 14.0.0.52 dst 14.0.0.70 \
|
||||
# spi 0x07 mode transport reqid 0x07 replay-window 32 \
|
||||
# aead 'rfc4106(gcm(aes))' 1234567890123456dcba 128 \
|
||||
# sel src 14.0.0.52/24 dst 14.0.0.70/24
|
||||
# offload dev sim1 dir out
|
||||
# ip x p add dir out src 14.0.0.52/24 dst 14.0.0.70/24 \
|
||||
# tmpl proto esp src 14.0.0.52 dst 14.0.0.70 \
|
||||
# spi 0x07 mode transport reqid 0x07
|
||||
#
|
||||
#-------------------------------------------------------------------
|
||||
kci_test_ipsec_offload()
|
||||
{
|
||||
ret=0
|
||||
algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128"
|
||||
srcip=192.168.123.3
|
||||
dstip=192.168.123.4
|
||||
dev=simx1
|
||||
sysfsd=/sys/kernel/debug/netdevsim/$dev
|
||||
sysfsf=$sysfsd/ipsec
|
||||
|
||||
# setup netdevsim since dummydev doesn't have offload support
|
||||
modprobe netdevsim
|
||||
check_err $?
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "FAIL: ipsec_offload can't load netdevsim"
|
||||
return 1
|
||||
fi
|
||||
|
||||
ip link add $dev type netdevsim
|
||||
ip addr add $srcip dev $dev
|
||||
ip link set $dev up
|
||||
if [ ! -d $sysfsd ] ; then
|
||||
echo "FAIL: ipsec_offload can't create device $dev"
|
||||
return 1
|
||||
fi
|
||||
if [ ! -f $sysfsf ] ; then
|
||||
echo "FAIL: ipsec_offload netdevsim doesn't support IPsec offload"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# flush to be sure there's nothing configured
|
||||
ip x s flush ; ip x p flush
|
||||
|
||||
# create offloaded SAs, both in and out
|
||||
ip x p add dir out src $srcip/24 dst $dstip/24 \
|
||||
tmpl proto esp src $srcip dst $dstip spi 9 \
|
||||
mode transport reqid 42
|
||||
check_err $?
|
||||
ip x p add dir out src $dstip/24 dst $srcip/24 \
|
||||
tmpl proto esp src $dstip dst $srcip spi 9 \
|
||||
mode transport reqid 42
|
||||
check_err $?
|
||||
|
||||
ip x s add proto esp src $srcip dst $dstip spi 9 \
|
||||
mode transport reqid 42 $algo sel src $srcip/24 dst $dstip/24 \
|
||||
offload dev $dev dir out
|
||||
check_err $?
|
||||
ip x s add proto esp src $dstip dst $srcip spi 9 \
|
||||
mode transport reqid 42 $algo sel src $dstip/24 dst $srcip/24 \
|
||||
offload dev $dev dir in
|
||||
check_err $?
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "FAIL: ipsec_offload can't create SA"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# does offload show up in ip output
|
||||
lines=`ip x s list | grep -c "crypto offload parameters: dev $dev dir"`
|
||||
if [ $lines -ne 2 ] ; then
|
||||
echo "FAIL: ipsec_offload SA offload missing from list output"
|
||||
check_err 1
|
||||
fi
|
||||
|
||||
# use ping to exercise the Tx path
|
||||
ping -I $dev -c 3 -W 1 -i 0 $dstip >/dev/null
|
||||
|
||||
# does driver have correct offload info
|
||||
diff $sysfsf - << EOF
|
||||
SA count=2 tx=3
|
||||
sa[0] tx ipaddr=0x00000000 00000000 00000000 00000000
|
||||
sa[0] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1
|
||||
sa[0] key=0x34333231 38373635 32313039 36353433
|
||||
sa[1] rx ipaddr=0x00000000 00000000 00000000 037ba8c0
|
||||
sa[1] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1
|
||||
sa[1] key=0x34333231 38373635 32313039 36353433
|
||||
EOF
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "FAIL: ipsec_offload incorrect driver data"
|
||||
check_err 1
|
||||
fi
|
||||
|
||||
# does offload get removed from driver
|
||||
ip x s flush
|
||||
ip x p flush
|
||||
lines=`grep -c "SA count=0" $sysfsf`
|
||||
if [ $lines -ne 1 ] ; then
|
||||
echo "FAIL: ipsec_offload SA not removed from driver"
|
||||
check_err 1
|
||||
fi
|
||||
|
||||
# clean up any leftovers
|
||||
ip link del $dev
|
||||
rmmod netdevsim
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "FAIL: ipsec_offload"
|
||||
return 1
|
||||
fi
|
||||
echo "PASS: ipsec_offload"
|
||||
}
|
||||
|
||||
kci_test_gretap()
|
||||
{
|
||||
testns="testns"
|
||||
@@ -861,6 +978,7 @@ kci_test_rtnl()
|
||||
kci_test_encap
|
||||
kci_test_macsec
|
||||
kci_test_ipsec
|
||||
kci_test_ipsec_offload
|
||||
|
||||
kci_del_dummy
|
||||
}
|
||||
|
692
tools/testing/selftests/net/tls.c
Normal file
692
tools/testing/selftests/net/tls.c
Normal file
@@ -0,0 +1,692 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/tls.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../kselftest_harness.h"
|
||||
|
||||
#define TLS_PAYLOAD_MAX_LEN 16384
|
||||
#define SOL_TLS 282
|
||||
|
||||
FIXTURE(tls)
|
||||
{
|
||||
int fd, cfd;
|
||||
bool notls;
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(tls)
|
||||
{
|
||||
struct tls12_crypto_info_aes_gcm_128 tls12;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len;
|
||||
int sfd, ret;
|
||||
|
||||
self->notls = false;
|
||||
len = sizeof(addr);
|
||||
|
||||
memset(&tls12, 0, sizeof(tls12));
|
||||
tls12.info.version = TLS_1_2_VERSION;
|
||||
tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = 0;
|
||||
|
||||
self->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
sfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
ret = bind(sfd, &addr, sizeof(addr));
|
||||
ASSERT_EQ(ret, 0);
|
||||
ret = listen(sfd, 10);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
ret = getsockname(sfd, &addr, &len);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
ret = connect(self->fd, &addr, sizeof(addr));
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
ret = setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
|
||||
if (ret != 0) {
|
||||
self->notls = true;
|
||||
printf("Failure setting TCP_ULP, testing without tls\n");
|
||||
}
|
||||
|
||||
if (!self->notls) {
|
||||
ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12,
|
||||
sizeof(tls12));
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
self->cfd = accept(sfd, &addr, &len);
|
||||
ASSERT_GE(self->cfd, 0);
|
||||
|
||||
if (!self->notls) {
|
||||
ret = setsockopt(self->cfd, IPPROTO_TCP, TCP_ULP, "tls",
|
||||
sizeof("tls"));
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12,
|
||||
sizeof(tls12));
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
close(sfd);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(tls)
|
||||
{
|
||||
close(self->fd);
|
||||
close(self->cfd);
|
||||
}
|
||||
|
||||
TEST_F(tls, sendfile)
|
||||
{
|
||||
int filefd = open("/proc/self/exe", O_RDONLY);
|
||||
struct stat st;
|
||||
|
||||
EXPECT_GE(filefd, 0);
|
||||
fstat(filefd, &st);
|
||||
EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, send_then_sendfile)
|
||||
{
|
||||
int filefd = open("/proc/self/exe", O_RDONLY);
|
||||
char const *test_str = "test_send";
|
||||
int to_send = strlen(test_str) + 1;
|
||||
char recv_buf[10];
|
||||
struct stat st;
|
||||
char *buf;
|
||||
|
||||
EXPECT_GE(filefd, 0);
|
||||
fstat(filefd, &st);
|
||||
buf = (char *)malloc(st.st_size);
|
||||
|
||||
EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send);
|
||||
EXPECT_EQ(recv(self->cfd, recv_buf, to_send, 0), to_send);
|
||||
EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0);
|
||||
|
||||
EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
|
||||
EXPECT_EQ(recv(self->cfd, buf, st.st_size, 0), st.st_size);
|
||||
}
|
||||
|
||||
TEST_F(tls, recv_max)
|
||||
{
|
||||
unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
|
||||
char recv_mem[TLS_PAYLOAD_MAX_LEN];
|
||||
char buf[TLS_PAYLOAD_MAX_LEN];
|
||||
|
||||
EXPECT_GE(send(self->fd, buf, send_len, 0), 0);
|
||||
EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
|
||||
EXPECT_EQ(memcmp(buf, recv_mem, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recv_small)
|
||||
{
|
||||
char const *test_str = "test_read";
|
||||
int send_len = 10;
|
||||
char buf[10];
|
||||
|
||||
send_len = strlen(test_str) + 1;
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
|
||||
EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, msg_more)
|
||||
{
|
||||
char const *test_str = "test_read";
|
||||
int send_len = 10;
|
||||
char buf[10 * 2];
|
||||
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);
|
||||
EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1);
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_DONTWAIT),
|
||||
send_len * 2);
|
||||
EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, sendmsg_single)
|
||||
{
|
||||
struct msghdr msg;
|
||||
|
||||
char const *test_str = "test_sendmsg";
|
||||
size_t send_len = 13;
|
||||
struct iovec vec;
|
||||
char buf[13];
|
||||
|
||||
vec.iov_base = (char *)test_str;
|
||||
vec.iov_len = send_len;
|
||||
memset(&msg, 0, sizeof(struct msghdr));
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
|
||||
EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
|
||||
EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, sendmsg_large)
|
||||
{
|
||||
void *mem = malloc(16384);
|
||||
size_t send_len = 16384;
|
||||
size_t sends = 128;
|
||||
struct msghdr msg;
|
||||
size_t recvs = 0;
|
||||
size_t sent = 0;
|
||||
|
||||
memset(&msg, 0, sizeof(struct msghdr));
|
||||
while (sent++ < sends) {
|
||||
struct iovec vec = { (void *)mem, send_len };
|
||||
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
EXPECT_EQ(sendmsg(self->cfd, &msg, 0), send_len);
|
||||
}
|
||||
|
||||
while (recvs++ < sends)
|
||||
EXPECT_NE(recv(self->fd, mem, send_len, 0), -1);
|
||||
|
||||
free(mem);
|
||||
}
|
||||
|
||||
TEST_F(tls, sendmsg_multiple)
|
||||
{
|
||||
char const *test_str = "test_sendmsg_multiple";
|
||||
struct iovec vec[5];
|
||||
char *test_strs[5];
|
||||
struct msghdr msg;
|
||||
int total_len = 0;
|
||||
int len_cmp = 0;
|
||||
int iov_len = 5;
|
||||
char *buf;
|
||||
int i;
|
||||
|
||||
memset(&msg, 0, sizeof(struct msghdr));
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
test_strs[i] = (char *)malloc(strlen(test_str) + 1);
|
||||
snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
|
||||
vec[i].iov_base = (void *)test_strs[i];
|
||||
vec[i].iov_len = strlen(test_strs[i]) + 1;
|
||||
total_len += vec[i].iov_len;
|
||||
}
|
||||
msg.msg_iov = vec;
|
||||
msg.msg_iovlen = iov_len;
|
||||
|
||||
EXPECT_EQ(sendmsg(self->cfd, &msg, 0), total_len);
|
||||
buf = malloc(total_len);
|
||||
EXPECT_NE(recv(self->fd, buf, total_len, 0), -1);
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
EXPECT_EQ(memcmp(test_strs[i], buf + len_cmp,
|
||||
strlen(test_strs[i])),
|
||||
0);
|
||||
len_cmp += strlen(buf + len_cmp) + 1;
|
||||
}
|
||||
for (i = 0; i < iov_len; i++)
|
||||
free(test_strs[i]);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
TEST_F(tls, sendmsg_multiple_stress)
|
||||
{
|
||||
char const *test_str = "abcdefghijklmno";
|
||||
struct iovec vec[1024];
|
||||
char *test_strs[1024];
|
||||
int iov_len = 1024;
|
||||
int total_len = 0;
|
||||
char buf[1 << 14];
|
||||
struct msghdr msg;
|
||||
int len_cmp = 0;
|
||||
int i;
|
||||
|
||||
memset(&msg, 0, sizeof(struct msghdr));
|
||||
for (i = 0; i < iov_len; i++) {
|
||||
test_strs[i] = (char *)malloc(strlen(test_str) + 1);
|
||||
snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
|
||||
vec[i].iov_base = (void *)test_strs[i];
|
||||
vec[i].iov_len = strlen(test_strs[i]) + 1;
|
||||
total_len += vec[i].iov_len;
|
||||
}
|
||||
msg.msg_iov = vec;
|
||||
msg.msg_iovlen = iov_len;
|
||||
|
||||
EXPECT_EQ(sendmsg(self->fd, &msg, 0), total_len);
|
||||
EXPECT_NE(recv(self->cfd, buf, total_len, 0), -1);
|
||||
|
||||
for (i = 0; i < iov_len; i++)
|
||||
len_cmp += strlen(buf + len_cmp) + 1;
|
||||
|
||||
for (i = 0; i < iov_len; i++)
|
||||
free(test_strs[i]);
|
||||
}
|
||||
|
||||
TEST_F(tls, splice_from_pipe)
|
||||
{
|
||||
int send_len = TLS_PAYLOAD_MAX_LEN;
|
||||
char mem_send[TLS_PAYLOAD_MAX_LEN];
|
||||
char mem_recv[TLS_PAYLOAD_MAX_LEN];
|
||||
int p[2];
|
||||
|
||||
ASSERT_GE(pipe(p), 0);
|
||||
EXPECT_GE(write(p[1], mem_send, send_len), 0);
|
||||
EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0);
|
||||
EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
|
||||
EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, splice_from_pipe2)
|
||||
{
|
||||
int send_len = 16000;
|
||||
char mem_send[16000];
|
||||
char mem_recv[16000];
|
||||
int p2[2];
|
||||
int p[2];
|
||||
|
||||
ASSERT_GE(pipe(p), 0);
|
||||
ASSERT_GE(pipe(p2), 0);
|
||||
EXPECT_GE(write(p[1], mem_send, 8000), 0);
|
||||
EXPECT_GE(splice(p[0], NULL, self->fd, NULL, 8000, 0), 0);
|
||||
EXPECT_GE(write(p2[1], mem_send + 8000, 8000), 0);
|
||||
EXPECT_GE(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 0);
|
||||
EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
|
||||
EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, send_and_splice)
|
||||
{
|
||||
int send_len = TLS_PAYLOAD_MAX_LEN;
|
||||
char mem_send[TLS_PAYLOAD_MAX_LEN];
|
||||
char mem_recv[TLS_PAYLOAD_MAX_LEN];
|
||||
char const *test_str = "test_read";
|
||||
int send_len2 = 10;
|
||||
char buf[10];
|
||||
int p[2];
|
||||
|
||||
ASSERT_GE(pipe(p), 0);
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2);
|
||||
EXPECT_NE(recv(self->cfd, buf, send_len2, 0), -1);
|
||||
EXPECT_EQ(memcmp(test_str, buf, send_len2), 0);
|
||||
|
||||
EXPECT_GE(write(p[1], mem_send, send_len), send_len);
|
||||
EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len);
|
||||
|
||||
EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
|
||||
EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, splice_to_pipe)
|
||||
{
|
||||
int send_len = TLS_PAYLOAD_MAX_LEN;
|
||||
char mem_send[TLS_PAYLOAD_MAX_LEN];
|
||||
char mem_recv[TLS_PAYLOAD_MAX_LEN];
|
||||
int p[2];
|
||||
|
||||
ASSERT_GE(pipe(p), 0);
|
||||
EXPECT_GE(send(self->fd, mem_send, send_len, 0), 0);
|
||||
EXPECT_GE(splice(self->cfd, NULL, p[1], NULL, send_len, 0), 0);
|
||||
EXPECT_GE(read(p[0], mem_recv, send_len), 0);
|
||||
EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recvmsg_single)
|
||||
{
|
||||
char const *test_str = "test_recvmsg_single";
|
||||
int send_len = strlen(test_str) + 1;
|
||||
char buf[20];
|
||||
struct msghdr hdr;
|
||||
struct iovec vec;
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
vec.iov_base = (char *)buf;
|
||||
vec.iov_len = send_len;
|
||||
hdr.msg_iovlen = 1;
|
||||
hdr.msg_iov = &vec;
|
||||
EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
|
||||
EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recvmsg_single_max)
|
||||
{
|
||||
int send_len = TLS_PAYLOAD_MAX_LEN;
|
||||
char send_mem[TLS_PAYLOAD_MAX_LEN];
|
||||
char recv_mem[TLS_PAYLOAD_MAX_LEN];
|
||||
struct iovec vec;
|
||||
struct msghdr hdr;
|
||||
|
||||
EXPECT_EQ(send(self->fd, send_mem, send_len, 0), send_len);
|
||||
vec.iov_base = (char *)recv_mem;
|
||||
vec.iov_len = TLS_PAYLOAD_MAX_LEN;
|
||||
|
||||
hdr.msg_iovlen = 1;
|
||||
hdr.msg_iov = &vec;
|
||||
EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
|
||||
EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recvmsg_multiple)
|
||||
{
|
||||
unsigned int msg_iovlen = 1024;
|
||||
unsigned int len_compared = 0;
|
||||
struct iovec vec[1024];
|
||||
char *iov_base[1024];
|
||||
unsigned int iov_len = 16;
|
||||
int send_len = 1 << 14;
|
||||
char buf[1 << 14];
|
||||
struct msghdr hdr;
|
||||
int i;
|
||||
|
||||
EXPECT_EQ(send(self->fd, buf, send_len, 0), send_len);
|
||||
for (i = 0; i < msg_iovlen; i++) {
|
||||
iov_base[i] = (char *)malloc(iov_len);
|
||||
vec[i].iov_base = iov_base[i];
|
||||
vec[i].iov_len = iov_len;
|
||||
}
|
||||
|
||||
hdr.msg_iovlen = msg_iovlen;
|
||||
hdr.msg_iov = vec;
|
||||
EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
|
||||
for (i = 0; i < msg_iovlen; i++)
|
||||
len_compared += iov_len;
|
||||
|
||||
for (i = 0; i < msg_iovlen; i++)
|
||||
free(iov_base[i]);
|
||||
}
|
||||
|
||||
TEST_F(tls, single_send_multiple_recv)
|
||||
{
|
||||
unsigned int total_len = TLS_PAYLOAD_MAX_LEN * 2;
|
||||
unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
|
||||
char send_mem[TLS_PAYLOAD_MAX_LEN * 2];
|
||||
char recv_mem[TLS_PAYLOAD_MAX_LEN * 2];
|
||||
|
||||
EXPECT_GE(send(self->fd, send_mem, total_len, 0), 0);
|
||||
memset(recv_mem, 0, total_len);
|
||||
|
||||
EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
|
||||
EXPECT_NE(recv(self->cfd, recv_mem + send_len, send_len, 0), -1);
|
||||
EXPECT_EQ(memcmp(send_mem, recv_mem, total_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, multiple_send_single_recv)
|
||||
{
|
||||
unsigned int total_len = 2 * 10;
|
||||
unsigned int send_len = 10;
|
||||
char recv_mem[2 * 10];
|
||||
char send_mem[10];
|
||||
|
||||
EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
|
||||
EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
|
||||
memset(recv_mem, 0, total_len);
|
||||
EXPECT_EQ(recv(self->cfd, recv_mem, total_len, 0), total_len);
|
||||
|
||||
EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
|
||||
EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recv_partial)
|
||||
{
|
||||
char const *test_str = "test_read_partial";
|
||||
char const *test_str_first = "test_read";
|
||||
char const *test_str_second = "_partial";
|
||||
int send_len = strlen(test_str) + 1;
|
||||
char recv_mem[18];
|
||||
|
||||
memset(recv_mem, 0, sizeof(recv_mem));
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_first), 0), -1);
|
||||
EXPECT_EQ(memcmp(test_str_first, recv_mem, strlen(test_str_first)), 0);
|
||||
memset(recv_mem, 0, sizeof(recv_mem));
|
||||
EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_second), 0), -1);
|
||||
EXPECT_EQ(memcmp(test_str_second, recv_mem, strlen(test_str_second)),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recv_nonblock)
|
||||
{
|
||||
char buf[4096];
|
||||
bool err;
|
||||
|
||||
EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
|
||||
err = (errno == EAGAIN || errno == EWOULDBLOCK);
|
||||
EXPECT_EQ(err, true);
|
||||
}
|
||||
|
||||
TEST_F(tls, recv_peek)
|
||||
{
|
||||
char const *test_str = "test_read_peek";
|
||||
int send_len = strlen(test_str) + 1;
|
||||
char buf[15];
|
||||
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
|
||||
EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
|
||||
EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recv_peek_multiple)
|
||||
{
|
||||
char const *test_str = "test_read_peek";
|
||||
int send_len = strlen(test_str) + 1;
|
||||
unsigned int num_peeks = 100;
|
||||
char buf[15];
|
||||
int i;
|
||||
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
for (i = 0; i < num_peeks; i++) {
|
||||
EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
|
||||
EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
}
|
||||
EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
|
||||
EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, pollin)
|
||||
{
|
||||
char const *test_str = "test_poll";
|
||||
struct pollfd fd = { 0, 0, 0 };
|
||||
char buf[10];
|
||||
int send_len = 10;
|
||||
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
fd.fd = self->cfd;
|
||||
fd.events = POLLIN;
|
||||
|
||||
EXPECT_EQ(poll(&fd, 1, 20), 1);
|
||||
EXPECT_EQ(fd.revents & POLLIN, 1);
|
||||
EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
|
||||
/* Test timing out */
|
||||
EXPECT_EQ(poll(&fd, 1, 20), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, poll_wait)
|
||||
{
|
||||
char const *test_str = "test_poll_wait";
|
||||
int send_len = strlen(test_str) + 1;
|
||||
struct pollfd fd = { 0, 0, 0 };
|
||||
char recv_mem[15];
|
||||
|
||||
fd.fd = self->cfd;
|
||||
fd.events = POLLIN;
|
||||
EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
|
||||
/* Set timeout to inf. secs */
|
||||
EXPECT_EQ(poll(&fd, 1, -1), 1);
|
||||
EXPECT_EQ(fd.revents & POLLIN, 1);
|
||||
EXPECT_EQ(recv(self->cfd, recv_mem, send_len, 0), send_len);
|
||||
}
|
||||
|
||||
TEST_F(tls, blocking)
|
||||
{
|
||||
size_t data = 100000;
|
||||
int res = fork();
|
||||
|
||||
EXPECT_NE(res, -1);
|
||||
|
||||
if (res) {
|
||||
/* parent */
|
||||
size_t left = data;
|
||||
char buf[16384];
|
||||
int status;
|
||||
int pid2;
|
||||
|
||||
while (left) {
|
||||
int res = send(self->fd, buf,
|
||||
left > 16384 ? 16384 : left, 0);
|
||||
|
||||
EXPECT_GE(res, 0);
|
||||
left -= res;
|
||||
}
|
||||
|
||||
pid2 = wait(&status);
|
||||
EXPECT_EQ(status, 0);
|
||||
EXPECT_EQ(res, pid2);
|
||||
} else {
|
||||
/* child */
|
||||
size_t left = data;
|
||||
char buf[16384];
|
||||
|
||||
while (left) {
|
||||
int res = recv(self->cfd, buf,
|
||||
left > 16384 ? 16384 : left, 0);
|
||||
|
||||
EXPECT_GE(res, 0);
|
||||
left -= res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(tls, nonblocking)
|
||||
{
|
||||
size_t data = 100000;
|
||||
int sendbuf = 100;
|
||||
int flags;
|
||||
int res;
|
||||
|
||||
flags = fcntl(self->fd, F_GETFL, 0);
|
||||
fcntl(self->fd, F_SETFL, flags | O_NONBLOCK);
|
||||
fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
/* Ensure nonblocking behavior by imposing a small send
|
||||
* buffer.
|
||||
*/
|
||||
EXPECT_EQ(setsockopt(self->fd, SOL_SOCKET, SO_SNDBUF,
|
||||
&sendbuf, sizeof(sendbuf)), 0);
|
||||
|
||||
res = fork();
|
||||
EXPECT_NE(res, -1);
|
||||
|
||||
if (res) {
|
||||
/* parent */
|
||||
bool eagain = false;
|
||||
size_t left = data;
|
||||
char buf[16384];
|
||||
int status;
|
||||
int pid2;
|
||||
|
||||
while (left) {
|
||||
int res = send(self->fd, buf,
|
||||
left > 16384 ? 16384 : left, 0);
|
||||
|
||||
if (res == -1 && errno == EAGAIN) {
|
||||
eagain = true;
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
EXPECT_GE(res, 0);
|
||||
left -= res;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(eagain);
|
||||
pid2 = wait(&status);
|
||||
|
||||
EXPECT_EQ(status, 0);
|
||||
EXPECT_EQ(res, pid2);
|
||||
} else {
|
||||
/* child */
|
||||
bool eagain = false;
|
||||
size_t left = data;
|
||||
char buf[16384];
|
||||
|
||||
while (left) {
|
||||
int res = recv(self->cfd, buf,
|
||||
left > 16384 ? 16384 : left, 0);
|
||||
|
||||
if (res == -1 && errno == EAGAIN) {
|
||||
eagain = true;
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
EXPECT_GE(res, 0);
|
||||
left -= res;
|
||||
}
|
||||
EXPECT_TRUE(eagain);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(tls, control_msg)
|
||||
{
|
||||
if (self->notls)
|
||||
return;
|
||||
|
||||
char cbuf[CMSG_SPACE(sizeof(char))];
|
||||
char const *test_str = "test_read";
|
||||
int cmsg_len = sizeof(char);
|
||||
char record_type = 100;
|
||||
struct cmsghdr *cmsg;
|
||||
struct msghdr msg;
|
||||
int send_len = 10;
|
||||
struct iovec vec;
|
||||
char buf[10];
|
||||
|
||||
vec.iov_base = (char *)test_str;
|
||||
vec.iov_len = 10;
|
||||
memset(&msg, 0, sizeof(struct msghdr));
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cbuf;
|
||||
msg.msg_controllen = sizeof(cbuf);
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_TLS;
|
||||
/* test sending non-record types. */
|
||||
cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
|
||||
cmsg->cmsg_len = CMSG_LEN(cmsg_len);
|
||||
*CMSG_DATA(cmsg) = record_type;
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
|
||||
/* Should fail because we didn't provide a control message */
|
||||
EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
|
||||
|
||||
vec.iov_base = buf;
|
||||
EXPECT_EQ(recvmsg(self->cfd, &msg, 0), send_len);
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
EXPECT_NE(cmsg, NULL);
|
||||
EXPECT_EQ(cmsg->cmsg_level, SOL_TLS);
|
||||
EXPECT_EQ(cmsg->cmsg_type, TLS_GET_RECORD_TYPE);
|
||||
record_type = *((unsigned char *)CMSG_DATA(cmsg));
|
||||
EXPECT_EQ(record_type, 100);
|
||||
EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
@@ -17,6 +17,10 @@ REQUIREMENTS
|
||||
* The kernel must have veth support available, as a veth pair is created
|
||||
prior to running the tests.
|
||||
|
||||
* The kernel must have the appropriate infrastructure enabled to run all tdc
|
||||
unit tests. See the config file in this directory for minimum required
|
||||
features. As new tests will be added, config options list will be updated.
|
||||
|
||||
* All tc-related features being tested must be built in or available as
|
||||
modules. To check what is required in current setup run:
|
||||
./tdc.py -c
|
||||
@@ -109,8 +113,8 @@ COMMAND LINE ARGUMENTS
|
||||
Run tdc.py -h to see the full list of available arguments.
|
||||
|
||||
usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]]
|
||||
[-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v]
|
||||
[-d DEVICE] [-n NS] [-V]
|
||||
[-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v] [-N]
|
||||
[-d DEVICE] [-P] [-n] [-V]
|
||||
|
||||
Linux TC unit tests
|
||||
|
||||
@@ -118,8 +122,10 @@ optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-p PATH, --path PATH The full path to the tc executable to use
|
||||
-v, --verbose Show the commands that are being run
|
||||
-N, --notap Suppress tap results for command under test
|
||||
-d DEVICE, --device DEVICE
|
||||
Execute the test case in flower category
|
||||
-P, --pause Pause execution just before post-suite stage
|
||||
|
||||
selection:
|
||||
select which test cases: files plus directories; filtered by categories
|
||||
@@ -146,10 +152,10 @@ action:
|
||||
-i, --id Generate ID numbers for new test cases
|
||||
|
||||
netns:
|
||||
options for nsPlugin(run commands in net namespace)
|
||||
options for nsPlugin (run commands in net namespace)
|
||||
|
||||
-n NS, --namespace NS
|
||||
Run commands in namespace NS
|
||||
-n, --namespace
|
||||
Run commands in namespace as specified in tdc_config.py
|
||||
|
||||
valgrind:
|
||||
options for valgrindPlugin (run command under test under Valgrind)
|
||||
|
48
tools/testing/selftests/tc-testing/config
Normal file
48
tools/testing/selftests/tc-testing/config
Normal file
@@ -0,0 +1,48 @@
|
||||
CONFIG_NET_SCHED=y
|
||||
|
||||
#
|
||||
# Queueing/Scheduling
|
||||
#
|
||||
CONFIG_NET_SCH_PRIO=m
|
||||
CONFIG_NET_SCH_INGRESS=m
|
||||
|
||||
#
|
||||
# Classification
|
||||
#
|
||||
CONFIG_NET_CLS=y
|
||||
CONFIG_NET_CLS_FW=m
|
||||
CONFIG_NET_CLS_U32=m
|
||||
CONFIG_CLS_U32_PERF=y
|
||||
CONFIG_CLS_U32_MARK=y
|
||||
CONFIG_NET_EMATCH=y
|
||||
CONFIG_NET_EMATCH_STACK=32
|
||||
CONFIG_NET_EMATCH_CMP=m
|
||||
CONFIG_NET_EMATCH_NBYTE=m
|
||||
CONFIG_NET_EMATCH_U32=m
|
||||
CONFIG_NET_EMATCH_META=m
|
||||
CONFIG_NET_EMATCH_TEXT=m
|
||||
CONFIG_NET_EMATCH_IPSET=m
|
||||
CONFIG_NET_EMATCH_IPT=m
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
CONFIG_NET_ACT_POLICE=m
|
||||
CONFIG_NET_ACT_GACT=m
|
||||
CONFIG_GACT_PROB=y
|
||||
CONFIG_NET_ACT_MIRRED=m
|
||||
CONFIG_NET_ACT_SAMPLE=m
|
||||
CONFIG_NET_ACT_IPT=m
|
||||
CONFIG_NET_ACT_NAT=m
|
||||
CONFIG_NET_ACT_PEDIT=m
|
||||
CONFIG_NET_ACT_SIMP=m
|
||||
CONFIG_NET_ACT_SKBEDIT=m
|
||||
CONFIG_NET_ACT_CSUM=m
|
||||
CONFIG_NET_ACT_VLAN=m
|
||||
CONFIG_NET_ACT_BPF=m
|
||||
CONFIG_NET_ACT_CONNMARK=m
|
||||
CONFIG_NET_ACT_SKBMOD=m
|
||||
CONFIG_NET_ACT_IFE=m
|
||||
CONFIG_NET_ACT_TUNNEL_KEY=m
|
||||
CONFIG_NET_IFE_SKBMARK=m
|
||||
CONFIG_NET_IFE_SKBPRIO=m
|
||||
CONFIG_NET_IFE_SKBTCINDEX=m
|
||||
CONFIG_NET_CLS_IND=y
|
||||
CONFIG_NET_SCH_FIFO=y
|
@@ -17,7 +17,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action connmark",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 pipe",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 pipe",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -41,7 +41,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark pass index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action connmark index 1",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -65,7 +65,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark drop index 100",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action connmark index 100",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -89,7 +89,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark pipe index 455",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action connmark index 455",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -113,7 +113,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark reclassify index 7",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action connmark",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -137,7 +137,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark continue index 17",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action connmark",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -161,7 +161,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark jump 10 index 17",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action connmark",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -185,7 +185,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark zone 100 pipe index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action connmark index 1",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -209,7 +209,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark zone 65536 reclassify index 21",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action connmark index 1",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -233,7 +233,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark zone 655 unsupp_arg pass index 2",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action connmark index 2",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -258,7 +258,7 @@
|
||||
"cmdUnderTest": "$TC actions replace action connmark zone 555 reclassify index 555",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action connmark index 555",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
@@ -282,7 +282,7 @@
|
||||
"cmdUnderTest": "$TC actions add action connmark zone 555 pipe index 5 cookie aabbccddeeff112233445566778800a1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action connmark index 5",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1",
|
||||
"matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action connmark"
|
||||
|
@@ -335,6 +335,30 @@
|
||||
"$TC actions flush action csum"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "b10b",
|
||||
"name": "Add all 7 csum actions",
|
||||
"category": [
|
||||
"actions",
|
||||
"csum"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action csum",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action csum icmp ip4h sctp igmp udplite udp tcp index 7",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action csum index 7",
|
||||
"matchPattern": "action order [0-9]*: csum \\(iph, icmp, igmp, tcp, udp, udplite, sctp\\).*index 7 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action csum"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ce92",
|
||||
"name": "Add csum udp action with cookie",
|
||||
|
@@ -44,7 +44,8 @@
|
||||
"matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 2 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action mirred"
|
||||
"$TC actions flush action mirred",
|
||||
"$TC actions flush action gact"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
593
tools/testing/selftests/tc-testing/tc-tests/actions/nat.json
Normal file
593
tools/testing/selftests/tc-testing/tc-tests/actions/nat.json
Normal file
@@ -0,0 +1,593 @@
|
||||
[
|
||||
{
|
||||
"id": "7565",
|
||||
"name": "Add nat action on ingress with default control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 192.168.1.1 200.200.200.1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions ls action nat",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 192.168.1.1/32 200.200.200.1 pass",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "fd79",
|
||||
"name": "Add nat action on ingress with pipe control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 2.2.2.1 pipe index 77",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 77",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 2.2.2.1 pipe.*index 77 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "eab9",
|
||||
"name": "Add nat action on ingress with continue control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 192.168.10.10 192.168.20.20 continue index 1000",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 1000",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 192.168.10.10/32 192.168.20.20 continue.*index 1000 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c53a",
|
||||
"name": "Add nat action on ingress with reclassify control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 192.168.10.10 192.168.20.20 reclassify index 1000",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 1000",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 192.168.10.10/32 192.168.20.20 reclassify.*index 1000 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "76c9",
|
||||
"name": "Add nat action on ingress with jump control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 12.18.10.10 12.18.20.20 jump 10 index 22",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 22",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 12.18.10.10/32 12.18.20.20 jump 10.*index 22 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "24c6",
|
||||
"name": "Add nat action on ingress with drop control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 drop index 722",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 722",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 drop.*index 722 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2120",
|
||||
"name": "Add nat action on ingress with maximum index value",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 index 4294967295",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 4294967295",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 pass.*index 4294967295 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "3e9d",
|
||||
"name": "Add nat action on ingress with invalid index value",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 index 4294967295555",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action nat index 4294967295555",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 pass.*index 4294967295555 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "f6c9",
|
||||
"name": "Add nat action on ingress with invalid IP address",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 1.1888.2.2 index 7",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action nat index 7",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 1.1888.2.2 pass.*index 7 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "be25",
|
||||
"name": "Add nat action on ingress with invalid argument",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 1.18.2.2 another_arg index 12",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action nat index 12",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 1.18.2.2 pass.*another_arg.*index 12 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "a7bd",
|
||||
"name": "Add nat action on ingress with DEFAULT IP address",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress default 10.10.10.1 index 12",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 12",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ee1e",
|
||||
"name": "Add nat action on ingress with ANY IP address",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress any 10.10.10.1 index 12",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 12",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1de8",
|
||||
"name": "Add nat action on ingress with ALL IP address",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress all 10.10.10.1 index 12",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 12",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "8dba",
|
||||
"name": "Add nat action on egress with default control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions ls action nat",
|
||||
"matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 pass",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "19a7",
|
||||
"name": "Add nat action on egress with pipe control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 pipe",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions ls action nat",
|
||||
"matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 pipe",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "f1d9",
|
||||
"name": "Add nat action on egress with continue control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 continue",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions ls action nat",
|
||||
"matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 continue",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6d4a",
|
||||
"name": "Add nat action on egress with reclassify control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 reclassify",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions ls action nat",
|
||||
"matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 reclassify",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "b313",
|
||||
"name": "Add nat action on egress with jump control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 jump 777",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions ls action nat",
|
||||
"matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 jump 777",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "d9fc",
|
||||
"name": "Add nat action on egress with drop control action",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 drop",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions ls action nat",
|
||||
"matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 drop",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "a895",
|
||||
"name": "Add nat action on egress with DEFAULT IP address",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress default 20.20.20.1 pipe index 10",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 10",
|
||||
"matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2572",
|
||||
"name": "Add nat action on egress with ANY IP address",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress any 20.20.20.1 pipe index 10",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 10",
|
||||
"matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "37f3",
|
||||
"name": "Add nat action on egress with ALL IP address",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress all 20.20.20.1 pipe index 10",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 10",
|
||||
"matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6054",
|
||||
"name": "Add nat action on egress with cookie",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat egress all 20.20.20.1 pipe index 10 cookie aa1bc2d3eeff112233445566778800a1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 10",
|
||||
"matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref.*cookie aa1bc2d3eeff112233445566778800a1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "79d6",
|
||||
"name": "Add nat action on ingress with cookie",
|
||||
"category": [
|
||||
"actions",
|
||||
"nat"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action nat",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action nat ingress 192.168.1.1 10.10.10.1 reclassify index 1 cookie 112233445566778899aabbccddeeff11",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action nat index 1",
|
||||
"matchPattern": "action order [0-9]+: nat ingress 192.168.1.1/32 10.10.10.1 reclassify.*index 1 ref.*cookie 112233445566778899aabbccddeeff11",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action nat"
|
||||
]
|
||||
}
|
||||
]
|
@@ -17,7 +17,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit mark 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action skbedit",
|
||||
"matchPattern": "action order [0-9]*: skbedit mark 1",
|
||||
"matchPattern": "action order [0-9]*: skbedit mark 1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -65,7 +65,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit prio 99",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action skbedit",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :99",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :99",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -113,7 +113,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit queue_mapping 909",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action skbedit",
|
||||
"matchPattern": "action order [0-9]*: skbedit queue_mapping 909",
|
||||
"matchPattern": "action order [0-9]*: skbedit queue_mapping 909",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -161,7 +161,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit ptype host",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action skbedit",
|
||||
"matchPattern": "action order [0-9]*: skbedit ptype host",
|
||||
"matchPattern": "action order [0-9]*: skbedit ptype host",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -185,7 +185,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit ptype otherhost",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action skbedit",
|
||||
"matchPattern": "action order [0-9]*: skbedit ptype otherhost",
|
||||
"matchPattern": "action order [0-9]*: skbedit ptype otherhost",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -233,7 +233,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit ptype host pipe index 11",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action skbedit index 11",
|
||||
"matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref",
|
||||
"matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -257,7 +257,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit mark 56789 reclassify index 90",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action skbedit index 90",
|
||||
"matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref",
|
||||
"matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -281,7 +281,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 pass index 271",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action skbedit index 271",
|
||||
"matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref",
|
||||
"matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -305,7 +305,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 drop index 271",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action skbedit index 271",
|
||||
"matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref",
|
||||
"matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -329,7 +329,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit priority 8 jump 9 index 2",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action skbedit index 2",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -353,7 +353,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action skbedit index 32",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -377,7 +377,7 @@
|
||||
"cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32 cookie deadbeef",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action skbedit index 32",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef",
|
||||
"matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
@@ -405,7 +405,7 @@
|
||||
"cmdUnderTest": "$TC actions list action skbedit",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action skbedit",
|
||||
"matchPattern": "action order [0-9]*: skbedit",
|
||||
"matchPattern": "action order [0-9]*: skbedit",
|
||||
"matchCount": "4",
|
||||
"teardown": [
|
||||
"$TC actions flush action skbedit"
|
||||
|
@@ -0,0 +1,917 @@
|
||||
[
|
||||
{
|
||||
"id": "2b11",
|
||||
"name": "Add tunnel_key set action with mandatory parameters",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action tunnel_key",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dc6b",
|
||||
"name": "Add tunnel_key set action with missing mandatory src_ip parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set dst_ip 20.20.20.2 id 100",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions list action tunnel_key",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*dst_ip 20.20.20.2.*key_id 100",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7f25",
|
||||
"name": "Add tunnel_key set action with missing mandatory dst_ip parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 id 100",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions list action tunnel_key",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 10.10.10.1.*key_id 100",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ba4e",
|
||||
"name": "Add tunnel_key set action with missing mandatory id parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions list action tunnel_key",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "a5e0",
|
||||
"name": "Add tunnel_key set action with invalid src_ip parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 300.168.100.1 dst_ip 192.168.200.1 id 7 index 1",
|
||||
"expExitCode": "1",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 300.168.100.1.*dst_ip 192.168.200.1.*key_id 7.*index 1 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "eaa8",
|
||||
"name": "Add tunnel_key set action with invalid dst_ip parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.100.1 dst_ip 192.168.800.1 id 10 index 11",
|
||||
"expExitCode": "1",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 11",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 192.168.100.1.*dst_ip 192.168.800.1.*key_id 10.*index 11 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "3b09",
|
||||
"name": "Add tunnel_key set action with invalid id parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 112233445566778899 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 112233445566778899.*index 1 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "9625",
|
||||
"name": "Add tunnel_key set action with invalid dst_port parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 dst_port 998877 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 11.*dst_port 998877.*index 1 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "05af",
|
||||
"name": "Add tunnel_key set action with optional dst_port parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.100.1 dst_ip 192.168.200.1 id 789 dst_port 4000 index 10",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 10",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.100.1.*dst_ip 192.168.200.1.*key_id 789.*dst_port 4000.*index 10 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "da80",
|
||||
"name": "Add tunnel_key set action with index at 32-bit maximum",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 index 4294967295",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 4294967295",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*id 11.*index 4294967295 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "d407",
|
||||
"name": "Add tunnel_key set action with index exceeding 32-bit maximum",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 index 4294967295678",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 4294967295678",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key set.*index 4294967295678 ref",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "5cba",
|
||||
"name": "Add tunnel_key set action with id value at 32-bit maximum",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 4294967295 index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 4294967295.*index 1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e84a",
|
||||
"name": "Add tunnel_key set action with id value exceeding 32-bit maximum",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42949672955 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 4294967295",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42949672955.*index 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "9c19",
|
||||
"name": "Add tunnel_key set action with dst_port value at 16-bit maximum",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 429 dst_port 65535 index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 429.*dst_port 65535.*index 1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "3bd9",
|
||||
"name": "Add tunnel_key set action with dst_port value exceeding 16-bit maximum",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 429 dst_port 65535789 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 429.*dst_port 65535789.*index 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "68e2",
|
||||
"name": "Add tunnel_key unset action",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key unset index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*unset.*index 1 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6192",
|
||||
"name": "Add tunnel_key unset continue action",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key unset continue index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*unset continue.*index 1 ref",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "061d",
|
||||
"name": "Add tunnel_key set continue action with cookie",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.10.1 dst_ip 192.168.20.2 id 123 continue index 1 cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.10.1.*dst_ip 192.168.20.2.*key_id 123.*csum continue.*index 1.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "8acb",
|
||||
"name": "Add tunnel_key set continue action with invalid cookie",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.10.1 dst_ip 192.168.20.2 id 123 continue index 1 cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.10.1.*dst_ip 192.168.20.2.*key_id 123.*csum continue.*index 1.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "a07e",
|
||||
"name": "Add tunnel_key action with no set/unset command specified",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "b227",
|
||||
"name": "Add tunnel_key action with csum option",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1 csum index 99",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 99",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1.*csum pipe.*index 99",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "58a7",
|
||||
"name": "Add tunnel_key action with nocsum option",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7823 nocsum index 234",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 234",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7823.*nocsum pipe.*index 234",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2575",
|
||||
"name": "Add tunnel_key action with not-supported parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7 foobar 999 index 4",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 4",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*foobar 999.*index 4",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7a88",
|
||||
"name": "Add tunnel_key action with cookie parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7 index 4 cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 4",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*dst_port 0.*csum pipe.*index 4 ref.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "4f20",
|
||||
"name": "Add tunnel_key action with a single geneve option parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022 index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022.*index 1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e33d",
|
||||
"name": "Add tunnel_key action with multiple geneve options parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022,0408:42:0040007611223344,0111:02:1020304011223344 index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022,0408:42:0040007611223344,0111:02:1020304011223344.*index 1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "0778",
|
||||
"name": "Add tunnel_key action with invalid class geneve option parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 824212:80:00880022 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 824212:80:00880022.*index 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "4ae8",
|
||||
"name": "Add tunnel_key action with invalid type geneve option parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:4224:00880022 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:4224:00880022.*index 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "4039",
|
||||
"name": "Add tunnel_key action with short data length geneve option parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:4288 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:4288.*index 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "26a6",
|
||||
"name": "Add tunnel_key action with non-multiple of 4 data length geneve option parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:4288428822 index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:4288428822.*index 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "f44d",
|
||||
"name": "Add tunnel_key action with incomplete geneve options parameter",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
]
|
||||
],
|
||||
"cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022,0408:42: index 1",
|
||||
"expExitCode": "255",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022,0408:42:.*index 1",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7afc",
|
||||
"name": "Replace tunnel_key set action with all parameters",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
],
|
||||
"$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 csum id 1 index 1"
|
||||
],
|
||||
"cmdUnderTest": "$TC actions replace action tunnel_key set src_ip 11.11.11.1 dst_ip 21.21.21.2 dst_port 3129 nocsum id 11 index 1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 11.11.11.1.*dst_ip 21.21.21.2.*key_id 11.*dst_port 3129.*nocsum pipe.*index 1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "364d",
|
||||
"name": "Replace tunnel_key set action with all parameters and cookie",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
],
|
||||
"$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 index 1 cookie aabbccddeeff112233445566778800a"
|
||||
],
|
||||
"cmdUnderTest": "$TC actions replace action tunnel_key set src_ip 11.11.11.1 dst_ip 21.21.21.2 dst_port 3129 id 11 csum reclassify index 1 cookie a1b1c1d1",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions get action tunnel_key index 1",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 11.11.11.1.*dst_ip 21.21.21.2.*key_id 11.*dst_port 3129.*csum reclassify.*index 1.*cookie a1b1c1d1",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "937c",
|
||||
"name": "Fetch all existing tunnel_key actions",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
],
|
||||
"$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 pipe index 1",
|
||||
"$TC actions add action tunnel_key set src_ip 11.10.10.1 dst_ip 21.20.20.2 dst_port 3129 csum id 2 jump 10 index 2",
|
||||
"$TC actions add action tunnel_key set src_ip 12.10.10.1 dst_ip 22.20.20.2 dst_port 3130 csum id 3 pass index 3",
|
||||
"$TC actions add action tunnel_key set src_ip 13.10.10.1 dst_ip 23.20.20.2 dst_port 3131 nocsum id 4 continue index 4"
|
||||
],
|
||||
"cmdUnderTest": "$TC actions list action tunnel_key",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action tunnel_key",
|
||||
"matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1.*dst_port 3128.*nocsum pipe.*index 1.*set.*src_ip 11.10.10.1.*dst_ip 21.20.20.2.*key_id 2.*dst_port 3129.*csum jump 10.*index 2.*set.*src_ip 12.10.10.1.*dst_ip 22.20.20.2.*key_id 3.*dst_port 3130.*csum pass.*index 3.*set.*src_ip 13.10.10.1.*dst_ip 23.20.20.2.*key_id 4.*dst_port 3131.*nocsum continue.*index 4",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6783",
|
||||
"name": "Flush all existing tunnel_key actions",
|
||||
"category": [
|
||||
"actions",
|
||||
"tunnel_key"
|
||||
],
|
||||
"setup": [
|
||||
[
|
||||
"$TC actions flush action tunnel_key",
|
||||
0,
|
||||
1,
|
||||
255
|
||||
],
|
||||
"$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 pipe index 1",
|
||||
"$TC actions add action tunnel_key set src_ip 11.10.10.1 dst_ip 21.20.20.2 dst_port 3129 csum id 2 reclassify index 2",
|
||||
"$TC actions add action tunnel_key set src_ip 12.10.10.1 dst_ip 22.20.20.2 dst_port 3130 csum id 3 pass index 3",
|
||||
"$TC actions add action tunnel_key set src_ip 13.10.10.1 dst_ip 23.20.20.2 dst_port 3131 nocsum id 4 continue index 4"
|
||||
],
|
||||
"cmdUnderTest": "$TC actions flush action tunnel_key",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC actions list action tunnel_key",
|
||||
"matchPattern": "action order [0-9]+:.*",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"$TC actions flush action tunnel_key"
|
||||
]
|
||||
}
|
||||
]
|
1049
tools/testing/selftests/tc-testing/tc-tests/filters/fw.json
Normal file
1049
tools/testing/selftests/tc-testing/tc-tests/filters/fw.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,8 +12,8 @@
|
||||
"cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 u32 match ip src 127.0.0.1/32 flowid 1:1 action ok",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
|
||||
"matchPattern": "match 7f000002/ffffffff at 12",
|
||||
"matchCount": "0",
|
||||
"matchPattern": "match 7f000001/ffffffff at 12",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC qdisc del dev $DEV1 ingress"
|
||||
]
|
||||
|
Reference in New Issue
Block a user