1886225bbSStanislav Fomichev // SPDX-License-Identifier: GPL-2.0
2886225bbSStanislav Fomichev #include <test_progs.h>
3488a23b8SStanislav Fomichev #include <network_helpers.h>
40905beecSStanislav Fomichev #include <error.h>
50905beecSStanislav Fomichev #include <linux/if.h>
60905beecSStanislav Fomichev #include <linux/if_tun.h>
75fac1718SAlakesh Haloi #include <sys/uio.h>
8886225bbSStanislav Fomichev 
9b4b8a3bfSJakub Sitnicki #include "bpf_flow.skel.h"
10b4b8a3bfSJakub Sitnicki 
11d6513727SShmulik Ladkani #define FLOW_CONTINUE_SADDR 0x7f00007f /* 127.0.0.127 */
12d6513727SShmulik Ladkani 
13ae173a91SStanislav Fomichev #ifndef IP_MF
14ae173a91SStanislav Fomichev #define IP_MF 0x2000
15ae173a91SStanislav Fomichev #endif
16ae173a91SStanislav Fomichev 
17886225bbSStanislav Fomichev #define CHECK_FLOW_KEYS(desc, got, expected)				\
1839316183SDelyan Kratunov 	_CHECK(memcmp(&got, &expected, sizeof(got)) != 0,		\
19886225bbSStanislav Fomichev 	      desc,							\
2039316183SDelyan Kratunov 	      topts.duration,						\
21886225bbSStanislav Fomichev 	      "nhoff=%u/%u "						\
22886225bbSStanislav Fomichev 	      "thoff=%u/%u "						\
23886225bbSStanislav Fomichev 	      "addr_proto=0x%x/0x%x "					\
24886225bbSStanislav Fomichev 	      "is_frag=%u/%u "						\
25886225bbSStanislav Fomichev 	      "is_first_frag=%u/%u "					\
26886225bbSStanislav Fomichev 	      "is_encap=%u/%u "						\
27a5cb3346SStanislav Fomichev 	      "ip_proto=0x%x/0x%x "					\
28886225bbSStanislav Fomichev 	      "n_proto=0x%x/0x%x "					\
2971c99e32SStanislav Fomichev 	      "flow_label=0x%x/0x%x "					\
30886225bbSStanislav Fomichev 	      "sport=%u/%u "						\
31886225bbSStanislav Fomichev 	      "dport=%u/%u\n",						\
32886225bbSStanislav Fomichev 	      got.nhoff, expected.nhoff,				\
33886225bbSStanislav Fomichev 	      got.thoff, expected.thoff,				\
34886225bbSStanislav Fomichev 	      got.addr_proto, expected.addr_proto,			\
35886225bbSStanislav Fomichev 	      got.is_frag, expected.is_frag,				\
36886225bbSStanislav Fomichev 	      got.is_first_frag, expected.is_first_frag,		\
37886225bbSStanislav Fomichev 	      got.is_encap, expected.is_encap,				\
38a5cb3346SStanislav Fomichev 	      got.ip_proto, expected.ip_proto,				\
39886225bbSStanislav Fomichev 	      got.n_proto, expected.n_proto,				\
4071c99e32SStanislav Fomichev 	      got.flow_label, expected.flow_label,			\
41886225bbSStanislav Fomichev 	      got.sport, expected.sport,				\
42886225bbSStanislav Fomichev 	      got.dport, expected.dport)
43886225bbSStanislav Fomichev 
44a5cb3346SStanislav Fomichev struct ipv4_pkt {
45a5cb3346SStanislav Fomichev 	struct ethhdr eth;
46a5cb3346SStanislav Fomichev 	struct iphdr iph;
47a5cb3346SStanislav Fomichev 	struct tcphdr tcp;
48a5cb3346SStanislav Fomichev } __packed;
49886225bbSStanislav Fomichev 
50e853ae77SStanislav Fomichev struct ipip_pkt {
51e853ae77SStanislav Fomichev 	struct ethhdr eth;
52e853ae77SStanislav Fomichev 	struct iphdr iph;
53e853ae77SStanislav Fomichev 	struct iphdr iph_inner;
54e853ae77SStanislav Fomichev 	struct tcphdr tcp;
55e853ae77SStanislav Fomichev } __packed;
56e853ae77SStanislav Fomichev 
57a5cb3346SStanislav Fomichev struct svlan_ipv4_pkt {
582c3af7d9SStanislav Fomichev 	struct ethhdr eth;
592c3af7d9SStanislav Fomichev 	__u16 vlan_tci;
602c3af7d9SStanislav Fomichev 	__u16 vlan_proto;
612c3af7d9SStanislav Fomichev 	struct iphdr iph;
622c3af7d9SStanislav Fomichev 	struct tcphdr tcp;
63a5cb3346SStanislav Fomichev } __packed;
642c3af7d9SStanislav Fomichev 
65a5cb3346SStanislav Fomichev struct ipv6_pkt {
66a5cb3346SStanislav Fomichev 	struct ethhdr eth;
67a5cb3346SStanislav Fomichev 	struct ipv6hdr iph;
68a5cb3346SStanislav Fomichev 	struct tcphdr tcp;
69a5cb3346SStanislav Fomichev } __packed;
702c3af7d9SStanislav Fomichev 
71ae173a91SStanislav Fomichev struct ipv6_frag_pkt {
72ae173a91SStanislav Fomichev 	struct ethhdr eth;
73ae173a91SStanislav Fomichev 	struct ipv6hdr iph;
74ae173a91SStanislav Fomichev 	struct frag_hdr {
75ae173a91SStanislav Fomichev 		__u8 nexthdr;
76ae173a91SStanislav Fomichev 		__u8 reserved;
77ae173a91SStanislav Fomichev 		__be16 frag_off;
78ae173a91SStanislav Fomichev 		__be32 identification;
79ae173a91SStanislav Fomichev 	} ipf;
80ae173a91SStanislav Fomichev 	struct tcphdr tcp;
81ae173a91SStanislav Fomichev } __packed;
82ae173a91SStanislav Fomichev 
83a5cb3346SStanislav Fomichev struct dvlan_ipv6_pkt {
842c3af7d9SStanislav Fomichev 	struct ethhdr eth;
852c3af7d9SStanislav Fomichev 	__u16 vlan_tci;
862c3af7d9SStanislav Fomichev 	__u16 vlan_proto;
872c3af7d9SStanislav Fomichev 	__u16 vlan_tci2;
882c3af7d9SStanislav Fomichev 	__u16 vlan_proto2;
892c3af7d9SStanislav Fomichev 	struct ipv6hdr iph;
902c3af7d9SStanislav Fomichev 	struct tcphdr tcp;
91a5cb3346SStanislav Fomichev } __packed;
92a5cb3346SStanislav Fomichev 
93a5cb3346SStanislav Fomichev struct test {
94a5cb3346SStanislav Fomichev 	const char *name;
95a5cb3346SStanislav Fomichev 	union {
96a5cb3346SStanislav Fomichev 		struct ipv4_pkt ipv4;
97a5cb3346SStanislav Fomichev 		struct svlan_ipv4_pkt svlan_ipv4;
98e853ae77SStanislav Fomichev 		struct ipip_pkt ipip;
99a5cb3346SStanislav Fomichev 		struct ipv6_pkt ipv6;
100ae173a91SStanislav Fomichev 		struct ipv6_frag_pkt ipv6_frag;
101a5cb3346SStanislav Fomichev 		struct dvlan_ipv6_pkt dvlan_ipv6;
102a5cb3346SStanislav Fomichev 	} pkt;
103a5cb3346SStanislav Fomichev 	struct bpf_flow_keys keys;
104ae173a91SStanislav Fomichev 	__u32 flags;
1055deedfbeSShmulik Ladkani 	__u32 retval;
106a5cb3346SStanislav Fomichev };
107a5cb3346SStanislav Fomichev 
108a5cb3346SStanislav Fomichev #define VLAN_HLEN	4
109a5cb3346SStanislav Fomichev 
11006716e04SJakub Sitnicki static __u32 duration;
111a5cb3346SStanislav Fomichev struct test tests[] = {
112a5cb3346SStanislav Fomichev 	{
113a5cb3346SStanislav Fomichev 		.name = "ipv4",
114a5cb3346SStanislav Fomichev 		.pkt.ipv4 = {
115a5cb3346SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
116a5cb3346SStanislav Fomichev 			.iph.ihl = 5,
117a5cb3346SStanislav Fomichev 			.iph.protocol = IPPROTO_TCP,
118a5cb3346SStanislav Fomichev 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
119a5cb3346SStanislav Fomichev 			.tcp.doff = 5,
1209840a4ffSPetar Penkov 			.tcp.source = 80,
1219840a4ffSPetar Penkov 			.tcp.dest = 8080,
122a5cb3346SStanislav Fomichev 		},
123a5cb3346SStanislav Fomichev 		.keys = {
12402ee0658SStanislav Fomichev 			.nhoff = ETH_HLEN,
12502ee0658SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct iphdr),
126a5cb3346SStanislav Fomichev 			.addr_proto = ETH_P_IP,
127a5cb3346SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
128a5cb3346SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IP),
1299840a4ffSPetar Penkov 			.sport = 80,
1309840a4ffSPetar Penkov 			.dport = 8080,
131a5cb3346SStanislav Fomichev 		},
1325deedfbeSShmulik Ladkani 		.retval = BPF_OK,
133a5cb3346SStanislav Fomichev 	},
134a5cb3346SStanislav Fomichev 	{
135a5cb3346SStanislav Fomichev 		.name = "ipv6",
136a5cb3346SStanislav Fomichev 		.pkt.ipv6 = {
137a5cb3346SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
138a5cb3346SStanislav Fomichev 			.iph.nexthdr = IPPROTO_TCP,
139a5cb3346SStanislav Fomichev 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
140a5cb3346SStanislav Fomichev 			.tcp.doff = 5,
1419840a4ffSPetar Penkov 			.tcp.source = 80,
1429840a4ffSPetar Penkov 			.tcp.dest = 8080,
143a5cb3346SStanislav Fomichev 		},
144a5cb3346SStanislav Fomichev 		.keys = {
14502ee0658SStanislav Fomichev 			.nhoff = ETH_HLEN,
14602ee0658SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct ipv6hdr),
147a5cb3346SStanislav Fomichev 			.addr_proto = ETH_P_IPV6,
148a5cb3346SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
149a5cb3346SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
1509840a4ffSPetar Penkov 			.sport = 80,
1519840a4ffSPetar Penkov 			.dport = 8080,
152a5cb3346SStanislav Fomichev 		},
1535deedfbeSShmulik Ladkani 		.retval = BPF_OK,
154a5cb3346SStanislav Fomichev 	},
155a5cb3346SStanislav Fomichev 	{
156a5cb3346SStanislav Fomichev 		.name = "802.1q-ipv4",
157a5cb3346SStanislav Fomichev 		.pkt.svlan_ipv4 = {
158a5cb3346SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_8021Q),
159a5cb3346SStanislav Fomichev 			.vlan_proto = __bpf_constant_htons(ETH_P_IP),
160a5cb3346SStanislav Fomichev 			.iph.ihl = 5,
161a5cb3346SStanislav Fomichev 			.iph.protocol = IPPROTO_TCP,
162a5cb3346SStanislav Fomichev 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
163a5cb3346SStanislav Fomichev 			.tcp.doff = 5,
1649840a4ffSPetar Penkov 			.tcp.source = 80,
1659840a4ffSPetar Penkov 			.tcp.dest = 8080,
166a5cb3346SStanislav Fomichev 		},
167a5cb3346SStanislav Fomichev 		.keys = {
16802ee0658SStanislav Fomichev 			.nhoff = ETH_HLEN + VLAN_HLEN,
16902ee0658SStanislav Fomichev 			.thoff = ETH_HLEN + VLAN_HLEN + sizeof(struct iphdr),
170a5cb3346SStanislav Fomichev 			.addr_proto = ETH_P_IP,
171a5cb3346SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
172a5cb3346SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IP),
1739840a4ffSPetar Penkov 			.sport = 80,
1749840a4ffSPetar Penkov 			.dport = 8080,
175a5cb3346SStanislav Fomichev 		},
1765deedfbeSShmulik Ladkani 		.retval = BPF_OK,
177a5cb3346SStanislav Fomichev 	},
178a5cb3346SStanislav Fomichev 	{
179a5cb3346SStanislav Fomichev 		.name = "802.1ad-ipv6",
180a5cb3346SStanislav Fomichev 		.pkt.dvlan_ipv6 = {
1812c3af7d9SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_8021AD),
1822c3af7d9SStanislav Fomichev 			.vlan_proto = __bpf_constant_htons(ETH_P_8021Q),
1832c3af7d9SStanislav Fomichev 			.vlan_proto2 = __bpf_constant_htons(ETH_P_IPV6),
1842c3af7d9SStanislav Fomichev 			.iph.nexthdr = IPPROTO_TCP,
1852c3af7d9SStanislav Fomichev 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
1862c3af7d9SStanislav Fomichev 			.tcp.doff = 5,
1879840a4ffSPetar Penkov 			.tcp.source = 80,
1889840a4ffSPetar Penkov 			.tcp.dest = 8080,
189a5cb3346SStanislav Fomichev 		},
190a5cb3346SStanislav Fomichev 		.keys = {
19102ee0658SStanislav Fomichev 			.nhoff = ETH_HLEN + VLAN_HLEN * 2,
19202ee0658SStanislav Fomichev 			.thoff = ETH_HLEN + VLAN_HLEN * 2 +
19302ee0658SStanislav Fomichev 				sizeof(struct ipv6hdr),
1942c3af7d9SStanislav Fomichev 			.addr_proto = ETH_P_IPV6,
1952c3af7d9SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
1962c3af7d9SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
1979840a4ffSPetar Penkov 			.sport = 80,
1989840a4ffSPetar Penkov 			.dport = 8080,
199a5cb3346SStanislav Fomichev 		},
2005deedfbeSShmulik Ladkani 		.retval = BPF_OK,
201a5cb3346SStanislav Fomichev 	},
202ae173a91SStanislav Fomichev 	{
203ae173a91SStanislav Fomichev 		.name = "ipv4-frag",
204ae173a91SStanislav Fomichev 		.pkt.ipv4 = {
205ae173a91SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
206ae173a91SStanislav Fomichev 			.iph.ihl = 5,
207ae173a91SStanislav Fomichev 			.iph.protocol = IPPROTO_TCP,
208ae173a91SStanislav Fomichev 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
209ae173a91SStanislav Fomichev 			.iph.frag_off = __bpf_constant_htons(IP_MF),
210ae173a91SStanislav Fomichev 			.tcp.doff = 5,
211ae173a91SStanislav Fomichev 			.tcp.source = 80,
212ae173a91SStanislav Fomichev 			.tcp.dest = 8080,
213ae173a91SStanislav Fomichev 		},
214ae173a91SStanislav Fomichev 		.keys = {
215ae173a91SStanislav Fomichev 			.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
216ae173a91SStanislav Fomichev 			.nhoff = ETH_HLEN,
217ae173a91SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct iphdr),
218ae173a91SStanislav Fomichev 			.addr_proto = ETH_P_IP,
219ae173a91SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
220ae173a91SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IP),
221ae173a91SStanislav Fomichev 			.is_frag = true,
222ae173a91SStanislav Fomichev 			.is_first_frag = true,
223ae173a91SStanislav Fomichev 			.sport = 80,
224ae173a91SStanislav Fomichev 			.dport = 8080,
225ae173a91SStanislav Fomichev 		},
226ae173a91SStanislav Fomichev 		.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
2275deedfbeSShmulik Ladkani 		.retval = BPF_OK,
228ae173a91SStanislav Fomichev 	},
229ae173a91SStanislav Fomichev 	{
230ae173a91SStanislav Fomichev 		.name = "ipv4-no-frag",
231ae173a91SStanislav Fomichev 		.pkt.ipv4 = {
232ae173a91SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
233ae173a91SStanislav Fomichev 			.iph.ihl = 5,
234ae173a91SStanislav Fomichev 			.iph.protocol = IPPROTO_TCP,
235ae173a91SStanislav Fomichev 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
236ae173a91SStanislav Fomichev 			.iph.frag_off = __bpf_constant_htons(IP_MF),
237ae173a91SStanislav Fomichev 			.tcp.doff = 5,
238ae173a91SStanislav Fomichev 			.tcp.source = 80,
239ae173a91SStanislav Fomichev 			.tcp.dest = 8080,
240ae173a91SStanislav Fomichev 		},
241ae173a91SStanislav Fomichev 		.keys = {
242ae173a91SStanislav Fomichev 			.nhoff = ETH_HLEN,
243ae173a91SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct iphdr),
244ae173a91SStanislav Fomichev 			.addr_proto = ETH_P_IP,
245ae173a91SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
246ae173a91SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IP),
247ae173a91SStanislav Fomichev 			.is_frag = true,
248ae173a91SStanislav Fomichev 			.is_first_frag = true,
249ae173a91SStanislav Fomichev 		},
2505deedfbeSShmulik Ladkani 		.retval = BPF_OK,
251ae173a91SStanislav Fomichev 	},
252ae173a91SStanislav Fomichev 	{
253ae173a91SStanislav Fomichev 		.name = "ipv6-frag",
254ae173a91SStanislav Fomichev 		.pkt.ipv6_frag = {
255ae173a91SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
256ae173a91SStanislav Fomichev 			.iph.nexthdr = IPPROTO_FRAGMENT,
257ae173a91SStanislav Fomichev 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
258ae173a91SStanislav Fomichev 			.ipf.nexthdr = IPPROTO_TCP,
259ae173a91SStanislav Fomichev 			.tcp.doff = 5,
260ae173a91SStanislav Fomichev 			.tcp.source = 80,
261ae173a91SStanislav Fomichev 			.tcp.dest = 8080,
262ae173a91SStanislav Fomichev 		},
263ae173a91SStanislav Fomichev 		.keys = {
264ae173a91SStanislav Fomichev 			.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
265ae173a91SStanislav Fomichev 			.nhoff = ETH_HLEN,
266ae173a91SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct ipv6hdr) +
267ae173a91SStanislav Fomichev 				sizeof(struct frag_hdr),
268ae173a91SStanislav Fomichev 			.addr_proto = ETH_P_IPV6,
269ae173a91SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
270ae173a91SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
271ae173a91SStanislav Fomichev 			.is_frag = true,
272ae173a91SStanislav Fomichev 			.is_first_frag = true,
273ae173a91SStanislav Fomichev 			.sport = 80,
274ae173a91SStanislav Fomichev 			.dport = 8080,
275ae173a91SStanislav Fomichev 		},
276ae173a91SStanislav Fomichev 		.flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
2775deedfbeSShmulik Ladkani 		.retval = BPF_OK,
278ae173a91SStanislav Fomichev 	},
279ae173a91SStanislav Fomichev 	{
280ae173a91SStanislav Fomichev 		.name = "ipv6-no-frag",
281ae173a91SStanislav Fomichev 		.pkt.ipv6_frag = {
282ae173a91SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
283ae173a91SStanislav Fomichev 			.iph.nexthdr = IPPROTO_FRAGMENT,
284ae173a91SStanislav Fomichev 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
285ae173a91SStanislav Fomichev 			.ipf.nexthdr = IPPROTO_TCP,
286ae173a91SStanislav Fomichev 			.tcp.doff = 5,
287ae173a91SStanislav Fomichev 			.tcp.source = 80,
288ae173a91SStanislav Fomichev 			.tcp.dest = 8080,
289ae173a91SStanislav Fomichev 		},
290ae173a91SStanislav Fomichev 		.keys = {
291ae173a91SStanislav Fomichev 			.nhoff = ETH_HLEN,
292ae173a91SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct ipv6hdr) +
293ae173a91SStanislav Fomichev 				sizeof(struct frag_hdr),
294ae173a91SStanislav Fomichev 			.addr_proto = ETH_P_IPV6,
295ae173a91SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
296ae173a91SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
297ae173a91SStanislav Fomichev 			.is_frag = true,
298ae173a91SStanislav Fomichev 			.is_first_frag = true,
299ae173a91SStanislav Fomichev 		},
3005deedfbeSShmulik Ladkani 		.retval = BPF_OK,
301ae173a91SStanislav Fomichev 	},
30271c99e32SStanislav Fomichev 	{
30371c99e32SStanislav Fomichev 		.name = "ipv6-flow-label",
30471c99e32SStanislav Fomichev 		.pkt.ipv6 = {
30571c99e32SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
30671c99e32SStanislav Fomichev 			.iph.nexthdr = IPPROTO_TCP,
30771c99e32SStanislav Fomichev 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
30871c99e32SStanislav Fomichev 			.iph.flow_lbl = { 0xb, 0xee, 0xef },
30971c99e32SStanislav Fomichev 			.tcp.doff = 5,
31071c99e32SStanislav Fomichev 			.tcp.source = 80,
31171c99e32SStanislav Fomichev 			.tcp.dest = 8080,
31271c99e32SStanislav Fomichev 		},
31371c99e32SStanislav Fomichev 		.keys = {
31471c99e32SStanislav Fomichev 			.nhoff = ETH_HLEN,
31571c99e32SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct ipv6hdr),
31671c99e32SStanislav Fomichev 			.addr_proto = ETH_P_IPV6,
31771c99e32SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
31871c99e32SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
31971c99e32SStanislav Fomichev 			.sport = 80,
32071c99e32SStanislav Fomichev 			.dport = 8080,
32171c99e32SStanislav Fomichev 			.flow_label = __bpf_constant_htonl(0xbeeef),
32271c99e32SStanislav Fomichev 		},
3235deedfbeSShmulik Ladkani 		.retval = BPF_OK,
32471c99e32SStanislav Fomichev 	},
32571c99e32SStanislav Fomichev 	{
32671c99e32SStanislav Fomichev 		.name = "ipv6-no-flow-label",
32771c99e32SStanislav Fomichev 		.pkt.ipv6 = {
32871c99e32SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
32971c99e32SStanislav Fomichev 			.iph.nexthdr = IPPROTO_TCP,
33071c99e32SStanislav Fomichev 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
33171c99e32SStanislav Fomichev 			.iph.flow_lbl = { 0xb, 0xee, 0xef },
33271c99e32SStanislav Fomichev 			.tcp.doff = 5,
33371c99e32SStanislav Fomichev 			.tcp.source = 80,
33471c99e32SStanislav Fomichev 			.tcp.dest = 8080,
33571c99e32SStanislav Fomichev 		},
33671c99e32SStanislav Fomichev 		.keys = {
33771c99e32SStanislav Fomichev 			.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
33871c99e32SStanislav Fomichev 			.nhoff = ETH_HLEN,
33971c99e32SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct ipv6hdr),
34071c99e32SStanislav Fomichev 			.addr_proto = ETH_P_IPV6,
34171c99e32SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
34271c99e32SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
34371c99e32SStanislav Fomichev 			.flow_label = __bpf_constant_htonl(0xbeeef),
34471c99e32SStanislav Fomichev 		},
34571c99e32SStanislav Fomichev 		.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
3465deedfbeSShmulik Ladkani 		.retval = BPF_OK,
34771c99e32SStanislav Fomichev 	},
348e853ae77SStanislav Fomichev 	{
349*9fa02892SStanislav Fomichev 		.name = "ipv6-empty-flow-label",
350*9fa02892SStanislav Fomichev 		.pkt.ipv6 = {
351*9fa02892SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
352*9fa02892SStanislav Fomichev 			.iph.nexthdr = IPPROTO_TCP,
353*9fa02892SStanislav Fomichev 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
354*9fa02892SStanislav Fomichev 			.iph.flow_lbl = { 0x00, 0x00, 0x00 },
355*9fa02892SStanislav Fomichev 			.tcp.doff = 5,
356*9fa02892SStanislav Fomichev 			.tcp.source = 80,
357*9fa02892SStanislav Fomichev 			.tcp.dest = 8080,
358*9fa02892SStanislav Fomichev 		},
359*9fa02892SStanislav Fomichev 		.keys = {
360*9fa02892SStanislav Fomichev 			.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
361*9fa02892SStanislav Fomichev 			.nhoff = ETH_HLEN,
362*9fa02892SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct ipv6hdr),
363*9fa02892SStanislav Fomichev 			.addr_proto = ETH_P_IPV6,
364*9fa02892SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
365*9fa02892SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
366*9fa02892SStanislav Fomichev 			.sport = 80,
367*9fa02892SStanislav Fomichev 			.dport = 8080,
368*9fa02892SStanislav Fomichev 		},
369*9fa02892SStanislav Fomichev 		.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
370*9fa02892SStanislav Fomichev 		.retval = BPF_OK,
371*9fa02892SStanislav Fomichev 	},
372*9fa02892SStanislav Fomichev 	{
373e853ae77SStanislav Fomichev 		.name = "ipip-encap",
374e853ae77SStanislav Fomichev 		.pkt.ipip = {
375e853ae77SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
376e853ae77SStanislav Fomichev 			.iph.ihl = 5,
377e853ae77SStanislav Fomichev 			.iph.protocol = IPPROTO_IPIP,
378e853ae77SStanislav Fomichev 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
379e853ae77SStanislav Fomichev 			.iph_inner.ihl = 5,
380e853ae77SStanislav Fomichev 			.iph_inner.protocol = IPPROTO_TCP,
381e853ae77SStanislav Fomichev 			.iph_inner.tot_len =
382e853ae77SStanislav Fomichev 				__bpf_constant_htons(MAGIC_BYTES) -
383e853ae77SStanislav Fomichev 				sizeof(struct iphdr),
384e853ae77SStanislav Fomichev 			.tcp.doff = 5,
385e853ae77SStanislav Fomichev 			.tcp.source = 80,
386e853ae77SStanislav Fomichev 			.tcp.dest = 8080,
387e853ae77SStanislav Fomichev 		},
388e853ae77SStanislav Fomichev 		.keys = {
389e853ae77SStanislav Fomichev 			.nhoff = ETH_HLEN,
390e853ae77SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct iphdr) +
391e853ae77SStanislav Fomichev 				sizeof(struct iphdr),
392e853ae77SStanislav Fomichev 			.addr_proto = ETH_P_IP,
393e853ae77SStanislav Fomichev 			.ip_proto = IPPROTO_TCP,
394e853ae77SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IP),
395e853ae77SStanislav Fomichev 			.is_encap = true,
396e853ae77SStanislav Fomichev 			.sport = 80,
397e853ae77SStanislav Fomichev 			.dport = 8080,
398e853ae77SStanislav Fomichev 		},
3995deedfbeSShmulik Ladkani 		.retval = BPF_OK,
400e853ae77SStanislav Fomichev 	},
401e853ae77SStanislav Fomichev 	{
402e853ae77SStanislav Fomichev 		.name = "ipip-no-encap",
403e853ae77SStanislav Fomichev 		.pkt.ipip = {
404e853ae77SStanislav Fomichev 			.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
405e853ae77SStanislav Fomichev 			.iph.ihl = 5,
406e853ae77SStanislav Fomichev 			.iph.protocol = IPPROTO_IPIP,
407e853ae77SStanislav Fomichev 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
408e853ae77SStanislav Fomichev 			.iph_inner.ihl = 5,
409e853ae77SStanislav Fomichev 			.iph_inner.protocol = IPPROTO_TCP,
410e853ae77SStanislav Fomichev 			.iph_inner.tot_len =
411e853ae77SStanislav Fomichev 				__bpf_constant_htons(MAGIC_BYTES) -
412e853ae77SStanislav Fomichev 				sizeof(struct iphdr),
413e853ae77SStanislav Fomichev 			.tcp.doff = 5,
414e853ae77SStanislav Fomichev 			.tcp.source = 80,
415e853ae77SStanislav Fomichev 			.tcp.dest = 8080,
416e853ae77SStanislav Fomichev 		},
417e853ae77SStanislav Fomichev 		.keys = {
418e853ae77SStanislav Fomichev 			.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP,
419e853ae77SStanislav Fomichev 			.nhoff = ETH_HLEN,
420e853ae77SStanislav Fomichev 			.thoff = ETH_HLEN + sizeof(struct iphdr),
421e853ae77SStanislav Fomichev 			.addr_proto = ETH_P_IP,
422e853ae77SStanislav Fomichev 			.ip_proto = IPPROTO_IPIP,
423e853ae77SStanislav Fomichev 			.n_proto = __bpf_constant_htons(ETH_P_IP),
424e853ae77SStanislav Fomichev 			.is_encap = true,
425e853ae77SStanislav Fomichev 		},
426e853ae77SStanislav Fomichev 		.flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP,
4275deedfbeSShmulik Ladkani 		.retval = BPF_OK,
428e853ae77SStanislav Fomichev 	},
429d6513727SShmulik Ladkani 	{
430d6513727SShmulik Ladkani 		.name = "ipip-encap-dissector-continue",
431d6513727SShmulik Ladkani 		.pkt.ipip = {
432d6513727SShmulik Ladkani 			.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
433d6513727SShmulik Ladkani 			.iph.ihl = 5,
434d6513727SShmulik Ladkani 			.iph.protocol = IPPROTO_IPIP,
435d6513727SShmulik Ladkani 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
436d6513727SShmulik Ladkani 			.iph.saddr = __bpf_constant_htonl(FLOW_CONTINUE_SADDR),
437d6513727SShmulik Ladkani 			.iph_inner.ihl = 5,
438d6513727SShmulik Ladkani 			.iph_inner.protocol = IPPROTO_TCP,
439d6513727SShmulik Ladkani 			.iph_inner.tot_len =
440d6513727SShmulik Ladkani 				__bpf_constant_htons(MAGIC_BYTES) -
441d6513727SShmulik Ladkani 				sizeof(struct iphdr),
442d6513727SShmulik Ladkani 			.tcp.doff = 5,
443d6513727SShmulik Ladkani 			.tcp.source = 99,
444d6513727SShmulik Ladkani 			.tcp.dest = 9090,
445d6513727SShmulik Ladkani 		},
446d6513727SShmulik Ladkani 		.retval = BPF_FLOW_DISSECTOR_CONTINUE,
447d6513727SShmulik Ladkani 	},
4482c3af7d9SStanislav Fomichev };
4492c3af7d9SStanislav Fomichev 
create_tap(const char * ifname)4500905beecSStanislav Fomichev static int create_tap(const char *ifname)
4510905beecSStanislav Fomichev {
4520905beecSStanislav Fomichev 	struct ifreq ifr = {
4530905beecSStanislav Fomichev 		.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS,
4540905beecSStanislav Fomichev 	};
4550905beecSStanislav Fomichev 	int fd, ret;
4560905beecSStanislav Fomichev 
4570905beecSStanislav Fomichev 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
4580905beecSStanislav Fomichev 
4590905beecSStanislav Fomichev 	fd = open("/dev/net/tun", O_RDWR);
4600905beecSStanislav Fomichev 	if (fd < 0)
4610905beecSStanislav Fomichev 		return -1;
4620905beecSStanislav Fomichev 
4630905beecSStanislav Fomichev 	ret = ioctl(fd, TUNSETIFF, &ifr);
4640905beecSStanislav Fomichev 	if (ret)
4650905beecSStanislav Fomichev 		return -1;
4660905beecSStanislav Fomichev 
4670905beecSStanislav Fomichev 	return fd;
4680905beecSStanislav Fomichev }
4690905beecSStanislav Fomichev 
tx_tap(int fd,void * pkt,size_t len)4700905beecSStanislav Fomichev static int tx_tap(int fd, void *pkt, size_t len)
4710905beecSStanislav Fomichev {
4720905beecSStanislav Fomichev 	struct iovec iov[] = {
4730905beecSStanislav Fomichev 		{
4740905beecSStanislav Fomichev 			.iov_len = len,
4750905beecSStanislav Fomichev 			.iov_base = pkt,
4760905beecSStanislav Fomichev 		},
4770905beecSStanislav Fomichev 	};
4780905beecSStanislav Fomichev 	return writev(fd, iov, ARRAY_SIZE(iov));
4790905beecSStanislav Fomichev }
4800905beecSStanislav Fomichev 
ifup(const char * ifname)4810905beecSStanislav Fomichev static int ifup(const char *ifname)
4820905beecSStanislav Fomichev {
4830905beecSStanislav Fomichev 	struct ifreq ifr = {};
4840905beecSStanislav Fomichev 	int sk, ret;
4850905beecSStanislav Fomichev 
4860905beecSStanislav Fomichev 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
4870905beecSStanislav Fomichev 
4880905beecSStanislav Fomichev 	sk = socket(PF_INET, SOCK_DGRAM, 0);
4890905beecSStanislav Fomichev 	if (sk < 0)
4900905beecSStanislav Fomichev 		return -1;
4910905beecSStanislav Fomichev 
4920905beecSStanislav Fomichev 	ret = ioctl(sk, SIOCGIFFLAGS, &ifr);
4930905beecSStanislav Fomichev 	if (ret) {
4940905beecSStanislav Fomichev 		close(sk);
4950905beecSStanislav Fomichev 		return -1;
4960905beecSStanislav Fomichev 	}
4970905beecSStanislav Fomichev 
4980905beecSStanislav Fomichev 	ifr.ifr_flags |= IFF_UP;
4990905beecSStanislav Fomichev 	ret = ioctl(sk, SIOCSIFFLAGS, &ifr);
5000905beecSStanislav Fomichev 	if (ret) {
5010905beecSStanislav Fomichev 		close(sk);
5020905beecSStanislav Fomichev 		return -1;
5030905beecSStanislav Fomichev 	}
5040905beecSStanislav Fomichev 
5050905beecSStanislav Fomichev 	close(sk);
5060905beecSStanislav Fomichev 	return 0;
5070905beecSStanislav Fomichev }
5080905beecSStanislav Fomichev 
init_prog_array(struct bpf_object * obj,struct bpf_map * prog_array)509b4b8a3bfSJakub Sitnicki static int init_prog_array(struct bpf_object *obj, struct bpf_map *prog_array)
510b4b8a3bfSJakub Sitnicki {
511b4b8a3bfSJakub Sitnicki 	int i, err, map_fd, prog_fd;
512b4b8a3bfSJakub Sitnicki 	struct bpf_program *prog;
513b4b8a3bfSJakub Sitnicki 	char prog_name[32];
514b4b8a3bfSJakub Sitnicki 
515b4b8a3bfSJakub Sitnicki 	map_fd = bpf_map__fd(prog_array);
516b4b8a3bfSJakub Sitnicki 	if (map_fd < 0)
517b4b8a3bfSJakub Sitnicki 		return -1;
518b4b8a3bfSJakub Sitnicki 
5198d6fabf1SChristy Lee 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
52015669e1dSAndrii Nakryiko 		snprintf(prog_name, sizeof(prog_name), "flow_dissector_%d", i);
521b4b8a3bfSJakub Sitnicki 
52215669e1dSAndrii Nakryiko 		prog = bpf_object__find_program_by_name(obj, prog_name);
523b4b8a3bfSJakub Sitnicki 		if (!prog)
524b4b8a3bfSJakub Sitnicki 			return -1;
525b4b8a3bfSJakub Sitnicki 
526b4b8a3bfSJakub Sitnicki 		prog_fd = bpf_program__fd(prog);
527b4b8a3bfSJakub Sitnicki 		if (prog_fd < 0)
528b4b8a3bfSJakub Sitnicki 			return -1;
529b4b8a3bfSJakub Sitnicki 
530b4b8a3bfSJakub Sitnicki 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
531b4b8a3bfSJakub Sitnicki 		if (err)
532b4b8a3bfSJakub Sitnicki 			return -1;
533b4b8a3bfSJakub Sitnicki 	}
534b4b8a3bfSJakub Sitnicki 	return 0;
535b4b8a3bfSJakub Sitnicki }
536b4b8a3bfSJakub Sitnicki 
run_tests_skb_less(int tap_fd,struct bpf_map * keys)53706716e04SJakub Sitnicki static void run_tests_skb_less(int tap_fd, struct bpf_map *keys)
53806716e04SJakub Sitnicki {
53906716e04SJakub Sitnicki 	int i, err, keys_fd;
54006716e04SJakub Sitnicki 
54106716e04SJakub Sitnicki 	keys_fd = bpf_map__fd(keys);
54206716e04SJakub Sitnicki 	if (CHECK(keys_fd < 0, "bpf_map__fd", "err %d\n", keys_fd))
54306716e04SJakub Sitnicki 		return;
54406716e04SJakub Sitnicki 
54506716e04SJakub Sitnicki 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
54606716e04SJakub Sitnicki 		/* Keep in sync with 'flags' from eth_get_headlen. */
54706716e04SJakub Sitnicki 		__u32 eth_get_headlen_flags =
54806716e04SJakub Sitnicki 			BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG;
54939316183SDelyan Kratunov 		LIBBPF_OPTS(bpf_test_run_opts, topts);
55006716e04SJakub Sitnicki 		struct bpf_flow_keys flow_keys = {};
55106716e04SJakub Sitnicki 		__u32 key = (__u32)(tests[i].keys.sport) << 16 |
55206716e04SJakub Sitnicki 			    tests[i].keys.dport;
55306716e04SJakub Sitnicki 
55406716e04SJakub Sitnicki 		/* For skb-less case we can't pass input flags; run
55506716e04SJakub Sitnicki 		 * only the tests that have a matching set of flags.
55606716e04SJakub Sitnicki 		 */
55706716e04SJakub Sitnicki 
55806716e04SJakub Sitnicki 		if (tests[i].flags != eth_get_headlen_flags)
55906716e04SJakub Sitnicki 			continue;
56006716e04SJakub Sitnicki 
56106716e04SJakub Sitnicki 		err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt));
56206716e04SJakub Sitnicki 		CHECK(err < 0, "tx_tap", "err %d errno %d\n", err, errno);
56306716e04SJakub Sitnicki 
5645deedfbeSShmulik Ladkani 		/* check the stored flow_keys only if BPF_OK expected */
5655deedfbeSShmulik Ladkani 		if (tests[i].retval != BPF_OK)
5665deedfbeSShmulik Ladkani 			continue;
5675deedfbeSShmulik Ladkani 
56806716e04SJakub Sitnicki 		err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys);
56939316183SDelyan Kratunov 		ASSERT_OK(err, "bpf_map_lookup_elem");
57006716e04SJakub Sitnicki 
57106716e04SJakub Sitnicki 		CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
57206716e04SJakub Sitnicki 
57306716e04SJakub Sitnicki 		err = bpf_map_delete_elem(keys_fd, &key);
57439316183SDelyan Kratunov 		ASSERT_OK(err, "bpf_map_delete_elem");
57506716e04SJakub Sitnicki 	}
57606716e04SJakub Sitnicki }
57706716e04SJakub Sitnicki 
test_skb_less_prog_attach(struct bpf_flow * skel,int tap_fd)57806716e04SJakub Sitnicki static void test_skb_less_prog_attach(struct bpf_flow *skel, int tap_fd)
57906716e04SJakub Sitnicki {
58006716e04SJakub Sitnicki 	int err, prog_fd;
58106716e04SJakub Sitnicki 
58206716e04SJakub Sitnicki 	prog_fd = bpf_program__fd(skel->progs._dissect);
58306716e04SJakub Sitnicki 	if (CHECK(prog_fd < 0, "bpf_program__fd", "err %d\n", prog_fd))
58406716e04SJakub Sitnicki 		return;
58506716e04SJakub Sitnicki 
58606716e04SJakub Sitnicki 	err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0);
58706716e04SJakub Sitnicki 	if (CHECK(err, "bpf_prog_attach", "err %d errno %d\n", err, errno))
58806716e04SJakub Sitnicki 		return;
58906716e04SJakub Sitnicki 
59006716e04SJakub Sitnicki 	run_tests_skb_less(tap_fd, skel->maps.last_dissection);
59106716e04SJakub Sitnicki 
5921a1ad3c2SLorenz Bauer 	err = bpf_prog_detach2(prog_fd, 0, BPF_FLOW_DISSECTOR);
5931a1ad3c2SLorenz Bauer 	CHECK(err, "bpf_prog_detach2", "err %d errno %d\n", err, errno);
59406716e04SJakub Sitnicki }
59506716e04SJakub Sitnicki 
test_skb_less_link_create(struct bpf_flow * skel,int tap_fd)59606716e04SJakub Sitnicki static void test_skb_less_link_create(struct bpf_flow *skel, int tap_fd)
59706716e04SJakub Sitnicki {
59806716e04SJakub Sitnicki 	struct bpf_link *link;
59906716e04SJakub Sitnicki 	int err, net_fd;
60006716e04SJakub Sitnicki 
60106716e04SJakub Sitnicki 	net_fd = open("/proc/self/ns/net", O_RDONLY);
60206716e04SJakub Sitnicki 	if (CHECK(net_fd < 0, "open(/proc/self/ns/net)", "err %d\n", errno))
60306716e04SJakub Sitnicki 		return;
60406716e04SJakub Sitnicki 
60506716e04SJakub Sitnicki 	link = bpf_program__attach_netns(skel->progs._dissect, net_fd);
606bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(link, "attach_netns"))
60706716e04SJakub Sitnicki 		goto out_close;
60806716e04SJakub Sitnicki 
60906716e04SJakub Sitnicki 	run_tests_skb_less(tap_fd, skel->maps.last_dissection);
61006716e04SJakub Sitnicki 
61106716e04SJakub Sitnicki 	err = bpf_link__destroy(link);
61206716e04SJakub Sitnicki 	CHECK(err, "bpf_link__destroy", "err %d\n", err);
61306716e04SJakub Sitnicki out_close:
61406716e04SJakub Sitnicki 	close(net_fd);
61506716e04SJakub Sitnicki }
61606716e04SJakub Sitnicki 
test_flow_dissector(void)617886225bbSStanislav Fomichev void test_flow_dissector(void)
618886225bbSStanislav Fomichev {
6190905beecSStanislav Fomichev 	int i, err, prog_fd, keys_fd = -1, tap_fd;
620b4b8a3bfSJakub Sitnicki 	struct bpf_flow *skel;
621886225bbSStanislav Fomichev 
622b4b8a3bfSJakub Sitnicki 	skel = bpf_flow__open_and_load();
623b4b8a3bfSJakub Sitnicki 	if (CHECK(!skel, "skel", "failed to open/load skeleton\n"))
624886225bbSStanislav Fomichev 		return;
625886225bbSStanislav Fomichev 
626b4b8a3bfSJakub Sitnicki 	prog_fd = bpf_program__fd(skel->progs._dissect);
627b4b8a3bfSJakub Sitnicki 	if (CHECK(prog_fd < 0, "bpf_program__fd", "err %d\n", prog_fd))
628b4b8a3bfSJakub Sitnicki 		goto out_destroy_skel;
629b4b8a3bfSJakub Sitnicki 	keys_fd = bpf_map__fd(skel->maps.last_dissection);
630b4b8a3bfSJakub Sitnicki 	if (CHECK(keys_fd < 0, "bpf_map__fd", "err %d\n", keys_fd))
631b4b8a3bfSJakub Sitnicki 		goto out_destroy_skel;
632b4b8a3bfSJakub Sitnicki 	err = init_prog_array(skel->obj, skel->maps.jmp_table);
633b4b8a3bfSJakub Sitnicki 	if (CHECK(err, "init_prog_array", "err %d\n", err))
634b4b8a3bfSJakub Sitnicki 		goto out_destroy_skel;
635b4b8a3bfSJakub Sitnicki 
636ba02de1aSYonghong Song 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
637a5cb3346SStanislav Fomichev 		struct bpf_flow_keys flow_keys;
63839316183SDelyan Kratunov 		LIBBPF_OPTS(bpf_test_run_opts, topts,
639a5cb3346SStanislav Fomichev 			.data_in = &tests[i].pkt,
640a5cb3346SStanislav Fomichev 			.data_size_in = sizeof(tests[i].pkt),
641a5cb3346SStanislav Fomichev 			.data_out = &flow_keys,
64239316183SDelyan Kratunov 		);
643ae173a91SStanislav Fomichev 		static struct bpf_flow_keys ctx = {};
644ae173a91SStanislav Fomichev 
645ae173a91SStanislav Fomichev 		if (tests[i].flags) {
64639316183SDelyan Kratunov 			topts.ctx_in = &ctx;
64739316183SDelyan Kratunov 			topts.ctx_size_in = sizeof(ctx);
648ae173a91SStanislav Fomichev 			ctx.flags = tests[i].flags;
649ae173a91SStanislav Fomichev 		}
650886225bbSStanislav Fomichev 
65139316183SDelyan Kratunov 		err = bpf_prog_test_run_opts(prog_fd, &topts);
65239316183SDelyan Kratunov 		ASSERT_OK(err, "test_run");
6535deedfbeSShmulik Ladkani 		ASSERT_EQ(topts.retval, tests[i].retval, "test_run retval");
6545deedfbeSShmulik Ladkani 
6555deedfbeSShmulik Ladkani 		/* check the resulting flow_keys only if BPF_OK returned */
6565deedfbeSShmulik Ladkani 		if (topts.retval != BPF_OK)
6575deedfbeSShmulik Ladkani 			continue;
65839316183SDelyan Kratunov 		ASSERT_EQ(topts.data_size_out, sizeof(flow_keys),
65939316183SDelyan Kratunov 			  "test_run data_size_out");
660a5cb3346SStanislav Fomichev 		CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
661a5cb3346SStanislav Fomichev 	}
6622c3af7d9SStanislav Fomichev 
6630905beecSStanislav Fomichev 	/* Do the same tests but for skb-less flow dissector.
6640905beecSStanislav Fomichev 	 * We use a known path in the net/tun driver that calls
6650905beecSStanislav Fomichev 	 * eth_get_headlen and we manually export bpf_flow_keys
6660905beecSStanislav Fomichev 	 * via BPF map in this case.
6670905beecSStanislav Fomichev 	 */
6680905beecSStanislav Fomichev 
6690905beecSStanislav Fomichev 	tap_fd = create_tap("tap0");
670a9047734SStanislav Fomichev 	CHECK(tap_fd < 0, "create_tap", "tap_fd %d errno %d\n", tap_fd, errno);
6710905beecSStanislav Fomichev 	err = ifup("tap0");
672a9047734SStanislav Fomichev 	CHECK(err, "ifup", "err %d errno %d\n", err, errno);
6730905beecSStanislav Fomichev 
67406716e04SJakub Sitnicki 	/* Test direct prog attachment */
67506716e04SJakub Sitnicki 	test_skb_less_prog_attach(skel, tap_fd);
67606716e04SJakub Sitnicki 	/* Test indirect prog attachment via link */
67706716e04SJakub Sitnicki 	test_skb_less_link_create(skel, tap_fd);
6780905beecSStanislav Fomichev 
679b8215dceSJakub Sitnicki 	close(tap_fd);
680b4b8a3bfSJakub Sitnicki out_destroy_skel:
681b4b8a3bfSJakub Sitnicki 	bpf_flow__destroy(skel);
682886225bbSStanislav Fomichev }
683