This patch adds a sample/selftest that covers BPF_LWT_ENCAP_IP option added in the first patch in the series.
Signed-off-by: Peter Oskolkov <p...@google.com> --- tools/testing/selftests/bpf/Makefile | 5 +- .../testing/selftests/bpf/test_lwt_ip_encap.c | 65 ++++++++++ .../selftests/bpf/test_lwt_ip_encap.sh | 114 ++++++++++++++++++ 3 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/test_lwt_ip_encap.c create mode 100755 tools/testing/selftests/bpf/test_lwt_ip_encap.sh diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 73aa6d8f4a2f..044fcdbc9864 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -39,7 +39,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o \ test_sk_lookup_kern.o test_xdp_vlan.o test_queue_map.o test_stack_map.o \ - xdp_dummy.o test_map_in_map.o + xdp_dummy.o test_map_in_map.o test_lwt_ip_encap.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ @@ -53,7 +53,8 @@ TEST_PROGS := test_kmod.sh \ test_lirc_mode2.sh \ test_skb_cgroup_id.sh \ test_flow_dissector.sh \ - test_xdp_vlan.sh + test_xdp_vlan.sh \ + test_lwt_ip_encap.sh TEST_PROGS_EXTENDED := with_addr.sh diff --git a/tools/testing/selftests/bpf/test_lwt_ip_encap.c b/tools/testing/selftests/bpf/test_lwt_ip_encap.c new file mode 100644 index 000000000000..967db922dcc6 --- /dev/null +++ b/tools/testing/selftests/bpf/test_lwt_ip_encap.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/bpf.h> +#include <string.h> +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define BPF_LWT_ENCAP_IP 2 + +struct iphdr { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + __u8 ihl:4, + version:4; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + __u8 version:4, + ihl:4; +#else +#error "Fix your compiler's __BYTE_ORDER__?!" +#endif + __u8 tos; + __be16 tot_len; + __be16 id; + __be16 frag_off; + __u8 ttl; + __u8 protocol; + __sum16 check; + __be32 saddr; + __be32 daddr; +}; + +struct grehdr { + __be16 flags; + __be16 protocol; +}; + +SEC("encap_gre") +int bpf_lwt_encap_gre(struct __sk_buff *skb) +{ + char encap_header[24]; + int err; + struct iphdr *iphdr = (struct iphdr *)encap_header; + struct grehdr *greh = (struct grehdr *)(encap_header + sizeof(struct iphdr)); + + memset(encap_header, 0, sizeof(encap_header)); + + iphdr->ihl = 5; + iphdr->version = 4; + iphdr->tos = 0; + iphdr->ttl = 0x40; + iphdr->protocol = 47; /* IPPROTO_GRE */ + iphdr->saddr = 0x640110ac; /* 172.16.1.100 */ + iphdr->daddr = 0x640310ac; /* 172.16.5.100 */ + iphdr->check = 0; + iphdr->tot_len = bpf_htons(skb->len + sizeof(encap_header)); + + greh->protocol = bpf_htons(0x800); + + err = bpf_lwt_push_encap(skb, BPF_LWT_ENCAP_IP, (void *)encap_header, + sizeof(encap_header)); + if (err) + return BPF_DROP; + + return BPF_OK; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_lwt_ip_encap.sh b/tools/testing/selftests/bpf/test_lwt_ip_encap.sh new file mode 100755 index 000000000000..4c32b754bf96 --- /dev/null +++ b/tools/testing/selftests/bpf/test_lwt_ip_encap.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Setup: +# - create VETH1/VETH2 veth +# - VETH1 gets IP_SRC +# - create netns NS +# - move VETH2 to NS, add IP_DST +# - in NS, create gre tunnel GREDEV, add IP_GRE +# - in NS, configure GREDEV to route to IP_DST from IP_SRC +# - configure route to IP_GRE via VETH1 +# (note: there is no route to IP_DST from root/init ns) +# +# Test: +# - listen on IP_DST +# - send a packet to IP_DST: the listener does not get it +# - add LWT_XMIT bpf to IP_DST that gre-encaps all packets to IP_GRE +# - send a packet to IP_DST: the listener gets it + + +# set -x # debug ON +set +x # debug OFF +set -e # exit on error + +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + echo "FAIL" + exit 1 +fi + +readonly NS="ns-ip-encap-$(mktemp -u XXXXXX)" +readonly OUT=$(mktemp /tmp/test_lwt_ip_incap.XXXXXX) + +readonly NET_SRC="172.16.1.0" + +readonly IP_SRC="172.16.1.100" +readonly IP_DST="172.16.2.100" +readonly IP_GRE="172.16.3.100" + +readonly PORT=5555 +readonly MSG="foo_bar" + +PID1=0 +PID2=0 + +setup() { + ip link add veth1 type veth peer name veth2 + + ip netns add "${NS}" + ip link set veth2 netns ${NS} + + ip link set dev veth1 up + ip -netns ${NS} link set dev veth2 up + + ip addr add dev veth1 ${IP_SRC}/24 + ip -netns ${NS} addr add dev veth2 ${IP_DST}/24 + + ip -netns ${NS} tunnel add gre_dev mode gre remote ${IP_SRC} local ${IP_GRE} ttl 255 + ip -netns ${NS} link set gre_dev up + ip -netns ${NS} addr add ${IP_GRE} dev gre_dev + ip -netns ${NS} route add ${NET_SRC}/24 dev gre_dev + + ip route add ${IP_GRE}/32 dev veth1 +} + +cleanup() { + ip link del veth1 + ip netns del ${NS} + if [ $PID1 -ne 0 ] ; then kill $PID1 ; fi + if [ $PID2 -ne 0 ] ; then kill $PID2 ; fi + rm $OUT +} + +trap cleanup EXIT +setup + +# start the listener +ip netns exec ${NS} nc -ul ${IP_DST} $PORT > $OUT & +PID1=$! +usleep 100000 + +# send a packet +echo -ne "${MSG}" | nc -u ${IP_DST} $PORT & +PID2=$! +usleep 1000000 +kill $PID2 +PID2=0 + +# confirm the packet was not delivered +if [ "$(<$OUT)" != "" ]; then + echo "FAIL: unexpected packet" + exit 1 +fi + +# install an lwt/bpf encap prog +ip route add ${IP_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre dev veth1 +usleep 100000 + +# send a packet +echo -ne "${MSG}" | nc -u ${IP_DST} $PORT & +PID2=$! +usleep 1000000 +kill $PID2 +PID2=0 +kill $PID1 +PID1=0 + +if [ "$(<$OUT)" != "$MSG" ]; then + echo "FAIL" + exit 1 +fi + +echo "PASS" + -- 2.20.0.rc0.387.gc7a69e6b6c-goog