1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 
4 #define CHECK_FLOW_KEYS(desc, got, expected)				\
5 	CHECK_ATTR(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 	      "ip_proto=0x%x/0x%x "					\
14 	      "n_proto=0x%x/0x%x "					\
15 	      "sport=%u/%u "						\
16 	      "dport=%u/%u\n",						\
17 	      got.nhoff, expected.nhoff,				\
18 	      got.thoff, expected.thoff,				\
19 	      got.addr_proto, expected.addr_proto,			\
20 	      got.is_frag, expected.is_frag,				\
21 	      got.is_first_frag, expected.is_first_frag,		\
22 	      got.is_encap, expected.is_encap,				\
23 	      got.ip_proto, expected.ip_proto,				\
24 	      got.n_proto, expected.n_proto,				\
25 	      got.sport, expected.sport,				\
26 	      got.dport, expected.dport)
27 
28 struct ipv4_pkt {
29 	struct ethhdr eth;
30 	struct iphdr iph;
31 	struct tcphdr tcp;
32 } __packed;
33 
34 struct svlan_ipv4_pkt {
35 	struct ethhdr eth;
36 	__u16 vlan_tci;
37 	__u16 vlan_proto;
38 	struct iphdr iph;
39 	struct tcphdr tcp;
40 } __packed;
41 
42 struct ipv6_pkt {
43 	struct ethhdr eth;
44 	struct ipv6hdr iph;
45 	struct tcphdr tcp;
46 } __packed;
47 
48 struct dvlan_ipv6_pkt {
49 	struct ethhdr eth;
50 	__u16 vlan_tci;
51 	__u16 vlan_proto;
52 	__u16 vlan_tci2;
53 	__u16 vlan_proto2;
54 	struct ipv6hdr iph;
55 	struct tcphdr tcp;
56 } __packed;
57 
58 struct test {
59 	const char *name;
60 	union {
61 		struct ipv4_pkt ipv4;
62 		struct svlan_ipv4_pkt svlan_ipv4;
63 		struct ipv6_pkt ipv6;
64 		struct dvlan_ipv6_pkt dvlan_ipv6;
65 	} pkt;
66 	struct bpf_flow_keys keys;
67 };
68 
69 #define VLAN_HLEN	4
70 
71 struct test tests[] = {
72 	{
73 		.name = "ipv4",
74 		.pkt.ipv4 = {
75 			.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
76 			.iph.ihl = 5,
77 			.iph.protocol = IPPROTO_TCP,
78 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
79 			.tcp.doff = 5,
80 		},
81 		.keys = {
82 			.nhoff = 0,
83 			.thoff = sizeof(struct iphdr),
84 			.addr_proto = ETH_P_IP,
85 			.ip_proto = IPPROTO_TCP,
86 			.n_proto = __bpf_constant_htons(ETH_P_IP),
87 		},
88 	},
89 	{
90 		.name = "ipv6",
91 		.pkt.ipv6 = {
92 			.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
93 			.iph.nexthdr = IPPROTO_TCP,
94 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
95 			.tcp.doff = 5,
96 		},
97 		.keys = {
98 			.nhoff = 0,
99 			.thoff = sizeof(struct ipv6hdr),
100 			.addr_proto = ETH_P_IPV6,
101 			.ip_proto = IPPROTO_TCP,
102 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
103 		},
104 	},
105 	{
106 		.name = "802.1q-ipv4",
107 		.pkt.svlan_ipv4 = {
108 			.eth.h_proto = __bpf_constant_htons(ETH_P_8021Q),
109 			.vlan_proto = __bpf_constant_htons(ETH_P_IP),
110 			.iph.ihl = 5,
111 			.iph.protocol = IPPROTO_TCP,
112 			.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
113 			.tcp.doff = 5,
114 		},
115 		.keys = {
116 			.nhoff = VLAN_HLEN,
117 			.thoff = VLAN_HLEN + sizeof(struct iphdr),
118 			.addr_proto = ETH_P_IP,
119 			.ip_proto = IPPROTO_TCP,
120 			.n_proto = __bpf_constant_htons(ETH_P_IP),
121 		},
122 	},
123 	{
124 		.name = "802.1ad-ipv6",
125 		.pkt.dvlan_ipv6 = {
126 			.eth.h_proto = __bpf_constant_htons(ETH_P_8021AD),
127 			.vlan_proto = __bpf_constant_htons(ETH_P_8021Q),
128 			.vlan_proto2 = __bpf_constant_htons(ETH_P_IPV6),
129 			.iph.nexthdr = IPPROTO_TCP,
130 			.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
131 			.tcp.doff = 5,
132 		},
133 		.keys = {
134 			.nhoff = VLAN_HLEN * 2,
135 			.thoff = VLAN_HLEN * 2 + sizeof(struct ipv6hdr),
136 			.addr_proto = ETH_P_IPV6,
137 			.ip_proto = IPPROTO_TCP,
138 			.n_proto = __bpf_constant_htons(ETH_P_IPV6),
139 		},
140 	},
141 };
142 
143 void test_flow_dissector(void)
144 {
145 	struct bpf_object *obj;
146 	int i, err, prog_fd;
147 
148 	err = bpf_flow_load(&obj, "./bpf_flow.o", "flow_dissector",
149 			    "jmp_table", &prog_fd);
150 	if (err) {
151 		error_cnt++;
152 		return;
153 	}
154 
155 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
156 		struct bpf_flow_keys flow_keys;
157 		struct bpf_prog_test_run_attr tattr = {
158 			.prog_fd = prog_fd,
159 			.data_in = &tests[i].pkt,
160 			.data_size_in = sizeof(tests[i].pkt),
161 			.data_out = &flow_keys,
162 		};
163 
164 		err = bpf_prog_test_run_xattr(&tattr);
165 		CHECK_ATTR(tattr.data_size_out != sizeof(flow_keys) ||
166 			   err || tattr.retval != 1,
167 			   tests[i].name,
168 			   "err %d errno %d retval %d duration %d size %u/%lu\n",
169 			   err, errno, tattr.retval, tattr.duration,
170 			   tattr.data_size_out, sizeof(flow_keys));
171 		CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
172 	}
173 
174 	bpf_object__close(obj);
175 }
176