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

Reply via email to