Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b05cd740 authored by William Tu's avatar William Tu Committed by Daniel Borkmann
Browse files

samples/bpf: remove the bpf tunnel testsuite.



Move the testsuite to
selftests/bpf/{test_tunnel_kern.c, test_tunnel.sh}

Signed-off-by: default avatarWilliam Tu <u9012063@gmail.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 933a741e
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -114,7 +114,6 @@ always += sock_flags_kern.o
always += test_probe_write_user_kern.o
always += test_probe_write_user_kern.o
always += trace_output_kern.o
always += trace_output_kern.o
always += tcbpf1_kern.o
always += tcbpf1_kern.o
always += tcbpf2_kern.o
always += tc_l2_redirect_kern.o
always += tc_l2_redirect_kern.o
always += lathist_kern.o
always += lathist_kern.o
always += offwaketime_kern.o
always += offwaketime_kern.o

samples/bpf/tcbpf2_kern.c

deleted100644 → 0
+0 −612
Original line number Original line Diff line number Diff line
/* 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.
 */
#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/ipv6.h>
#include <uapi/linux/in.h>
#include <uapi/linux/tcp.h>
#include <uapi/linux/filter.h>
#include <uapi/linux/pkt_cls.h>
#include <uapi/linux/erspan.h>
#include <net/ipv6.h>
#include "bpf_helpers.h"
#include "bpf_endian.h"

#define _htonl __builtin_bswap32
#define ERROR(ret) do {\
		char fmt[] = "ERROR line:%d ret:%d\n";\
		bpf_trace_printk(fmt, sizeof(fmt), __LINE__, ret); \
	} while(0)

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] = _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] = _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 = 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("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 = 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 = 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("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 == htons(5200))
			key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
		else if (tcp->dest == 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;
	}

	key.remote_ipv6[0] = _htonl(0x2401db00);
	key.tunnel_ttl = 64;

	if (iph->protocol == IPPROTO_ICMP) {
		key.remote_ipv6[3] = _htonl(1);
	} else {
		if (iph->protocol != IPPROTO_TCP || iph->ihl != 5) {
			ERROR(iph->protocol);
			return TC_ACT_SHOT;
		}

		if (tcp->dest == htons(5200)) {
			key.remote_ipv6[3] = _htonl(1);
		} else if (tcp->dest == htons(5201)) {
			key.remote_ipv6[3] = _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("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), _htonl(key.remote_ipv6[0]),
			 _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] = _htonl(0x2401db00);
	key.tunnel_ttl = 64;

	if (iph->nexthdr == NEXTHDR_ICMP) {
		key.remote_ipv6[3] = _htonl(1);
	} else {
		if (iph->nexthdr != NEXTHDR_TCP) {
			ERROR(iph->nexthdr);
			return TC_ACT_SHOT;
		}

		if (tcp->dest == htons(5200)) {
			key.remote_ipv6[3] = _htonl(1);
		} else if (tcp->dest == htons(5201)) {
			key.remote_ipv6[3] = _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), _htonl(key.remote_ipv6[0]),
			 _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";

samples/bpf/test_tunnel_bpf.sh

deleted100755 → 0
+0 −390
Original line number Original line Diff line number Diff line
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# In Namespace 0 (at_ns0) using native tunnel
# Overlay IP: 10.1.1.100
# local 192.16.1.100 remote 192.16.1.200
# veth0 IP: 172.16.1.100, tunnel dev <type>00

# Out of Namespace using BPF set/get on lwtunnel
# Overlay IP: 10.1.1.200
# local 172.16.1.200 remote 172.16.1.100
# veth1 IP: 172.16.1.200, tunnel dev <type>11

function 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
}

function add_gre_tunnel {
	# in 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

	# out of 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
}

function 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

	# in 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

	# out of 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
}

function add_erspan_tunnel {
	# in 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

	# out of 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
}

function 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

	# in 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

	# out of 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
}

function 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}.

	# in 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

	# out of 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
}

function add_geneve_tunnel {
	# in 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

	# out of 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
}

function add_ipip_tunnel {
	# in 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

	# out of 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
}

function 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
	# in namespace
	# in -> out
	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
	# out -> in
	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

	# out of namespace
	# in -> out
	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
	# out -> in
	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
}

function attach_bpf {
	DEV=$1
	SET_TUNNEL=$2
	GET_TUNNEL=$3
	tc qdisc add dev $DEV clsact
	tc filter add dev $DEV egress bpf da obj tcbpf2_kern.o sec $SET_TUNNEL
	tc filter add dev $DEV ingress bpf da obj tcbpf2_kern.o sec $GET_TUNNEL
}

function test_gre {
	TYPE=gretap
	DEV_NS=gretap00
	DEV=gretap11
	config_device
	add_gre_tunnel
	attach_bpf $DEV gre_set_tunnel gre_get_tunnel
	ping -c 1 10.1.1.100
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	cleanup
}

function test_ip6gre {
	TYPE=ip6gre
	DEV_NS=ip6gre00
	DEV=ip6gre11
	config_device
	# reuse the ip6gretap function
	add_ip6gretap_tunnel
	attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
	# underlay
	ping6 -c 4 ::11
	# overlay: ipv4 over ipv6
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	ping -c 1 10.1.1.100
	# overlay: ipv6 over ipv6
	ip netns exec at_ns0 ping6 -c 1 fc80::200
	cleanup
}

function test_ip6gretap {
	TYPE=ip6gretap
	DEV_NS=ip6gretap00
	DEV=ip6gretap11
	config_device
	add_ip6gretap_tunnel
	attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
	# underlay
	ping6 -c 4 ::11
	# overlay: ipv4 over ipv6
	ip netns exec at_ns0 ping -i .2 -c 1 10.1.1.200
	ping -c 1 10.1.1.100
	# overlay: ipv6 over ipv6
	ip netns exec at_ns0 ping6 -c 1 fc80::200
	cleanup
}

function test_erspan {
	TYPE=erspan
	DEV_NS=erspan00
	DEV=erspan11
	config_device
	add_erspan_tunnel $1
	attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel
	ping -c 1 10.1.1.100
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	cleanup
}

function test_ip6erspan {
	TYPE=ip6erspan
	DEV_NS=ip6erspan00
	DEV=ip6erspan11
	config_device
	add_ip6erspan_tunnel $1
	attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel
	ping6 -c 3 ::11
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	cleanup
}

function test_vxlan {
	TYPE=vxlan
	DEV_NS=vxlan00
	DEV=vxlan11
	config_device
	add_vxlan_tunnel
	attach_bpf $DEV vxlan_set_tunnel vxlan_get_tunnel
	ping -c 1 10.1.1.100
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	cleanup
}

function test_geneve {
	TYPE=geneve
	DEV_NS=geneve00
	DEV=geneve11
	config_device
	add_geneve_tunnel
	attach_bpf $DEV geneve_set_tunnel geneve_get_tunnel
	ping -c 1 10.1.1.100
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	cleanup
}

function test_ipip {
	TYPE=ipip
	DEV_NS=ipip00
	DEV=ipip11
	config_device
	tcpdump -nei veth1 &
	cat /sys/kernel/debug/tracing/trace_pipe &
	add_ipip_tunnel
	ethtool -K veth1 gso off gro off rx off tx off
	ip link set dev veth1 mtu 1500
	attach_bpf $DEV ipip_set_tunnel ipip_get_tunnel
	ping -c 1 10.1.1.100
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	ip netns exec at_ns0 iperf -sD -p 5200 > /dev/null
	sleep 0.2
	iperf -c 10.1.1.100 -n 5k -p 5200
	cleanup
}

function 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 tcbpf2_kern.o \
		sec xfrm_get_state
	ip netns exec at_ns0 ping -c 1 10.1.1.200
	grep "reqid 1" $output
	grep "spi 0x1" $output
	grep "remote ip 0xac100164" $output
	cleanup
}

function cleanup {
	set +ex
	pkill iperf
	ip netns delete at_ns0
	ip link del veth1
	ip link del ipip11
	ip link del gretap11
	ip link del ip6gre11
	ip link del ip6gretap11
	ip link del vxlan11
	ip link del geneve11
	ip link del erspan11
	ip link del ip6erspan11
	ip x s flush
	ip x p flush
	pkill tcpdump
	pkill cat
	set -ex
}

trap cleanup 0 2 3 6 9
cleanup
echo "Testing GRE tunnel..."
test_gre
echo "Testing IP6GRE tunnel..."
test_ip6gre
echo "Testing IP6GRETAP tunnel..."
test_ip6gretap
echo "Testing ERSPAN tunnel..."
test_erspan v1
test_erspan v2
echo "Testing IP6ERSPAN tunnel..."
test_ip6erspan v1
test_ip6erspan v2
echo "Testing VXLAN tunnel..."
test_vxlan
echo "Testing GENEVE tunnel..."
test_geneve
echo "Testing IPIP tunnel..."
test_ipip
echo "Testing IPSec tunnel..."
test_xfrm_tunnel
echo "*** PASS ***"