1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 
4 #define CHECK_FLOW_KEYS(desc, got, expected)				\
5 	CHECK(memcmp(&got, &expected, sizeof(got)) != 0,		\
6 	      desc,							\
7 	      "nhoff=%u/%u "						\
8 	      "thoff=%u/%u "						\
9 	      "addr_proto=0x%x/0x%x "					\
10 	      "is_frag=%u/%u "						\
11 	      "is_first_frag=%u/%u "					\
12 	      "is_encap=%u/%u "						\
13 	      "n_proto=0x%x/0x%x "					\
14 	      "sport=%u/%u "						\
15 	      "dport=%u/%u\n",						\
16 	      got.nhoff, expected.nhoff,				\
17 	      got.thoff, expected.thoff,				\
18 	      got.addr_proto, expected.addr_proto,			\
19 	      got.is_frag, expected.is_frag,				\
20 	      got.is_first_frag, expected.is_first_frag,		\
21 	      got.is_encap, expected.is_encap,				\
22 	      got.n_proto, expected.n_proto,				\
23 	      got.sport, expected.sport,				\
24 	      got.dport, expected.dport)
25 
26 static struct bpf_flow_keys pkt_v4_flow_keys = {
27 	.nhoff = 0,
28 	.thoff = sizeof(struct iphdr),
29 	.addr_proto = ETH_P_IP,
30 	.ip_proto = IPPROTO_TCP,
31 	.n_proto = __bpf_constant_htons(ETH_P_IP),
32 };
33 
34 static struct bpf_flow_keys pkt_v6_flow_keys = {
35 	.nhoff = 0,
36 	.thoff = sizeof(struct ipv6hdr),
37 	.addr_proto = ETH_P_IPV6,
38 	.ip_proto = IPPROTO_TCP,
39 	.n_proto = __bpf_constant_htons(ETH_P_IPV6),
40 };
41 
42 #define VLAN_HLEN	4
43 
44 static struct {
45 	struct ethhdr eth;
46 	__u16 vlan_tci;
47 	__u16 vlan_proto;
48 	struct iphdr iph;
49 	struct tcphdr tcp;
50 } __packed pkt_vlan_v4 = {
51 	.eth.h_proto = __bpf_constant_htons(ETH_P_8021Q),
52 	.vlan_proto = __bpf_constant_htons(ETH_P_IP),
53 	.iph.ihl = 5,
54 	.iph.protocol = IPPROTO_TCP,
55 	.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
56 	.tcp.urg_ptr = 123,
57 	.tcp.doff = 5,
58 };
59 
60 static struct bpf_flow_keys pkt_vlan_v4_flow_keys = {
61 	.nhoff = VLAN_HLEN,
62 	.thoff = VLAN_HLEN + sizeof(struct iphdr),
63 	.addr_proto = ETH_P_IP,
64 	.ip_proto = IPPROTO_TCP,
65 	.n_proto = __bpf_constant_htons(ETH_P_IP),
66 };
67 
68 static struct {
69 	struct ethhdr eth;
70 	__u16 vlan_tci;
71 	__u16 vlan_proto;
72 	__u16 vlan_tci2;
73 	__u16 vlan_proto2;
74 	struct ipv6hdr iph;
75 	struct tcphdr tcp;
76 } __packed pkt_vlan_v6 = {
77 	.eth.h_proto = __bpf_constant_htons(ETH_P_8021AD),
78 	.vlan_proto = __bpf_constant_htons(ETH_P_8021Q),
79 	.vlan_proto2 = __bpf_constant_htons(ETH_P_IPV6),
80 	.iph.nexthdr = IPPROTO_TCP,
81 	.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
82 	.tcp.urg_ptr = 123,
83 	.tcp.doff = 5,
84 };
85 
86 static struct bpf_flow_keys pkt_vlan_v6_flow_keys = {
87 	.nhoff = VLAN_HLEN * 2,
88 	.thoff = VLAN_HLEN * 2 + sizeof(struct ipv6hdr),
89 	.addr_proto = ETH_P_IPV6,
90 	.ip_proto = IPPROTO_TCP,
91 	.n_proto = __bpf_constant_htons(ETH_P_IPV6),
92 };
93 
94 void test_flow_dissector(void)
95 {
96 	struct bpf_flow_keys flow_keys;
97 	struct bpf_object *obj;
98 	__u32 duration, retval;
99 	int err, prog_fd;
100 	__u32 size;
101 
102 	err = bpf_flow_load(&obj, "./bpf_flow.o", "flow_dissector",
103 			    "jmp_table", &prog_fd);
104 	if (err) {
105 		error_cnt++;
106 		return;
107 	}
108 
109 	err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4),
110 				&flow_keys, &size, &retval, &duration);
111 	CHECK(size != sizeof(flow_keys) || err || retval != 1, "ipv4",
112 	      "err %d errno %d retval %d duration %d size %u/%lu\n",
113 	      err, errno, retval, duration, size, sizeof(flow_keys));
114 	CHECK_FLOW_KEYS("ipv4_flow_keys", flow_keys, pkt_v4_flow_keys);
115 
116 	err = bpf_prog_test_run(prog_fd, 10, &pkt_v6, sizeof(pkt_v6),
117 				&flow_keys, &size, &retval, &duration);
118 	CHECK(size != sizeof(flow_keys) || err || retval != 1, "ipv6",
119 	      "err %d errno %d retval %d duration %d size %u/%lu\n",
120 	      err, errno, retval, duration, size, sizeof(flow_keys));
121 	CHECK_FLOW_KEYS("ipv6_flow_keys", flow_keys, pkt_v6_flow_keys);
122 
123 	err = bpf_prog_test_run(prog_fd, 10, &pkt_vlan_v4, sizeof(pkt_vlan_v4),
124 				&flow_keys, &size, &retval, &duration);
125 	CHECK(size != sizeof(flow_keys) || err || retval != 1, "vlan_ipv4",
126 	      "err %d errno %d retval %d duration %d size %u/%lu\n",
127 	      err, errno, retval, duration, size, sizeof(flow_keys));
128 	CHECK_FLOW_KEYS("vlan_ipv4_flow_keys", flow_keys,
129 			pkt_vlan_v4_flow_keys);
130 
131 	err = bpf_prog_test_run(prog_fd, 10, &pkt_vlan_v6, sizeof(pkt_vlan_v6),
132 				&flow_keys, &size, &retval, &duration);
133 	CHECK(size != sizeof(flow_keys) || err || retval != 1, "vlan_ipv6",
134 	      "err %d errno %d retval %d duration %d size %u/%lu\n",
135 	      err, errno, retval, duration, size, sizeof(flow_keys));
136 	CHECK_FLOW_KEYS("vlan_ipv6_flow_keys", flow_keys,
137 			pkt_vlan_v6_flow_keys);
138 
139 	bpf_object__close(obj);
140 }
141