xref: /openbmc/linux/tools/testing/selftests/bpf/prog_tests/test_tunnel.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
11ee7efd4SKaixi Fan // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
21ee7efd4SKaixi Fan 
31ee7efd4SKaixi Fan /*
41ee7efd4SKaixi Fan  * End-to-end eBPF tunnel test suite
51ee7efd4SKaixi Fan  *   The file tests BPF network tunnel implementation.
61ee7efd4SKaixi Fan  *
71ee7efd4SKaixi Fan  * Topology:
81ee7efd4SKaixi Fan  * ---------
91ee7efd4SKaixi Fan  *     root namespace   |     at_ns0 namespace
101ee7efd4SKaixi Fan  *                       |
111ee7efd4SKaixi Fan  *       -----------     |     -----------
121ee7efd4SKaixi Fan  *       | tnl dev |     |     | tnl dev |  (overlay network)
131ee7efd4SKaixi Fan  *       -----------     |     -----------
141ee7efd4SKaixi Fan  *       metadata-mode   |     metadata-mode
151ee7efd4SKaixi Fan  *        with bpf       |       with bpf
161ee7efd4SKaixi Fan  *                       |
171ee7efd4SKaixi Fan  *       ----------      |     ----------
181ee7efd4SKaixi Fan  *       |  veth1  | --------- |  veth0  |  (underlay network)
191ee7efd4SKaixi Fan  *       ----------    peer    ----------
201ee7efd4SKaixi Fan  *
211ee7efd4SKaixi Fan  *
221ee7efd4SKaixi Fan  *  Device Configuration
231ee7efd4SKaixi Fan  *  --------------------
241ee7efd4SKaixi Fan  *  root namespace with metadata-mode tunnel + BPF
251ee7efd4SKaixi Fan  *  Device names and addresses:
261ee7efd4SKaixi Fan  *	veth1 IP 1: 172.16.1.200, IPv6: 00::22 (underlay)
271ee7efd4SKaixi Fan  *		IP 2: 172.16.1.20, IPv6: 00::bb (underlay)
281ee7efd4SKaixi Fan  *	tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200, IPv6: 1::22 (overlay)
291ee7efd4SKaixi Fan  *
301ee7efd4SKaixi Fan  *  Namespace at_ns0 with native tunnel
311ee7efd4SKaixi Fan  *  Device names and addresses:
321ee7efd4SKaixi Fan  *	veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay)
331ee7efd4SKaixi Fan  *	tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100, IPv6: 1::11 (overlay)
341ee7efd4SKaixi Fan  *
351ee7efd4SKaixi Fan  *
361ee7efd4SKaixi Fan  * End-to-end ping packet flow
371ee7efd4SKaixi Fan  *  ---------------------------
381ee7efd4SKaixi Fan  *  Most of the tests start by namespace creation, device configuration,
391ee7efd4SKaixi Fan  *  then ping the underlay and overlay network.  When doing 'ping 10.1.1.100'
401ee7efd4SKaixi Fan  *  from root namespace, the following operations happen:
411ee7efd4SKaixi Fan  *  1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev.
421ee7efd4SKaixi Fan  *  2) Tnl device's egress BPF program is triggered and set the tunnel metadata,
431ee7efd4SKaixi Fan  *     with local_ip=172.16.1.200, remote_ip=172.16.1.100. BPF program choose
441ee7efd4SKaixi Fan  *     the primary or secondary ip of veth1 as the local ip of tunnel. The
451ee7efd4SKaixi Fan  *     choice is made based on the value of bpf map local_ip_map.
461ee7efd4SKaixi Fan  *  3) Outer tunnel header is prepended and route the packet to veth1's egress.
471ee7efd4SKaixi Fan  *  4) veth0's ingress queue receive the tunneled packet at namespace at_ns0.
481ee7efd4SKaixi Fan  *  5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet.
491ee7efd4SKaixi Fan  *  6) Forward the packet to the overlay tnl dev.
501ee7efd4SKaixi Fan  */
511ee7efd4SKaixi Fan 
521ee7efd4SKaixi Fan #include <arpa/inet.h>
531ee7efd4SKaixi Fan #include <linux/if_tun.h>
541ee7efd4SKaixi Fan #include <linux/limits.h>
551ee7efd4SKaixi Fan #include <linux/sysctl.h>
561ee7efd4SKaixi Fan #include <linux/time_types.h>
571ee7efd4SKaixi Fan #include <linux/net_tstamp.h>
581ee7efd4SKaixi Fan #include <net/if.h>
591ee7efd4SKaixi Fan #include <stdbool.h>
601ee7efd4SKaixi Fan #include <stdio.h>
611ee7efd4SKaixi Fan #include <sys/stat.h>
621ee7efd4SKaixi Fan #include <unistd.h>
631ee7efd4SKaixi Fan 
641ee7efd4SKaixi Fan #include "test_progs.h"
651ee7efd4SKaixi Fan #include "network_helpers.h"
661ee7efd4SKaixi Fan #include "test_tunnel_kern.skel.h"
671ee7efd4SKaixi Fan 
681ee7efd4SKaixi Fan #define IP4_ADDR_VETH0 "172.16.1.100"
691ee7efd4SKaixi Fan #define IP4_ADDR1_VETH1 "172.16.1.200"
701ee7efd4SKaixi Fan #define IP4_ADDR2_VETH1 "172.16.1.20"
711ee7efd4SKaixi Fan #define IP4_ADDR_TUNL_DEV0 "10.1.1.100"
721ee7efd4SKaixi Fan #define IP4_ADDR_TUNL_DEV1 "10.1.1.200"
731ee7efd4SKaixi Fan 
741ee7efd4SKaixi Fan #define IP6_ADDR_VETH0 "::11"
751ee7efd4SKaixi Fan #define IP6_ADDR1_VETH1 "::22"
761ee7efd4SKaixi Fan #define IP6_ADDR2_VETH1 "::bb"
771ee7efd4SKaixi Fan 
781ee7efd4SKaixi Fan #define IP4_ADDR1_HEX_VETH1 0xac1001c8
791ee7efd4SKaixi Fan #define IP4_ADDR2_HEX_VETH1 0xac100114
801ee7efd4SKaixi Fan #define IP6_ADDR1_HEX_VETH1 0x22
811ee7efd4SKaixi Fan #define IP6_ADDR2_HEX_VETH1 0xbb
821ee7efd4SKaixi Fan 
831ee7efd4SKaixi Fan #define MAC_TUNL_DEV0 "52:54:00:d9:01:00"
841ee7efd4SKaixi Fan #define MAC_TUNL_DEV1 "52:54:00:d9:02:00"
851115169fSPaul Chaignon #define MAC_VETH1 "52:54:00:d9:03:00"
861ee7efd4SKaixi Fan 
871ee7efd4SKaixi Fan #define VXLAN_TUNL_DEV0 "vxlan00"
881ee7efd4SKaixi Fan #define VXLAN_TUNL_DEV1 "vxlan11"
891ee7efd4SKaixi Fan #define IP6VXLAN_TUNL_DEV0 "ip6vxlan00"
901ee7efd4SKaixi Fan #define IP6VXLAN_TUNL_DEV1 "ip6vxlan11"
911ee7efd4SKaixi Fan 
92*d9688f89SChristian Ehrig #define IPIP_TUNL_DEV0 "ipip00"
93*d9688f89SChristian Ehrig #define IPIP_TUNL_DEV1 "ipip11"
94*d9688f89SChristian Ehrig 
951ee7efd4SKaixi Fan #define PING_ARGS "-i 0.01 -c 3 -w 10 -q"
961ee7efd4SKaixi Fan 
config_device(void)971ee7efd4SKaixi Fan static int config_device(void)
981ee7efd4SKaixi Fan {
99b61987d3SHangbin Liu 	SYS(fail, "ip netns add at_ns0");
100b61987d3SHangbin Liu 	SYS(fail, "ip link add veth0 address " MAC_VETH1 " type veth peer name veth1");
101b61987d3SHangbin Liu 	SYS(fail, "ip link set veth0 netns at_ns0");
102b61987d3SHangbin Liu 	SYS(fail, "ip addr add " IP4_ADDR1_VETH1 "/24 dev veth1");
103b61987d3SHangbin Liu 	SYS(fail, "ip link set dev veth1 up mtu 1500");
104b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip addr add " IP4_ADDR_VETH0 "/24 dev veth0");
105b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up mtu 1500");
1061ee7efd4SKaixi Fan 
1071ee7efd4SKaixi Fan 	return 0;
1081ee7efd4SKaixi Fan fail:
1091ee7efd4SKaixi Fan 	return -1;
1101ee7efd4SKaixi Fan }
1111ee7efd4SKaixi Fan 
cleanup(void)1121ee7efd4SKaixi Fan static void cleanup(void)
1131ee7efd4SKaixi Fan {
1141ee7efd4SKaixi Fan 	SYS_NOFAIL("test -f /var/run/netns/at_ns0 && ip netns delete at_ns0");
1151ee7efd4SKaixi Fan 	SYS_NOFAIL("ip link del veth1 2> /dev/null");
1161ee7efd4SKaixi Fan 	SYS_NOFAIL("ip link del %s 2> /dev/null", VXLAN_TUNL_DEV1);
1171ee7efd4SKaixi Fan 	SYS_NOFAIL("ip link del %s 2> /dev/null", IP6VXLAN_TUNL_DEV1);
1181ee7efd4SKaixi Fan }
1191ee7efd4SKaixi Fan 
add_vxlan_tunnel(void)1201ee7efd4SKaixi Fan static int add_vxlan_tunnel(void)
1211ee7efd4SKaixi Fan {
1221ee7efd4SKaixi Fan 	/* at_ns0 namespace */
123b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external gbp dstport 4789",
1241ee7efd4SKaixi Fan 	    VXLAN_TUNL_DEV0);
125b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up",
1261ee7efd4SKaixi Fan 	    VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
127b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24",
1281ee7efd4SKaixi Fan 	    VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
129b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev %s",
1301ee7efd4SKaixi Fan 	    IP4_ADDR_TUNL_DEV1, MAC_TUNL_DEV1, VXLAN_TUNL_DEV0);
131b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev veth0",
1321115169fSPaul Chaignon 	    IP4_ADDR2_VETH1, MAC_VETH1);
1331ee7efd4SKaixi Fan 
1341ee7efd4SKaixi Fan 	/* root namespace */
135b61987d3SHangbin Liu 	SYS(fail, "ip link add dev %s type vxlan external gbp dstport 4789",
1361ee7efd4SKaixi Fan 	    VXLAN_TUNL_DEV1);
137b61987d3SHangbin Liu 	SYS(fail, "ip link set dev %s address %s up", VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
138b61987d3SHangbin Liu 	SYS(fail, "ip addr add dev %s %s/24", VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
139b61987d3SHangbin Liu 	SYS(fail, "ip neigh add %s lladdr %s dev %s",
1401ee7efd4SKaixi Fan 	    IP4_ADDR_TUNL_DEV0, MAC_TUNL_DEV0, VXLAN_TUNL_DEV1);
1411ee7efd4SKaixi Fan 
1421ee7efd4SKaixi Fan 	return 0;
1431ee7efd4SKaixi Fan fail:
1441ee7efd4SKaixi Fan 	return -1;
1451ee7efd4SKaixi Fan }
1461ee7efd4SKaixi Fan 
delete_vxlan_tunnel(void)1471ee7efd4SKaixi Fan static void delete_vxlan_tunnel(void)
1481ee7efd4SKaixi Fan {
1491ee7efd4SKaixi Fan 	SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
1501ee7efd4SKaixi Fan 		   VXLAN_TUNL_DEV0);
1511ee7efd4SKaixi Fan 	SYS_NOFAIL("ip link delete dev %s", VXLAN_TUNL_DEV1);
1521ee7efd4SKaixi Fan }
1531ee7efd4SKaixi Fan 
add_ip6vxlan_tunnel(void)1541ee7efd4SKaixi Fan static int add_ip6vxlan_tunnel(void)
1551ee7efd4SKaixi Fan {
156b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip -6 addr add %s/96 dev veth0",
1571ee7efd4SKaixi Fan 	    IP6_ADDR_VETH0);
158b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up");
159b61987d3SHangbin Liu 	SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR1_VETH1);
160b61987d3SHangbin Liu 	SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR2_VETH1);
161b61987d3SHangbin Liu 	SYS(fail, "ip link set dev veth1 up");
1621ee7efd4SKaixi Fan 
1631ee7efd4SKaixi Fan 	/* at_ns0 namespace */
164b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external dstport 4789",
1651ee7efd4SKaixi Fan 	    IP6VXLAN_TUNL_DEV0);
166b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24",
1671ee7efd4SKaixi Fan 	    IP6VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
168b61987d3SHangbin Liu 	SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up",
1691ee7efd4SKaixi Fan 	    IP6VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
1701ee7efd4SKaixi Fan 
1711ee7efd4SKaixi Fan 	/* root namespace */
172b61987d3SHangbin Liu 	SYS(fail, "ip link add dev %s type vxlan external dstport 4789",
1731ee7efd4SKaixi Fan 	    IP6VXLAN_TUNL_DEV1);
174b61987d3SHangbin Liu 	SYS(fail, "ip addr add dev %s %s/24", IP6VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
175b61987d3SHangbin Liu 	SYS(fail, "ip link set dev %s address %s up",
1761ee7efd4SKaixi Fan 	    IP6VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
1771ee7efd4SKaixi Fan 
1781ee7efd4SKaixi Fan 	return 0;
1791ee7efd4SKaixi Fan fail:
1801ee7efd4SKaixi Fan 	return -1;
1811ee7efd4SKaixi Fan }
1821ee7efd4SKaixi Fan 
delete_ip6vxlan_tunnel(void)1831ee7efd4SKaixi Fan static void delete_ip6vxlan_tunnel(void)
1841ee7efd4SKaixi Fan {
1851ee7efd4SKaixi Fan 	SYS_NOFAIL("ip netns exec at_ns0 ip -6 addr delete %s/96 dev veth0",
1861ee7efd4SKaixi Fan 		   IP6_ADDR_VETH0);
1871ee7efd4SKaixi Fan 	SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR1_VETH1);
1881ee7efd4SKaixi Fan 	SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR2_VETH1);
1891ee7efd4SKaixi Fan 	SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
1901ee7efd4SKaixi Fan 		   IP6VXLAN_TUNL_DEV0);
1911ee7efd4SKaixi Fan 	SYS_NOFAIL("ip link delete dev %s", IP6VXLAN_TUNL_DEV1);
1921ee7efd4SKaixi Fan }
1931ee7efd4SKaixi Fan 
194*d9688f89SChristian Ehrig enum ipip_encap {
195*d9688f89SChristian Ehrig 	NONE	= 0,
196*d9688f89SChristian Ehrig 	FOU	= 1,
197*d9688f89SChristian Ehrig 	GUE	= 2,
198*d9688f89SChristian Ehrig };
199*d9688f89SChristian Ehrig 
set_ipip_encap(const char * ipproto,const char * type)200*d9688f89SChristian Ehrig static int set_ipip_encap(const char *ipproto, const char *type)
201*d9688f89SChristian Ehrig {
202*d9688f89SChristian Ehrig 	SYS(fail, "ip -n at_ns0 fou add port 5555 %s", ipproto);
203*d9688f89SChristian Ehrig 	SYS(fail, "ip -n at_ns0 link set dev %s type ipip encap %s",
204*d9688f89SChristian Ehrig 	    IPIP_TUNL_DEV0, type);
205*d9688f89SChristian Ehrig 	SYS(fail, "ip -n at_ns0 link set dev %s type ipip encap-dport 5555",
206*d9688f89SChristian Ehrig 	    IPIP_TUNL_DEV0);
207*d9688f89SChristian Ehrig 
208*d9688f89SChristian Ehrig 	return 0;
209*d9688f89SChristian Ehrig fail:
210*d9688f89SChristian Ehrig 	return -1;
211*d9688f89SChristian Ehrig }
212*d9688f89SChristian Ehrig 
add_ipip_tunnel(enum ipip_encap encap)213*d9688f89SChristian Ehrig static int add_ipip_tunnel(enum ipip_encap encap)
214*d9688f89SChristian Ehrig {
215*d9688f89SChristian Ehrig 	int err;
216*d9688f89SChristian Ehrig 	const char *ipproto, *type;
217*d9688f89SChristian Ehrig 
218*d9688f89SChristian Ehrig 	switch (encap) {
219*d9688f89SChristian Ehrig 	case FOU:
220*d9688f89SChristian Ehrig 		ipproto = "ipproto 4";
221*d9688f89SChristian Ehrig 		type = "fou";
222*d9688f89SChristian Ehrig 		break;
223*d9688f89SChristian Ehrig 	case GUE:
224*d9688f89SChristian Ehrig 		ipproto = "gue";
225*d9688f89SChristian Ehrig 		type = ipproto;
226*d9688f89SChristian Ehrig 		break;
227*d9688f89SChristian Ehrig 	default:
228*d9688f89SChristian Ehrig 		ipproto = NULL;
229*d9688f89SChristian Ehrig 		type = ipproto;
230*d9688f89SChristian Ehrig 	}
231*d9688f89SChristian Ehrig 
232*d9688f89SChristian Ehrig 	/* at_ns0 namespace */
233*d9688f89SChristian Ehrig 	SYS(fail, "ip -n at_ns0 link add dev %s type ipip local %s remote %s",
234*d9688f89SChristian Ehrig 	    IPIP_TUNL_DEV0, IP4_ADDR_VETH0, IP4_ADDR1_VETH1);
235*d9688f89SChristian Ehrig 
236*d9688f89SChristian Ehrig 	if (type && ipproto) {
237*d9688f89SChristian Ehrig 		err = set_ipip_encap(ipproto, type);
238*d9688f89SChristian Ehrig 		if (!ASSERT_OK(err, "set_ipip_encap"))
239*d9688f89SChristian Ehrig 			goto fail;
240*d9688f89SChristian Ehrig 	}
241*d9688f89SChristian Ehrig 
242*d9688f89SChristian Ehrig 	SYS(fail, "ip -n at_ns0 link set dev %s up", IPIP_TUNL_DEV0);
243*d9688f89SChristian Ehrig 	SYS(fail, "ip -n at_ns0 addr add dev %s %s/24",
244*d9688f89SChristian Ehrig 	    IPIP_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
245*d9688f89SChristian Ehrig 
246*d9688f89SChristian Ehrig 	/* root namespace */
247*d9688f89SChristian Ehrig 	if (type && ipproto)
248*d9688f89SChristian Ehrig 		SYS(fail, "ip fou add port 5555 %s", ipproto);
249*d9688f89SChristian Ehrig 	SYS(fail, "ip link add dev %s type ipip external", IPIP_TUNL_DEV1);
250*d9688f89SChristian Ehrig 	SYS(fail, "ip link set dev %s up", IPIP_TUNL_DEV1);
251*d9688f89SChristian Ehrig 	SYS(fail, "ip addr add dev %s %s/24", IPIP_TUNL_DEV1,
252*d9688f89SChristian Ehrig 	    IP4_ADDR_TUNL_DEV1);
253*d9688f89SChristian Ehrig 
254*d9688f89SChristian Ehrig 	return 0;
255*d9688f89SChristian Ehrig fail:
256*d9688f89SChristian Ehrig 	return -1;
257*d9688f89SChristian Ehrig }
258*d9688f89SChristian Ehrig 
delete_ipip_tunnel(void)259*d9688f89SChristian Ehrig static void delete_ipip_tunnel(void)
260*d9688f89SChristian Ehrig {
261*d9688f89SChristian Ehrig 	SYS_NOFAIL("ip -n at_ns0 link delete dev %s", IPIP_TUNL_DEV0);
262*d9688f89SChristian Ehrig 	SYS_NOFAIL("ip -n at_ns0 fou del port 5555 2> /dev/null");
263*d9688f89SChristian Ehrig 	SYS_NOFAIL("ip link delete dev %s", IPIP_TUNL_DEV1);
264*d9688f89SChristian Ehrig 	SYS_NOFAIL("ip fou del port 5555 2> /dev/null");
265*d9688f89SChristian Ehrig }
266*d9688f89SChristian Ehrig 
test_ping(int family,const char * addr)2671ee7efd4SKaixi Fan static int test_ping(int family, const char *addr)
2681ee7efd4SKaixi Fan {
269b61987d3SHangbin Liu 	SYS(fail, "%s %s %s > /dev/null", ping_command(family), PING_ARGS, addr);
2701ee7efd4SKaixi Fan 	return 0;
2711ee7efd4SKaixi Fan fail:
2721ee7efd4SKaixi Fan 	return -1;
2731ee7efd4SKaixi Fan }
2741ee7efd4SKaixi Fan 
attach_tc_prog(struct bpf_tc_hook * hook,int igr_fd,int egr_fd)2751ee7efd4SKaixi Fan static int attach_tc_prog(struct bpf_tc_hook *hook, int igr_fd, int egr_fd)
2761ee7efd4SKaixi Fan {
2771ee7efd4SKaixi Fan 	DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1,
2781ee7efd4SKaixi Fan 			    .priority = 1, .prog_fd = igr_fd);
2791ee7efd4SKaixi Fan 	DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1,
2801ee7efd4SKaixi Fan 			    .priority = 1, .prog_fd = egr_fd);
2811ee7efd4SKaixi Fan 	int ret;
2821ee7efd4SKaixi Fan 
2831ee7efd4SKaixi Fan 	ret = bpf_tc_hook_create(hook);
2841ee7efd4SKaixi Fan 	if (!ASSERT_OK(ret, "create tc hook"))
2851ee7efd4SKaixi Fan 		return ret;
2861ee7efd4SKaixi Fan 
2871ee7efd4SKaixi Fan 	if (igr_fd >= 0) {
2881ee7efd4SKaixi Fan 		hook->attach_point = BPF_TC_INGRESS;
2891ee7efd4SKaixi Fan 		ret = bpf_tc_attach(hook, &opts1);
2901ee7efd4SKaixi Fan 		if (!ASSERT_OK(ret, "bpf_tc_attach")) {
2911ee7efd4SKaixi Fan 			bpf_tc_hook_destroy(hook);
2921ee7efd4SKaixi Fan 			return ret;
2931ee7efd4SKaixi Fan 		}
2941ee7efd4SKaixi Fan 	}
2951ee7efd4SKaixi Fan 
2961ee7efd4SKaixi Fan 	if (egr_fd >= 0) {
2971ee7efd4SKaixi Fan 		hook->attach_point = BPF_TC_EGRESS;
2981ee7efd4SKaixi Fan 		ret = bpf_tc_attach(hook, &opts2);
2991ee7efd4SKaixi Fan 		if (!ASSERT_OK(ret, "bpf_tc_attach")) {
3001ee7efd4SKaixi Fan 			bpf_tc_hook_destroy(hook);
3011ee7efd4SKaixi Fan 			return ret;
3021ee7efd4SKaixi Fan 		}
3031ee7efd4SKaixi Fan 	}
3041ee7efd4SKaixi Fan 
3051ee7efd4SKaixi Fan 	return 0;
3061ee7efd4SKaixi Fan }
3071ee7efd4SKaixi Fan 
test_vxlan_tunnel(void)3081ee7efd4SKaixi Fan static void test_vxlan_tunnel(void)
3091ee7efd4SKaixi Fan {
3101ee7efd4SKaixi Fan 	struct test_tunnel_kern *skel = NULL;
3111ee7efd4SKaixi Fan 	struct nstoken *nstoken;
312fd0ad6f1SYonghong Song 	int local_ip_map_fd = -1;
3131ee7efd4SKaixi Fan 	int set_src_prog_fd, get_src_prog_fd;
3141ee7efd4SKaixi Fan 	int set_dst_prog_fd;
3151ee7efd4SKaixi Fan 	int key = 0, ifindex = -1;
3161ee7efd4SKaixi Fan 	uint local_ip;
3171ee7efd4SKaixi Fan 	int err;
3181ee7efd4SKaixi Fan 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
3191ee7efd4SKaixi Fan 			    .attach_point = BPF_TC_INGRESS);
3201ee7efd4SKaixi Fan 
3211ee7efd4SKaixi Fan 	/* add vxlan tunnel */
3221ee7efd4SKaixi Fan 	err = add_vxlan_tunnel();
3231ee7efd4SKaixi Fan 	if (!ASSERT_OK(err, "add vxlan tunnel"))
3241ee7efd4SKaixi Fan 		goto done;
3251ee7efd4SKaixi Fan 
3261ee7efd4SKaixi Fan 	/* load and attach bpf prog to tunnel dev tc hook point */
3271ee7efd4SKaixi Fan 	skel = test_tunnel_kern__open_and_load();
3281ee7efd4SKaixi Fan 	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
3291ee7efd4SKaixi Fan 		goto done;
3301ee7efd4SKaixi Fan 	ifindex = if_nametoindex(VXLAN_TUNL_DEV1);
3311ee7efd4SKaixi Fan 	if (!ASSERT_NEQ(ifindex, 0, "vxlan11 ifindex"))
3321ee7efd4SKaixi Fan 		goto done;
3331ee7efd4SKaixi Fan 	tc_hook.ifindex = ifindex;
3341ee7efd4SKaixi Fan 	get_src_prog_fd = bpf_program__fd(skel->progs.vxlan_get_tunnel_src);
3351ee7efd4SKaixi Fan 	set_src_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_src);
3361ee7efd4SKaixi Fan 	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
3371ee7efd4SKaixi Fan 		goto done;
3381ee7efd4SKaixi Fan 	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
3391ee7efd4SKaixi Fan 		goto done;
3401ee7efd4SKaixi Fan 	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
3411ee7efd4SKaixi Fan 		goto done;
3421ee7efd4SKaixi Fan 
3431115169fSPaul Chaignon 	/* load and attach bpf prog to veth dev tc hook point */
3441115169fSPaul Chaignon 	ifindex = if_nametoindex("veth1");
3451115169fSPaul Chaignon 	if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex"))
3461115169fSPaul Chaignon 		goto done;
3471115169fSPaul Chaignon 	tc_hook.ifindex = ifindex;
3481115169fSPaul Chaignon 	set_dst_prog_fd = bpf_program__fd(skel->progs.veth_set_outer_dst);
3491115169fSPaul Chaignon 	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
3501115169fSPaul Chaignon 		goto done;
3511115169fSPaul Chaignon 	if (attach_tc_prog(&tc_hook, set_dst_prog_fd, -1))
3521115169fSPaul Chaignon 		goto done;
3531115169fSPaul Chaignon 
3541ee7efd4SKaixi Fan 	/* load and attach prog set_md to tunnel dev tc hook point at_ns0 */
3551ee7efd4SKaixi Fan 	nstoken = open_netns("at_ns0");
3561ee7efd4SKaixi Fan 	if (!ASSERT_OK_PTR(nstoken, "setns src"))
3571ee7efd4SKaixi Fan 		goto done;
3581ee7efd4SKaixi Fan 	ifindex = if_nametoindex(VXLAN_TUNL_DEV0);
3591ee7efd4SKaixi Fan 	if (!ASSERT_NEQ(ifindex, 0, "vxlan00 ifindex"))
3601ee7efd4SKaixi Fan 		goto done;
3611ee7efd4SKaixi Fan 	tc_hook.ifindex = ifindex;
3621ee7efd4SKaixi Fan 	set_dst_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_dst);
3631ee7efd4SKaixi Fan 	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
3641ee7efd4SKaixi Fan 		goto done;
3651ee7efd4SKaixi Fan 	if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd))
3661ee7efd4SKaixi Fan 		goto done;
3671ee7efd4SKaixi Fan 	close_netns(nstoken);
3681ee7efd4SKaixi Fan 
3691ee7efd4SKaixi Fan 	/* use veth1 ip 2 as tunnel source ip */
3701ee7efd4SKaixi Fan 	local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map);
3711ee7efd4SKaixi Fan 	if (!ASSERT_GE(local_ip_map_fd, 0, "bpf_map__fd"))
3721ee7efd4SKaixi Fan 		goto done;
3731ee7efd4SKaixi Fan 	local_ip = IP4_ADDR2_HEX_VETH1;
3741ee7efd4SKaixi Fan 	err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY);
3751ee7efd4SKaixi Fan 	if (!ASSERT_OK(err, "update bpf local_ip_map"))
3761ee7efd4SKaixi Fan 		goto done;
3771ee7efd4SKaixi Fan 
3781ee7efd4SKaixi Fan 	/* ping test */
3791ee7efd4SKaixi Fan 	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
3801ee7efd4SKaixi Fan 	if (!ASSERT_OK(err, "test_ping"))
3811ee7efd4SKaixi Fan 		goto done;
3821ee7efd4SKaixi Fan 
3831ee7efd4SKaixi Fan done:
3841ee7efd4SKaixi Fan 	/* delete vxlan tunnel */
3851ee7efd4SKaixi Fan 	delete_vxlan_tunnel();
3861ee7efd4SKaixi Fan 	if (local_ip_map_fd >= 0)
3871ee7efd4SKaixi Fan 		close(local_ip_map_fd);
3881ee7efd4SKaixi Fan 	if (skel)
3891ee7efd4SKaixi Fan 		test_tunnel_kern__destroy(skel);
3901ee7efd4SKaixi Fan }
3911ee7efd4SKaixi Fan 
test_ip6vxlan_tunnel(void)3921ee7efd4SKaixi Fan static void test_ip6vxlan_tunnel(void)
3931ee7efd4SKaixi Fan {
3941ee7efd4SKaixi Fan 	struct test_tunnel_kern *skel = NULL;
3951ee7efd4SKaixi Fan 	struct nstoken *nstoken;
396fd0ad6f1SYonghong Song 	int local_ip_map_fd = -1;
3971ee7efd4SKaixi Fan 	int set_src_prog_fd, get_src_prog_fd;
3981ee7efd4SKaixi Fan 	int set_dst_prog_fd;
3991ee7efd4SKaixi Fan 	int key = 0, ifindex = -1;
4001ee7efd4SKaixi Fan 	uint local_ip;
4011ee7efd4SKaixi Fan 	int err;
4021ee7efd4SKaixi Fan 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
4031ee7efd4SKaixi Fan 			    .attach_point = BPF_TC_INGRESS);
4041ee7efd4SKaixi Fan 
4051ee7efd4SKaixi Fan 	/* add vxlan tunnel */
4061ee7efd4SKaixi Fan 	err = add_ip6vxlan_tunnel();
4071ee7efd4SKaixi Fan 	if (!ASSERT_OK(err, "add_ip6vxlan_tunnel"))
4081ee7efd4SKaixi Fan 		goto done;
4091ee7efd4SKaixi Fan 
4101ee7efd4SKaixi Fan 	/* load and attach bpf prog to tunnel dev tc hook point */
4111ee7efd4SKaixi Fan 	skel = test_tunnel_kern__open_and_load();
4121ee7efd4SKaixi Fan 	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
4131ee7efd4SKaixi Fan 		goto done;
4141ee7efd4SKaixi Fan 	ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV1);
4151ee7efd4SKaixi Fan 	if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan11 ifindex"))
4161ee7efd4SKaixi Fan 		goto done;
4171ee7efd4SKaixi Fan 	tc_hook.ifindex = ifindex;
4181ee7efd4SKaixi Fan 	get_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_get_tunnel_src);
4191ee7efd4SKaixi Fan 	set_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_src);
4201ee7efd4SKaixi Fan 	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
4211ee7efd4SKaixi Fan 		goto done;
4221ee7efd4SKaixi Fan 	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
4231ee7efd4SKaixi Fan 		goto done;
4241ee7efd4SKaixi Fan 	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
4251ee7efd4SKaixi Fan 		goto done;
4261ee7efd4SKaixi Fan 
4271ee7efd4SKaixi Fan 	/* load and attach prog set_md to tunnel dev tc hook point at_ns0 */
4281ee7efd4SKaixi Fan 	nstoken = open_netns("at_ns0");
4291ee7efd4SKaixi Fan 	if (!ASSERT_OK_PTR(nstoken, "setns src"))
4301ee7efd4SKaixi Fan 		goto done;
4311ee7efd4SKaixi Fan 	ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV0);
4321ee7efd4SKaixi Fan 	if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan00 ifindex"))
4331ee7efd4SKaixi Fan 		goto done;
4341ee7efd4SKaixi Fan 	tc_hook.ifindex = ifindex;
4351ee7efd4SKaixi Fan 	set_dst_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_dst);
4361ee7efd4SKaixi Fan 	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
4371ee7efd4SKaixi Fan 		goto done;
4381ee7efd4SKaixi Fan 	if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd))
4391ee7efd4SKaixi Fan 		goto done;
4401ee7efd4SKaixi Fan 	close_netns(nstoken);
4411ee7efd4SKaixi Fan 
4421ee7efd4SKaixi Fan 	/* use veth1 ip 2 as tunnel source ip */
4431ee7efd4SKaixi Fan 	local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map);
4441ee7efd4SKaixi Fan 	if (!ASSERT_GE(local_ip_map_fd, 0, "get local_ip_map fd"))
4451ee7efd4SKaixi Fan 		goto done;
4461ee7efd4SKaixi Fan 	local_ip = IP6_ADDR2_HEX_VETH1;
4471ee7efd4SKaixi Fan 	err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY);
4481ee7efd4SKaixi Fan 	if (!ASSERT_OK(err, "update bpf local_ip_map"))
4491ee7efd4SKaixi Fan 		goto done;
4501ee7efd4SKaixi Fan 
4511ee7efd4SKaixi Fan 	/* ping test */
4521ee7efd4SKaixi Fan 	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
4531ee7efd4SKaixi Fan 	if (!ASSERT_OK(err, "test_ping"))
4541ee7efd4SKaixi Fan 		goto done;
4551ee7efd4SKaixi Fan 
4561ee7efd4SKaixi Fan done:
4571ee7efd4SKaixi Fan 	/* delete ipv6 vxlan tunnel */
4581ee7efd4SKaixi Fan 	delete_ip6vxlan_tunnel();
4591ee7efd4SKaixi Fan 	if (local_ip_map_fd >= 0)
4601ee7efd4SKaixi Fan 		close(local_ip_map_fd);
4611ee7efd4SKaixi Fan 	if (skel)
4621ee7efd4SKaixi Fan 		test_tunnel_kern__destroy(skel);
4631ee7efd4SKaixi Fan }
4641ee7efd4SKaixi Fan 
test_ipip_tunnel(enum ipip_encap encap)465*d9688f89SChristian Ehrig static void test_ipip_tunnel(enum ipip_encap encap)
466*d9688f89SChristian Ehrig {
467*d9688f89SChristian Ehrig 	struct test_tunnel_kern *skel = NULL;
468*d9688f89SChristian Ehrig 	struct nstoken *nstoken;
469*d9688f89SChristian Ehrig 	int set_src_prog_fd, get_src_prog_fd;
470*d9688f89SChristian Ehrig 	int ifindex = -1;
471*d9688f89SChristian Ehrig 	int err;
472*d9688f89SChristian Ehrig 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
473*d9688f89SChristian Ehrig 			    .attach_point = BPF_TC_INGRESS);
474*d9688f89SChristian Ehrig 
475*d9688f89SChristian Ehrig 	/* add ipip tunnel */
476*d9688f89SChristian Ehrig 	err = add_ipip_tunnel(encap);
477*d9688f89SChristian Ehrig 	if (!ASSERT_OK(err, "add_ipip_tunnel"))
478*d9688f89SChristian Ehrig 		goto done;
479*d9688f89SChristian Ehrig 
480*d9688f89SChristian Ehrig 	/* load and attach bpf prog to tunnel dev tc hook point */
481*d9688f89SChristian Ehrig 	skel = test_tunnel_kern__open_and_load();
482*d9688f89SChristian Ehrig 	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
483*d9688f89SChristian Ehrig 		goto done;
484*d9688f89SChristian Ehrig 	ifindex = if_nametoindex(IPIP_TUNL_DEV1);
485*d9688f89SChristian Ehrig 	if (!ASSERT_NEQ(ifindex, 0, "ipip11 ifindex"))
486*d9688f89SChristian Ehrig 		goto done;
487*d9688f89SChristian Ehrig 	tc_hook.ifindex = ifindex;
488*d9688f89SChristian Ehrig 
489*d9688f89SChristian Ehrig 	switch (encap) {
490*d9688f89SChristian Ehrig 	case FOU:
491*d9688f89SChristian Ehrig 		get_src_prog_fd = bpf_program__fd(
492*d9688f89SChristian Ehrig 			skel->progs.ipip_encap_get_tunnel);
493*d9688f89SChristian Ehrig 		set_src_prog_fd = bpf_program__fd(
494*d9688f89SChristian Ehrig 			skel->progs.ipip_fou_set_tunnel);
495*d9688f89SChristian Ehrig 		break;
496*d9688f89SChristian Ehrig 	case GUE:
497*d9688f89SChristian Ehrig 		get_src_prog_fd = bpf_program__fd(
498*d9688f89SChristian Ehrig 			skel->progs.ipip_encap_get_tunnel);
499*d9688f89SChristian Ehrig 		set_src_prog_fd = bpf_program__fd(
500*d9688f89SChristian Ehrig 			skel->progs.ipip_gue_set_tunnel);
501*d9688f89SChristian Ehrig 		break;
502*d9688f89SChristian Ehrig 	default:
503*d9688f89SChristian Ehrig 		get_src_prog_fd = bpf_program__fd(
504*d9688f89SChristian Ehrig 			skel->progs.ipip_get_tunnel);
505*d9688f89SChristian Ehrig 		set_src_prog_fd = bpf_program__fd(
506*d9688f89SChristian Ehrig 			skel->progs.ipip_set_tunnel);
507*d9688f89SChristian Ehrig 	}
508*d9688f89SChristian Ehrig 
509*d9688f89SChristian Ehrig 	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
510*d9688f89SChristian Ehrig 		goto done;
511*d9688f89SChristian Ehrig 	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
512*d9688f89SChristian Ehrig 		goto done;
513*d9688f89SChristian Ehrig 	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
514*d9688f89SChristian Ehrig 		goto done;
515*d9688f89SChristian Ehrig 
516*d9688f89SChristian Ehrig 	/* ping from root namespace test */
517*d9688f89SChristian Ehrig 	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
518*d9688f89SChristian Ehrig 	if (!ASSERT_OK(err, "test_ping"))
519*d9688f89SChristian Ehrig 		goto done;
520*d9688f89SChristian Ehrig 
521*d9688f89SChristian Ehrig 	/* ping from at_ns0 namespace test */
522*d9688f89SChristian Ehrig 	nstoken = open_netns("at_ns0");
523*d9688f89SChristian Ehrig 	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV1);
524*d9688f89SChristian Ehrig 	if (!ASSERT_OK(err, "test_ping"))
525*d9688f89SChristian Ehrig 		goto done;
526*d9688f89SChristian Ehrig 	close_netns(nstoken);
527*d9688f89SChristian Ehrig 
528*d9688f89SChristian Ehrig done:
529*d9688f89SChristian Ehrig 	/* delete ipip tunnel */
530*d9688f89SChristian Ehrig 	delete_ipip_tunnel();
531*d9688f89SChristian Ehrig 	if (skel)
532*d9688f89SChristian Ehrig 		test_tunnel_kern__destroy(skel);
533*d9688f89SChristian Ehrig }
534*d9688f89SChristian Ehrig 
535*d9688f89SChristian Ehrig #define RUN_TEST(name, ...)						\
5361ee7efd4SKaixi Fan 	({								\
5371ee7efd4SKaixi Fan 		if (test__start_subtest(#name)) {			\
538*d9688f89SChristian Ehrig 			test_ ## name(__VA_ARGS__);			\
5391ee7efd4SKaixi Fan 		}							\
5401ee7efd4SKaixi Fan 	})
5411ee7efd4SKaixi Fan 
test_tunnel_run_tests(void * arg)5421ee7efd4SKaixi Fan static void *test_tunnel_run_tests(void *arg)
5431ee7efd4SKaixi Fan {
5441ee7efd4SKaixi Fan 	cleanup();
5451ee7efd4SKaixi Fan 	config_device();
5461ee7efd4SKaixi Fan 
5471ee7efd4SKaixi Fan 	RUN_TEST(vxlan_tunnel);
5481ee7efd4SKaixi Fan 	RUN_TEST(ip6vxlan_tunnel);
549*d9688f89SChristian Ehrig 	RUN_TEST(ipip_tunnel, NONE);
550*d9688f89SChristian Ehrig 	RUN_TEST(ipip_tunnel, FOU);
551*d9688f89SChristian Ehrig 	RUN_TEST(ipip_tunnel, GUE);
5521ee7efd4SKaixi Fan 
5531ee7efd4SKaixi Fan 	cleanup();
5541ee7efd4SKaixi Fan 
5551ee7efd4SKaixi Fan 	return NULL;
5561ee7efd4SKaixi Fan }
5571ee7efd4SKaixi Fan 
test_tunnel(void)5589b6a7773SMartin KaFai Lau void test_tunnel(void)
5591ee7efd4SKaixi Fan {
5601ee7efd4SKaixi Fan 	pthread_t test_thread;
5611ee7efd4SKaixi Fan 	int err;
5621ee7efd4SKaixi Fan 
5631ee7efd4SKaixi Fan 	/* Run the tests in their own thread to isolate the namespace changes
5641ee7efd4SKaixi Fan 	 * so they do not affect the environment of other tests.
5651ee7efd4SKaixi Fan 	 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns())
5661ee7efd4SKaixi Fan 	 */
5671ee7efd4SKaixi Fan 	err = pthread_create(&test_thread, NULL, &test_tunnel_run_tests, NULL);
5681ee7efd4SKaixi Fan 	if (ASSERT_OK(err, "pthread_create"))
5691ee7efd4SKaixi Fan 		ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join");
5701ee7efd4SKaixi Fan }
571