Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says: ==================== pull-request: bpf-next 2018-04-27 The following pull-request contains BPF updates for your *net-next* tree. The main changes are: 1) Add extensive BPF helper description into include/uapi/linux/bpf.h and a new script bpf_helpers_doc.py which allows for generating a man page out of it. Thus, every helper in BPF now comes with proper function signature, detailed description and return code explanation, from Quentin. 2) Migrate the BPF collect metadata tunnel tests from BPF samples over to the BPF selftests and further extend them with v6 vxlan, geneve and ipip tests, simplify the ipip tests, improve documentation and convert to bpf_ntoh*() / bpf_hton*() api, from William. 3) Currently, helpers that expect ARG_PTR_TO_MAP_{KEY,VALUE} can only access stack and packet memory. Extend this to allow such helpers to also use map values, which enabled use cases where value from a first lookup can be directly used as a key for a second lookup, from Paul. 4) Add a new helper bpf_skb_get_xfrm_state() for tc BPF programs in order to retrieve XFRM state information containing SPI, peer address and reqid values, from Eyal. 5) Various optimizations in nfp driver's BPF JIT in order to turn ADD and SUB instructions with negative immediate into the opposite operation with a positive immediate such that nfp can better fit small immediates into instructions. Savings in instruction count up to 4% have been observed, from Jakub. 6) Add the BPF prog's gpl_compatible flag to struct bpf_prog_info and add support for dumping this through bpftool, from Jiri. 7) Move the BPF sockmap samples over into BPF selftests instead since sockmap was rather a series of tests than sample anyway and this way this can be run from automated bots, from John. 8) Follow-up fix for bpf_adjust_tail() helper in order to make it work with generic XDP, from Nikita. 9) Some follow-up cleanups to BTF, namely, removing unused defines from BTF uapi header and renaming 'name' struct btf_* members into name_off to make it more clear they are offsets into string section, from Martin. 10) Remove test_sock_addr from TEST_GEN_PROGS in BPF selftests since not run directly but invoked from test_sock_addr.sh, from Yonghong. 11) Remove redundant ret assignment in sample BPF loader, from Wang. 12) Add couple of missing files to BPF selftest's gitignore, from Anders. There are two trivial merge conflicts while pulling: 1) Remove samples/sockmap/Makefile since all sockmap tests have been moved to selftests. 2) Add both hunks from tools/testing/selftests/bpf/.gitignore to the file since git should ignore all of them. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
1
tools/testing/selftests/bpf/.gitignore
vendored
1
tools/testing/selftests/bpf/.gitignore
vendored
@@ -15,3 +15,4 @@ test_libbpf_open
|
||||
test_sock
|
||||
test_sock_addr
|
||||
urandom_read
|
||||
test_btf
|
||||
|
@@ -24,7 +24,7 @@ urandom_read: urandom_read.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_sock_addr test_btf
|
||||
test_sock test_btf test_sockmap
|
||||
|
||||
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 \
|
||||
@@ -32,7 +32,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
|
||||
test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \
|
||||
sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \
|
||||
sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o test_adjust_tail.o \
|
||||
test_btf_haskv.o test_btf_nokv.o
|
||||
test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o
|
||||
|
||||
# Order correspond to 'make run_tests' order
|
||||
TEST_PROGS := test_kmod.sh \
|
||||
@@ -40,10 +40,11 @@ TEST_PROGS := test_kmod.sh \
|
||||
test_xdp_redirect.sh \
|
||||
test_xdp_meta.sh \
|
||||
test_offload.py \
|
||||
test_sock_addr.sh
|
||||
test_sock_addr.sh \
|
||||
test_tunnel.sh
|
||||
|
||||
# Compile but not part of 'make run_tests'
|
||||
TEST_GEN_PROGS_EXTENDED = test_libbpf_open
|
||||
TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr
|
||||
|
||||
include ../lib.mk
|
||||
|
||||
@@ -56,6 +57,7 @@ $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
|
||||
$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sock: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sock_addr: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sockmap: cgroup_helpers.c
|
||||
|
||||
.PHONY: force
|
||||
|
||||
|
@@ -98,7 +98,9 @@ static int (*bpf_bind)(void *ctx, void *addr, int addr_len) =
|
||||
(void *) BPF_FUNC_bind;
|
||||
static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) =
|
||||
(void *) BPF_FUNC_xdp_adjust_tail;
|
||||
|
||||
static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state,
|
||||
int size, int flags) =
|
||||
(void *) BPF_FUNC_skb_get_xfrm_state;
|
||||
|
||||
/* llvm builtin functions that eBPF C program may use to
|
||||
* emit BPF_LD_ABS and BPF_LD_IND instructions
|
||||
|
1464
tools/testing/selftests/bpf/test_sockmap.c
Normal file
1464
tools/testing/selftests/bpf/test_sockmap.c
Normal file
File diff suppressed because it is too large
Load Diff
340
tools/testing/selftests/bpf/test_sockmap_kern.c
Normal file
340
tools/testing/selftests/bpf/test_sockmap_kern.c
Normal file
@@ -0,0 +1,340 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <sys/socket.h>
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_endian.h"
|
||||
|
||||
/* Sockmap sample program connects a client and a backend together
|
||||
* using cgroups.
|
||||
*
|
||||
* client:X <---> frontend:80 client:X <---> backend:80
|
||||
*
|
||||
* For simplicity we hard code values here and bind 1:1. The hard
|
||||
* coded values are part of the setup in sockmap.sh script that
|
||||
* is associated with this BPF program.
|
||||
*
|
||||
* The bpf_printk is verbose and prints information as connections
|
||||
* are established and verdicts are decided.
|
||||
*/
|
||||
|
||||
#define bpf_printk(fmt, ...) \
|
||||
({ \
|
||||
char ____fmt[] = fmt; \
|
||||
bpf_trace_printk(____fmt, sizeof(____fmt), \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_map = {
|
||||
.type = BPF_MAP_TYPE_SOCKMAP,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 20,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_map_txmsg = {
|
||||
.type = BPF_MAP_TYPE_SOCKMAP,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 20,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_map_redir = {
|
||||
.type = BPF_MAP_TYPE_SOCKMAP,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 20,
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_apply_bytes = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 1
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_cork_bytes = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 1
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_pull_bytes = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 2
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_redir_flags = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 1
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") sock_skb_opts = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 1
|
||||
};
|
||||
|
||||
SEC("sk_skb1")
|
||||
int bpf_prog1(struct __sk_buff *skb)
|
||||
{
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
SEC("sk_skb2")
|
||||
int bpf_prog2(struct __sk_buff *skb)
|
||||
{
|
||||
__u32 lport = skb->local_port;
|
||||
__u32 rport = skb->remote_port;
|
||||
int len, *f, ret, zero = 0;
|
||||
__u64 flags = 0;
|
||||
|
||||
if (lport == 10000)
|
||||
ret = 10;
|
||||
else
|
||||
ret = 1;
|
||||
|
||||
len = (__u32)skb->data_end - (__u32)skb->data;
|
||||
f = bpf_map_lookup_elem(&sock_skb_opts, &zero);
|
||||
if (f && *f) {
|
||||
ret = 3;
|
||||
flags = *f;
|
||||
}
|
||||
|
||||
bpf_printk("sk_skb2: redirect(%iB) flags=%i\n",
|
||||
len, flags);
|
||||
return bpf_sk_redirect_map(skb, &sock_map, ret, flags);
|
||||
}
|
||||
|
||||
SEC("sockops")
|
||||
int bpf_sockmap(struct bpf_sock_ops *skops)
|
||||
{
|
||||
__u32 lport, rport;
|
||||
int op, err = 0, index, key, ret;
|
||||
|
||||
|
||||
op = (int) skops->op;
|
||||
|
||||
switch (op) {
|
||||
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
|
||||
lport = skops->local_port;
|
||||
rport = skops->remote_port;
|
||||
|
||||
if (lport == 10000) {
|
||||
ret = 1;
|
||||
err = bpf_sock_map_update(skops, &sock_map, &ret,
|
||||
BPF_NOEXIST);
|
||||
bpf_printk("passive(%i -> %i) map ctx update err: %d\n",
|
||||
lport, bpf_ntohl(rport), err);
|
||||
}
|
||||
break;
|
||||
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
|
||||
lport = skops->local_port;
|
||||
rport = skops->remote_port;
|
||||
|
||||
if (bpf_ntohl(rport) == 10001) {
|
||||
ret = 10;
|
||||
err = bpf_sock_map_update(skops, &sock_map, &ret,
|
||||
BPF_NOEXIST);
|
||||
bpf_printk("active(%i -> %i) map ctx update err: %d\n",
|
||||
lport, bpf_ntohl(rport), err);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("sk_msg1")
|
||||
int bpf_prog4(struct sk_msg_md *msg)
|
||||
{
|
||||
int *bytes, zero = 0, one = 1;
|
||||
int *start, *end;
|
||||
|
||||
bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
|
||||
if (bytes)
|
||||
bpf_msg_apply_bytes(msg, *bytes);
|
||||
bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
|
||||
if (bytes)
|
||||
bpf_msg_cork_bytes(msg, *bytes);
|
||||
start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
|
||||
end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
|
||||
if (start && end)
|
||||
bpf_msg_pull_data(msg, *start, *end, 0);
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_msg2")
|
||||
int bpf_prog5(struct sk_msg_md *msg)
|
||||
{
|
||||
int err1 = -1, err2 = -1, zero = 0, one = 1;
|
||||
int *bytes, *start, *end, len1, len2;
|
||||
|
||||
bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
|
||||
if (bytes)
|
||||
err1 = bpf_msg_apply_bytes(msg, *bytes);
|
||||
bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
|
||||
if (bytes)
|
||||
err2 = bpf_msg_cork_bytes(msg, *bytes);
|
||||
len1 = (__u64)msg->data_end - (__u64)msg->data;
|
||||
start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
|
||||
end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
|
||||
if (start && end) {
|
||||
int err;
|
||||
|
||||
bpf_printk("sk_msg2: pull(%i:%i)\n",
|
||||
start ? *start : 0, end ? *end : 0);
|
||||
err = bpf_msg_pull_data(msg, *start, *end, 0);
|
||||
if (err)
|
||||
bpf_printk("sk_msg2: pull_data err %i\n",
|
||||
err);
|
||||
len2 = (__u64)msg->data_end - (__u64)msg->data;
|
||||
bpf_printk("sk_msg2: length update %i->%i\n",
|
||||
len1, len2);
|
||||
}
|
||||
bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n",
|
||||
len1, err1, err2);
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_msg3")
|
||||
int bpf_prog6(struct sk_msg_md *msg)
|
||||
{
|
||||
int *bytes, zero = 0, one = 1, key = 0;
|
||||
int *start, *end, *f;
|
||||
__u64 flags = 0;
|
||||
|
||||
bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
|
||||
if (bytes)
|
||||
bpf_msg_apply_bytes(msg, *bytes);
|
||||
bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
|
||||
if (bytes)
|
||||
bpf_msg_cork_bytes(msg, *bytes);
|
||||
start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
|
||||
end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
|
||||
if (start && end)
|
||||
bpf_msg_pull_data(msg, *start, *end, 0);
|
||||
f = bpf_map_lookup_elem(&sock_redir_flags, &zero);
|
||||
if (f && *f) {
|
||||
key = 2;
|
||||
flags = *f;
|
||||
}
|
||||
return bpf_msg_redirect_map(msg, &sock_map_redir, key, flags);
|
||||
}
|
||||
|
||||
SEC("sk_msg4")
|
||||
int bpf_prog7(struct sk_msg_md *msg)
|
||||
{
|
||||
int err1 = 0, err2 = 0, zero = 0, one = 1, key = 0;
|
||||
int *f, *bytes, *start, *end, len1, len2;
|
||||
__u64 flags = 0;
|
||||
|
||||
int err;
|
||||
bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
|
||||
if (bytes)
|
||||
err1 = bpf_msg_apply_bytes(msg, *bytes);
|
||||
bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
|
||||
if (bytes)
|
||||
err2 = bpf_msg_cork_bytes(msg, *bytes);
|
||||
len1 = (__u64)msg->data_end - (__u64)msg->data;
|
||||
start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
|
||||
end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
|
||||
if (start && end) {
|
||||
|
||||
bpf_printk("sk_msg2: pull(%i:%i)\n",
|
||||
start ? *start : 0, end ? *end : 0);
|
||||
err = bpf_msg_pull_data(msg, *start, *end, 0);
|
||||
if (err)
|
||||
bpf_printk("sk_msg2: pull_data err %i\n",
|
||||
err);
|
||||
len2 = (__u64)msg->data_end - (__u64)msg->data;
|
||||
bpf_printk("sk_msg2: length update %i->%i\n",
|
||||
len1, len2);
|
||||
}
|
||||
f = bpf_map_lookup_elem(&sock_redir_flags, &zero);
|
||||
if (f && *f) {
|
||||
key = 2;
|
||||
flags = *f;
|
||||
}
|
||||
bpf_printk("sk_msg3: redirect(%iB) flags=%i err=%i\n",
|
||||
len1, flags, err1 ? err1 : err2);
|
||||
err = bpf_msg_redirect_map(msg, &sock_map_redir, key, flags);
|
||||
bpf_printk("sk_msg3: err %i\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
SEC("sk_msg5")
|
||||
int bpf_prog8(struct sk_msg_md *msg)
|
||||
{
|
||||
void *data_end = (void *)(long) msg->data_end;
|
||||
void *data = (void *)(long) msg->data;
|
||||
int ret = 0, *bytes, zero = 0;
|
||||
|
||||
bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
|
||||
if (bytes) {
|
||||
ret = bpf_msg_apply_bytes(msg, *bytes);
|
||||
if (ret)
|
||||
return SK_DROP;
|
||||
} else {
|
||||
return SK_DROP;
|
||||
}
|
||||
return SK_PASS;
|
||||
}
|
||||
SEC("sk_msg6")
|
||||
int bpf_prog9(struct sk_msg_md *msg)
|
||||
{
|
||||
void *data_end = (void *)(long) msg->data_end;
|
||||
void *data = (void *)(long) msg->data;
|
||||
int ret = 0, *bytes, zero = 0;
|
||||
|
||||
bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
|
||||
if (bytes) {
|
||||
if (((__u64)data_end - (__u64)data) >= *bytes)
|
||||
return SK_PASS;
|
||||
ret = bpf_msg_cork_bytes(msg, *bytes);
|
||||
if (ret)
|
||||
return SK_DROP;
|
||||
}
|
||||
return SK_PASS;
|
||||
}
|
||||
|
||||
SEC("sk_msg7")
|
||||
int bpf_prog10(struct sk_msg_md *msg)
|
||||
{
|
||||
int *bytes, zero = 0, one = 1;
|
||||
int *start, *end;
|
||||
|
||||
bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
|
||||
if (bytes)
|
||||
bpf_msg_apply_bytes(msg, *bytes);
|
||||
bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
|
||||
if (bytes)
|
||||
bpf_msg_cork_bytes(msg, *bytes);
|
||||
start = bpf_map_lookup_elem(&sock_pull_bytes, &zero);
|
||||
end = bpf_map_lookup_elem(&sock_pull_bytes, &one);
|
||||
if (start && end)
|
||||
bpf_msg_pull_data(msg, *start, *end, 0);
|
||||
|
||||
return SK_DROP;
|
||||
}
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
char _license[] SEC("license") = "GPL";
|
729
tools/testing/selftests/bpf/test_tunnel.sh
Executable file
729
tools/testing/selftests/bpf/test_tunnel.sh
Executable file
@@ -0,0 +1,729 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# End-to-end eBPF tunnel test suite
|
||||
# The script tests BPF network tunnel implementation.
|
||||
#
|
||||
# Topology:
|
||||
# ---------
|
||||
# root namespace | at_ns0 namespace
|
||||
# |
|
||||
# ----------- | -----------
|
||||
# | tnl dev | | | tnl dev | (overlay network)
|
||||
# ----------- | -----------
|
||||
# metadata-mode | native-mode
|
||||
# with bpf |
|
||||
# |
|
||||
# ---------- | ----------
|
||||
# | veth1 | --------- | veth0 | (underlay network)
|
||||
# ---------- peer ----------
|
||||
#
|
||||
#
|
||||
# Device Configuration
|
||||
# --------------------
|
||||
# Root namespace with metadata-mode tunnel + BPF
|
||||
# Device names and addresses:
|
||||
# veth1 IP: 172.16.1.200, IPv6: 00::22 (underlay)
|
||||
# tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200 (overlay)
|
||||
#
|
||||
# Namespace at_ns0 with native tunnel
|
||||
# Device names and addresses:
|
||||
# veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay)
|
||||
# tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100 (overlay)
|
||||
#
|
||||
#
|
||||
# End-to-end ping packet flow
|
||||
# ---------------------------
|
||||
# Most of the tests start by namespace creation, device configuration,
|
||||
# then ping the underlay and overlay network. When doing 'ping 10.1.1.100'
|
||||
# from root namespace, the following operations happen:
|
||||
# 1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev.
|
||||
# 2) Tnl device's egress BPF program is triggered and set the tunnel metadata,
|
||||
# with remote_ip=172.16.1.200 and others.
|
||||
# 3) Outer tunnel header is prepended and route the packet to veth1's egress
|
||||
# 4) veth0's ingress queue receive the tunneled packet at namespace at_ns0
|
||||
# 5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet
|
||||
# 6) Forward the packet to the overlay tnl dev
|
||||
|
||||
PING_ARG="-c 3 -w 10 -q"
|
||||
ret=0
|
||||
GREEN='\033[0;92m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
config_device()
|
||||
{
|
||||
ip netns add at_ns0
|
||||
ip link add veth0 type veth peer name veth1
|
||||
ip link set veth0 netns at_ns0
|
||||
ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip link set dev veth1 up mtu 1500
|
||||
ip addr add dev veth1 172.16.1.200/24
|
||||
}
|
||||
|
||||
add_gre_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE key 2 external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ip6gretap_tunnel()
|
||||
{
|
||||
|
||||
# assign ipv6 address
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq flowlabel 0xbcdef key 2 \
|
||||
local ::11 remote ::22
|
||||
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS fc80::100/96
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip addr add dev $DEV fc80::200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_erspan_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
if [ "$1" == "v1" ]; then
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200 \
|
||||
erspan_ver 1 erspan 123
|
||||
else
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200 \
|
||||
erspan_ver 2 erspan_dir egress erspan_hwid 3
|
||||
fi
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ip6erspan_tunnel()
|
||||
{
|
||||
|
||||
# assign ipv6 address
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
if [ "$1" == "v1" ]; then
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local ::11 remote ::22 \
|
||||
erspan_ver 1 erspan 123
|
||||
else
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local ::11 remote ::22 \
|
||||
erspan_ver 2 erspan_dir egress erspan_hwid 7
|
||||
fi
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_vxlan_tunnel()
|
||||
{
|
||||
# Set static ARP entry here because iptables set-mark works
|
||||
# on L3 packet, as a result not applying to ARP packets,
|
||||
# causing errors at get_tunnel_{key/opt}.
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
id 2 dstport 4789 gbp remote 172.16.1.200
|
||||
ip netns exec at_ns0 \
|
||||
ip link set dev $DEV_NS address 52:54:00:d9:01:00 up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 arp -s 10.1.1.200 52:54:00:d9:02:00
|
||||
ip netns exec at_ns0 iptables -A OUTPUT -j MARK --set-mark 0x800FF
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external gbp dstport 4789
|
||||
ip link set dev $DEV address 52:54:00:d9:02:00 up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
arp -s 10.1.1.100 52:54:00:d9:01:00
|
||||
}
|
||||
|
||||
add_ip6vxlan_tunnel()
|
||||
{
|
||||
#ip netns exec at_ns0 ip -4 addr del 172.16.1.100 dev veth0
|
||||
ip netns exec at_ns0 ip -6 addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
#ip -4 addr del 172.16.1.200 dev veth1
|
||||
ip -6 addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE id 22 dstport 4789 \
|
||||
local ::11 remote ::22
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external dstport 4789
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_geneve_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
id 2 dstport 6081 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE dstport 6081 external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ip6geneve_tunnel()
|
||||
{
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE id 22 \
|
||||
remote ::22 # geneve has no local option
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_ipip_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
local 172.16.1.100 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ipip6tnl_tunnel()
|
||||
{
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
local ::11 remote ::22
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
test_gre()
|
||||
{
|
||||
TYPE=gretap
|
||||
DEV_NS=gretap00
|
||||
DEV=gretap11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_gre_tunnel
|
||||
attach_bpf $DEV gre_set_tunnel gre_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6gre()
|
||||
{
|
||||
TYPE=ip6gre
|
||||
DEV_NS=ip6gre00
|
||||
DEV=ip6gre11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
# reuse the ip6gretap function
|
||||
add_ip6gretap_tunnel
|
||||
attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# overlay: ipv4 over ipv6
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
# overlay: ipv6 over ipv6
|
||||
ip netns exec at_ns0 ping6 $PING_ARG fc80::200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6gretap()
|
||||
{
|
||||
TYPE=ip6gretap
|
||||
DEV_NS=ip6gretap00
|
||||
DEV=ip6gretap11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6gretap_tunnel
|
||||
attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# overlay: ipv4 over ipv6
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
# overlay: ipv6 over ipv6
|
||||
ip netns exec at_ns0 ping6 $PING_ARG fc80::200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_erspan()
|
||||
{
|
||||
TYPE=erspan
|
||||
DEV_NS=erspan00
|
||||
DEV=erspan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_erspan_tunnel $1
|
||||
attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6erspan()
|
||||
{
|
||||
TYPE=ip6erspan
|
||||
DEV_NS=ip6erspan00
|
||||
DEV=ip6erspan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6erspan_tunnel $1
|
||||
attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel
|
||||
ping6 $PING_ARG ::11
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_vxlan()
|
||||
{
|
||||
TYPE=vxlan
|
||||
DEV_NS=vxlan00
|
||||
DEV=vxlan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_vxlan_tunnel
|
||||
attach_bpf $DEV vxlan_set_tunnel vxlan_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6vxlan()
|
||||
{
|
||||
TYPE=vxlan
|
||||
DEV_NS=ip6vxlan00
|
||||
DEV=ip6vxlan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6vxlan_tunnel
|
||||
ip link set dev veth1 mtu 1500
|
||||
attach_bpf $DEV ip6vxlan_set_tunnel ip6vxlan_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# ip4 over ip6
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: ip6$TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: ip6$TYPE"${NC}
|
||||
}
|
||||
|
||||
test_geneve()
|
||||
{
|
||||
TYPE=geneve
|
||||
DEV_NS=geneve00
|
||||
DEV=geneve11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_geneve_tunnel
|
||||
attach_bpf $DEV geneve_set_tunnel geneve_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6geneve()
|
||||
{
|
||||
TYPE=geneve
|
||||
DEV_NS=ip6geneve00
|
||||
DEV=ip6geneve11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6geneve_tunnel
|
||||
attach_bpf $DEV ip6geneve_set_tunnel ip6geneve_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: ip6$TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: ip6$TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ipip()
|
||||
{
|
||||
TYPE=ipip
|
||||
DEV_NS=ipip00
|
||||
DEV=ipip11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ipip_tunnel
|
||||
ip link set dev veth1 mtu 1500
|
||||
attach_bpf $DEV ipip_set_tunnel ipip_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ipip6()
|
||||
{
|
||||
TYPE=ip6tnl
|
||||
DEV_NS=ipip6tnl00
|
||||
DEV=ipip6tnl11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ipip6tnl_tunnel
|
||||
ip link set dev veth1 mtu 1500
|
||||
attach_bpf $DEV ipip6_set_tunnel ipip6_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# ip4 over ip6
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
setup_xfrm_tunnel()
|
||||
{
|
||||
auth=0x$(printf '1%.0s' {1..40})
|
||||
enc=0x$(printf '2%.0s' {1..32})
|
||||
spi_in_to_out=0x1
|
||||
spi_out_to_in=0x2
|
||||
# at_ns0 namespace
|
||||
# at_ns0 -> root
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm state add src 172.16.1.100 dst 172.16.1.200 proto esp \
|
||||
spi $spi_in_to_out reqid 1 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm policy add src 10.1.1.100/32 dst 10.1.1.200/32 dir out \
|
||||
tmpl src 172.16.1.100 dst 172.16.1.200 proto esp reqid 1 \
|
||||
mode tunnel
|
||||
# root -> at_ns0
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm state add src 172.16.1.200 dst 172.16.1.100 proto esp \
|
||||
spi $spi_out_to_in reqid 2 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm policy add src 10.1.1.200/32 dst 10.1.1.100/32 dir in \
|
||||
tmpl src 172.16.1.200 dst 172.16.1.100 proto esp reqid 2 \
|
||||
mode tunnel
|
||||
# address & route
|
||||
ip netns exec at_ns0 \
|
||||
ip addr add dev veth0 10.1.1.100/32
|
||||
ip netns exec at_ns0 \
|
||||
ip route add 10.1.1.200 dev veth0 via 172.16.1.200 \
|
||||
src 10.1.1.100
|
||||
|
||||
# root namespace
|
||||
# at_ns0 -> root
|
||||
ip xfrm state add src 172.16.1.100 dst 172.16.1.200 proto esp \
|
||||
spi $spi_in_to_out reqid 1 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip xfrm policy add src 10.1.1.100/32 dst 10.1.1.200/32 dir in \
|
||||
tmpl src 172.16.1.100 dst 172.16.1.200 proto esp reqid 1 \
|
||||
mode tunnel
|
||||
# root -> at_ns0
|
||||
ip xfrm state add src 172.16.1.200 dst 172.16.1.100 proto esp \
|
||||
spi $spi_out_to_in reqid 2 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip xfrm policy add src 10.1.1.200/32 dst 10.1.1.100/32 dir out \
|
||||
tmpl src 172.16.1.200 dst 172.16.1.100 proto esp reqid 2 \
|
||||
mode tunnel
|
||||
# address & route
|
||||
ip addr add dev veth1 10.1.1.200/32
|
||||
ip route add 10.1.1.100 dev veth1 via 172.16.1.100 src 10.1.1.200
|
||||
}
|
||||
|
||||
test_xfrm_tunnel()
|
||||
{
|
||||
config_device
|
||||
#tcpdump -nei veth1 ip &
|
||||
output=$(mktemp)
|
||||
cat /sys/kernel/debug/tracing/trace_pipe | tee $output &
|
||||
setup_xfrm_tunnel
|
||||
tc qdisc add dev veth1 clsact
|
||||
tc filter add dev veth1 proto ip ingress bpf da obj test_tunnel_kern.o \
|
||||
sec xfrm_get_state
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
sleep 1
|
||||
grep "reqid 1" $output
|
||||
check_err $?
|
||||
grep "spi 0x1" $output
|
||||
check_err $?
|
||||
grep "remote ip 0xac100164" $output
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: xfrm tunnel"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: xfrm tunnel"${NC}
|
||||
}
|
||||
|
||||
attach_bpf()
|
||||
{
|
||||
DEV=$1
|
||||
SET=$2
|
||||
GET=$3
|
||||
tc qdisc add dev $DEV clsact
|
||||
tc filter add dev $DEV egress bpf da obj test_tunnel_kern.o sec $SET
|
||||
tc filter add dev $DEV ingress bpf da obj test_tunnel_kern.o sec $GET
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
ip netns delete at_ns0 2> /dev/null
|
||||
ip link del veth1 2> /dev/null
|
||||
ip link del ipip11 2> /dev/null
|
||||
ip link del ipip6tnl11 2> /dev/null
|
||||
ip link del gretap11 2> /dev/null
|
||||
ip link del ip6gre11 2> /dev/null
|
||||
ip link del ip6gretap11 2> /dev/null
|
||||
ip link del vxlan11 2> /dev/null
|
||||
ip link del ip6vxlan11 2> /dev/null
|
||||
ip link del geneve11 2> /dev/null
|
||||
ip link del ip6geneve11 2> /dev/null
|
||||
ip link del erspan11 2> /dev/null
|
||||
ip link del ip6erspan11 2> /dev/null
|
||||
}
|
||||
|
||||
cleanup_exit()
|
||||
{
|
||||
echo "CATCH SIGKILL or SIGINT, cleanup and exit"
|
||||
cleanup
|
||||
exit 0
|
||||
}
|
||||
|
||||
check()
|
||||
{
|
||||
ip link help $1 2>&1 | grep -q "^Usage:"
|
||||
if [ $? -ne 0 ];then
|
||||
echo "SKIP $1: iproute2 not support"
|
||||
cleanup
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
enable_debug()
|
||||
{
|
||||
echo 'file ip_gre.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file ip6_gre.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file vxlan.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file geneve.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file ipip.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
}
|
||||
|
||||
check_err()
|
||||
{
|
||||
if [ $ret -eq 0 ]; then
|
||||
ret=$1
|
||||
fi
|
||||
}
|
||||
|
||||
bpf_tunnel_test()
|
||||
{
|
||||
echo "Testing GRE tunnel..."
|
||||
test_gre
|
||||
echo "Testing IP6GRE tunnel..."
|
||||
test_ip6gre
|
||||
echo "Testing IP6GRETAP tunnel..."
|
||||
test_ip6gretap
|
||||
echo "Testing ERSPAN tunnel..."
|
||||
test_erspan v2
|
||||
echo "Testing IP6ERSPAN tunnel..."
|
||||
test_ip6erspan v2
|
||||
echo "Testing VXLAN tunnel..."
|
||||
test_vxlan
|
||||
echo "Testing IP6VXLAN tunnel..."
|
||||
test_ip6vxlan
|
||||
echo "Testing GENEVE tunnel..."
|
||||
test_geneve
|
||||
echo "Testing IP6GENEVE tunnel..."
|
||||
test_ip6geneve
|
||||
echo "Testing IPIP tunnel..."
|
||||
test_ipip
|
||||
echo "Testing IPIP6 tunnel..."
|
||||
test_ipip6
|
||||
echo "Testing IPSec tunnel..."
|
||||
test_xfrm_tunnel
|
||||
}
|
||||
|
||||
trap cleanup 0 3 6
|
||||
trap cleanup_exit 2 9
|
||||
|
||||
cleanup
|
||||
bpf_tunnel_test
|
||||
|
||||
exit 0
|
713
tools/testing/selftests/bpf/test_tunnel_kern.c
Normal file
713
tools/testing/selftests/bpf/test_tunnel_kern.c
Normal file
@@ -0,0 +1,713 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2016 VMware
|
||||
* Copyright (c) 2016 Facebook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/erspan.h>
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_endian.h"
|
||||
|
||||
#define ERROR(ret) do {\
|
||||
char fmt[] = "ERROR line:%d ret:%d\n";\
|
||||
bpf_trace_printk(fmt, sizeof(fmt), __LINE__, ret); \
|
||||
} while (0)
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
struct geneve_opt {
|
||||
__be16 opt_class;
|
||||
__u8 type;
|
||||
__u8 length:5;
|
||||
__u8 r3:1;
|
||||
__u8 r2:1;
|
||||
__u8 r1:1;
|
||||
__u8 opt_data[8]; /* hard-coded to 8 byte */
|
||||
};
|
||||
|
||||
struct vxlan_metadata {
|
||||
__u32 gbp;
|
||||
};
|
||||
|
||||
SEC("gre_set_tunnel")
|
||||
int _gre_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_ZERO_CSUM_TX | BPF_F_SEQ_NUMBER);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("gre_get_tunnel")
|
||||
int _gre_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
char fmt[] = "key %d remote ip 0x%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), key.tunnel_id, key.remote_ipv4);
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6gretap_set_tunnel")
|
||||
int _ip6gretap_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key;
|
||||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
key.tunnel_label = 0xabcde;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX |
|
||||
BPF_F_SEQ_NUMBER);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6gretap_get_tunnel")
|
||||
int _ip6gretap_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
char fmt[] = "key %d remote ip6 ::%x label %x\n";
|
||||
struct bpf_tunnel_key key;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv6[3], key.tunnel_label);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("erspan_set_tunnel")
|
||||
int _erspan_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key;
|
||||
struct erspan_metadata md;
|
||||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_ZERO_CSUM_TX);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
__builtin_memset(&md, 0, sizeof(md));
|
||||
#ifdef ERSPAN_V1
|
||||
md.version = 1;
|
||||
md.u.index = bpf_htonl(123);
|
||||
#else
|
||||
__u8 direction = 1;
|
||||
__u8 hwid = 7;
|
||||
|
||||
md.version = 2;
|
||||
md.u.md2.dir = direction;
|
||||
md.u.md2.hwid = hwid & 0xf;
|
||||
md.u.md2.hwid_upper = (hwid >> 4) & 0x3;
|
||||
#endif
|
||||
|
||||
ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("erspan_get_tunnel")
|
||||
int _erspan_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
char fmt[] = "key %d remote ip 0x%x erspan version %d\n";
|
||||
struct bpf_tunnel_key key;
|
||||
struct erspan_metadata md;
|
||||
__u32 index;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv4, md.version);
|
||||
|
||||
#ifdef ERSPAN_V1
|
||||
char fmt2[] = "\tindex %x\n";
|
||||
|
||||
index = bpf_ntohl(md.u.index);
|
||||
bpf_trace_printk(fmt2, sizeof(fmt2), index);
|
||||
#else
|
||||
char fmt2[] = "\tdirection %d hwid %x timestamp %u\n";
|
||||
|
||||
bpf_trace_printk(fmt2, sizeof(fmt2),
|
||||
md.u.md2.dir,
|
||||
(md.u.md2.hwid_upper << 4) + md.u.md2.hwid,
|
||||
bpf_ntohl(md.u.md2.timestamp));
|
||||
#endif
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip4ip6erspan_set_tunnel")
|
||||
int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key;
|
||||
struct erspan_metadata md;
|
||||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11);
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
__builtin_memset(&md, 0, sizeof(md));
|
||||
|
||||
#ifdef ERSPAN_V1
|
||||
md.u.index = bpf_htonl(123);
|
||||
md.version = 1;
|
||||
#else
|
||||
__u8 direction = 0;
|
||||
__u8 hwid = 17;
|
||||
|
||||
md.version = 2;
|
||||
md.u.md2.dir = direction;
|
||||
md.u.md2.hwid = hwid & 0xf;
|
||||
md.u.md2.hwid_upper = (hwid >> 4) & 0x3;
|
||||
#endif
|
||||
|
||||
ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip4ip6erspan_get_tunnel")
|
||||
int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
char fmt[] = "ip6erspan get key %d remote ip6 ::%x erspan version %d\n";
|
||||
struct bpf_tunnel_key key;
|
||||
struct erspan_metadata md;
|
||||
__u32 index;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv4, md.version);
|
||||
|
||||
#ifdef ERSPAN_V1
|
||||
char fmt2[] = "\tindex %x\n";
|
||||
|
||||
index = bpf_ntohl(md.u.index);
|
||||
bpf_trace_printk(fmt2, sizeof(fmt2), index);
|
||||
#else
|
||||
char fmt2[] = "\tdirection %d hwid %x timestamp %u\n";
|
||||
|
||||
bpf_trace_printk(fmt2, sizeof(fmt2),
|
||||
md.u.md2.dir,
|
||||
(md.u.md2.hwid_upper << 4) + md.u.md2.hwid,
|
||||
bpf_ntohl(md.u.md2.timestamp));
|
||||
#endif
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("vxlan_set_tunnel")
|
||||
int _vxlan_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
struct vxlan_metadata md;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_ZERO_CSUM_TX);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
md.gbp = 0x800FF; /* Set VXLAN Group Policy extension */
|
||||
ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("vxlan_get_tunnel")
|
||||
int _vxlan_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
struct vxlan_metadata md;
|
||||
char fmt[] = "key %d remote ip 0x%x vxlan gbp 0x%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv4, md.gbp);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6vxlan_set_tunnel")
|
||||
int _ip6vxlan_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key;
|
||||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_id = 22;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6vxlan_get_tunnel")
|
||||
int _ip6vxlan_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
char fmt[] = "key %d remote ip6 ::%x label %x\n";
|
||||
struct bpf_tunnel_key key;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv6[3], key.tunnel_label);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("geneve_set_tunnel")
|
||||
int _geneve_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret, ret2;
|
||||
struct bpf_tunnel_key key;
|
||||
struct geneve_opt gopt;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
__builtin_memset(&gopt, 0x0, sizeof(gopt));
|
||||
gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */
|
||||
gopt.type = 0x08;
|
||||
gopt.r1 = 0;
|
||||
gopt.r2 = 0;
|
||||
gopt.r3 = 0;
|
||||
gopt.length = 2; /* 4-byte multiple */
|
||||
*(int *) &gopt.opt_data = bpf_htonl(0xdeadbeef);
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_ZERO_CSUM_TX);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("geneve_get_tunnel")
|
||||
int _geneve_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
struct geneve_opt gopt;
|
||||
char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv4, gopt.opt_class);
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6geneve_set_tunnel")
|
||||
int _ip6geneve_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key;
|
||||
struct geneve_opt gopt;
|
||||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_id = 22;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
__builtin_memset(&gopt, 0x0, sizeof(gopt));
|
||||
gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */
|
||||
gopt.type = 0x08;
|
||||
gopt.r1 = 0;
|
||||
gopt.r2 = 0;
|
||||
gopt.r3 = 0;
|
||||
gopt.length = 2; /* 4-byte multiple */
|
||||
*(int *) &gopt.opt_data = bpf_htonl(0xfeedbeef);
|
||||
|
||||
ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6geneve_get_tunnel")
|
||||
int _ip6geneve_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n";
|
||||
struct bpf_tunnel_key key;
|
||||
struct geneve_opt gopt;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv4, gopt.opt_class);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ipip_set_tunnel")
|
||||
int _ipip_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key = {};
|
||||
void *data = (void *)(long)skb->data;
|
||||
struct iphdr *iph = data;
|
||||
struct tcphdr *tcp = data + sizeof(*iph);
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
int ret;
|
||||
|
||||
/* single length check */
|
||||
if (data + sizeof(*iph) + sizeof(*tcp) > data_end) {
|
||||
ERROR(1);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
key.tunnel_ttl = 64;
|
||||
if (iph->protocol == IPPROTO_ICMP) {
|
||||
key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
|
||||
} else {
|
||||
if (iph->protocol != IPPROTO_TCP || iph->ihl != 5)
|
||||
return TC_ACT_SHOT;
|
||||
|
||||
if (tcp->dest == bpf_htons(5200))
|
||||
key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
|
||||
else if (tcp->dest == bpf_htons(5201))
|
||||
key.remote_ipv4 = 0xac100165; /* 172.16.1.101 */
|
||||
else
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ipip_get_tunnel")
|
||||
int _ipip_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
char fmt[] = "remote ip 0x%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), key.remote_ipv4);
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ipip6_set_tunnel")
|
||||
int _ipip6_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key = {};
|
||||
void *data = (void *)(long)skb->data;
|
||||
struct iphdr *iph = data;
|
||||
struct tcphdr *tcp = data + sizeof(*iph);
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
int ret;
|
||||
|
||||
/* single length check */
|
||||
if (data + sizeof(*iph) + sizeof(*tcp) > data_end) {
|
||||
ERROR(1);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ipip6_get_tunnel")
|
||||
int _ipip6_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
char fmt[] = "remote ip6 %x::%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]),
|
||||
bpf_htonl(key.remote_ipv6[3]));
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6ip6_set_tunnel")
|
||||
int _ip6ip6_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key = {};
|
||||
void *data = (void *)(long)skb->data;
|
||||
struct ipv6hdr *iph = data;
|
||||
struct tcphdr *tcp = data + sizeof(*iph);
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
int ret;
|
||||
|
||||
/* single length check */
|
||||
if (data + sizeof(*iph) + sizeof(*tcp) > data_end) {
|
||||
ERROR(1);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
key.remote_ipv6[0] = bpf_htonl(0x2401db00);
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
if (iph->nexthdr == 58 /* NEXTHDR_ICMP */) {
|
||||
key.remote_ipv6[3] = bpf_htonl(1);
|
||||
} else {
|
||||
if (iph->nexthdr != 6 /* NEXTHDR_TCP */) {
|
||||
ERROR(iph->nexthdr);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
if (tcp->dest == bpf_htons(5200)) {
|
||||
key.remote_ipv6[3] = bpf_htonl(1);
|
||||
} else if (tcp->dest == bpf_htons(5201)) {
|
||||
key.remote_ipv6[3] = bpf_htonl(2);
|
||||
} else {
|
||||
ERROR(tcp->dest);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6ip6_get_tunnel")
|
||||
int _ip6ip6_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
struct bpf_tunnel_key key;
|
||||
char fmt[] = "remote ip6 %x::%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]),
|
||||
bpf_htonl(key.remote_ipv6[3]));
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("xfrm_get_state")
|
||||
int _xfrm_get_state(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_xfrm_state x;
|
||||
char fmt[] = "reqid %d spi 0x%x remote ip 0x%x\n";
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_xfrm_state(skb, 0, &x, sizeof(x), 0);
|
||||
if (ret < 0)
|
||||
return TC_ACT_OK;
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), x.reqid, bpf_ntohl(x.spi),
|
||||
bpf_ntohl(x.remote_ipv4));
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
@@ -64,6 +64,7 @@ struct bpf_test {
|
||||
struct bpf_insn insns[MAX_INSNS];
|
||||
int fixup_map1[MAX_FIXUPS];
|
||||
int fixup_map2[MAX_FIXUPS];
|
||||
int fixup_map3[MAX_FIXUPS];
|
||||
int fixup_prog[MAX_FIXUPS];
|
||||
int fixup_map_in_map[MAX_FIXUPS];
|
||||
const char *errstr;
|
||||
@@ -88,6 +89,11 @@ struct test_val {
|
||||
int foo[MAX_ENTRIES];
|
||||
};
|
||||
|
||||
struct other_val {
|
||||
long long foo;
|
||||
long long bar;
|
||||
};
|
||||
|
||||
static struct bpf_test tests[] = {
|
||||
{
|
||||
"add+sub+mul",
|
||||
@@ -5593,6 +5599,257 @@ static struct bpf_test tests[] = {
|
||||
.errstr = "R1 min value is negative",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map lookup helper access to map",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 8 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map update helper access to map",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_update_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map update helper access to map: wrong size",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_update_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map1 = { 3 },
|
||||
.fixup_map3 = { 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=8 off=0 size=16",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const imm)",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2,
|
||||
offsetof(struct other_val, bar)),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 9 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const imm): out-of-bound 1",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2,
|
||||
sizeof(struct other_val) - 4),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 9 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=12 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const imm): out-of-bound 2",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 9 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=-4 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const reg)",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_3,
|
||||
offsetof(struct other_val, bar)),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const reg): out-of-bound 1",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_3,
|
||||
sizeof(struct other_val) - 4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=12 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const reg): out-of-bound 2",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_3, -4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=-4 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via variable)",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
|
||||
BPF_JMP_IMM(BPF_JGT, BPF_REG_3,
|
||||
offsetof(struct other_val, bar), 4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 11 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via variable): no max check",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "R2 unbounded memory access, make sure to bounds check any array access into a map",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via variable): wrong max check",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
|
||||
BPF_JMP_IMM(BPF_JGT, BPF_REG_3,
|
||||
offsetof(struct other_val, bar) + 1, 4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 11 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=9 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map element value is preserved across register spilling",
|
||||
.insns = {
|
||||
@@ -11533,6 +11790,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
|
||||
{
|
||||
int *fixup_map1 = test->fixup_map1;
|
||||
int *fixup_map2 = test->fixup_map2;
|
||||
int *fixup_map3 = test->fixup_map3;
|
||||
int *fixup_prog = test->fixup_prog;
|
||||
int *fixup_map_in_map = test->fixup_map_in_map;
|
||||
|
||||
@@ -11556,6 +11814,14 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
|
||||
} while (*fixup_map2);
|
||||
}
|
||||
|
||||
if (*fixup_map3) {
|
||||
map_fds[1] = create_map(sizeof(struct other_val), 1);
|
||||
do {
|
||||
prog[*fixup_map3].imm = map_fds[1];
|
||||
fixup_map3++;
|
||||
} while (*fixup_map3);
|
||||
}
|
||||
|
||||
if (*fixup_prog) {
|
||||
map_fds[2] = create_prog_array();
|
||||
do {
|
||||
|
Reference in New Issue
Block a user