/src/openvswitch/tests/oss-fuzz/miniflow_target.c
Line | Count | Source |
1 | | #include <config.h> |
2 | | #include "classifier.h" |
3 | | #include "fuzzer.h" |
4 | | #include "dp-packet.h" |
5 | | #include "flow.h" |
6 | | #include "openvswitch/ofp-match.h" |
7 | | #include "openvswitch/ofp-print.h" |
8 | | #include "openvswitch/match.h" |
9 | | #include "classifier-private.h" |
10 | | #include "util.h" |
11 | | |
12 | | /* Returns a copy of 'src'. The caller must eventually free the returned |
13 | | * miniflow with free(). */ |
14 | | static struct miniflow * |
15 | | miniflow_clone__(const struct miniflow *src) |
16 | 2.03k | { |
17 | 2.03k | struct miniflow *dst; |
18 | 2.03k | size_t data_size; |
19 | | |
20 | 2.03k | data_size = miniflow_alloc(&dst, 1, src); |
21 | 2.03k | miniflow_clone(dst, src, data_size / sizeof(uint64_t)); |
22 | 2.03k | return dst; |
23 | 2.03k | } |
24 | | |
25 | | /* Returns a hash value for 'flow', given 'basis'. */ |
26 | | static inline uint32_t |
27 | | miniflow_hash__(const struct miniflow *flow, uint32_t basis) |
28 | 6.09k | { |
29 | 6.09k | const uint64_t *p = miniflow_get_values(flow); |
30 | 6.09k | size_t n_values = miniflow_n_values(flow); |
31 | 6.09k | struct flowmap hash_map = FLOWMAP_EMPTY_INITIALIZER; |
32 | 6.09k | uint32_t hash = basis; |
33 | 6.09k | size_t idx; |
34 | | |
35 | 53.5k | FLOWMAP_FOR_EACH_INDEX (idx, flow->map) { |
36 | 53.5k | uint64_t value = *p++; |
37 | | |
38 | 53.5k | if (value) { |
39 | 53.5k | hash = hash_add64(hash, value); |
40 | 53.5k | flowmap_set(&hash_map, idx, 1); |
41 | 53.5k | } |
42 | 53.5k | } |
43 | 6.09k | map_t map; |
44 | 12.1k | FLOWMAP_FOR_EACH_MAP (map, hash_map) { |
45 | 12.1k | hash = hash_add64(hash, map); |
46 | 12.1k | } |
47 | | |
48 | 6.09k | return hash_finish(hash, n_values); |
49 | 6.09k | } |
50 | | |
51 | 682k | #define FLOW_U32S (FLOW_U64S * 2) |
52 | | |
53 | | static void |
54 | | toggle_masked_flow_bits(struct flow *flow, const struct flow_wildcards *mask) |
55 | 2.03k | { |
56 | 2.03k | const uint32_t *mask_u32 = (const uint32_t *) &mask->masks; |
57 | 2.03k | uint32_t *flow_u32 = (uint32_t *) flow; |
58 | 2.03k | int i; |
59 | | |
60 | 343k | for (i = 0; i < FLOW_U32S; i++) { |
61 | 341k | if (mask_u32[i] != 0) { |
62 | 58.3k | uint32_t bit; |
63 | | |
64 | 125k | do { |
65 | 125k | bit = 1u << random_range(32); |
66 | 125k | } while (!(bit & mask_u32[i])); |
67 | 58.3k | flow_u32[i] ^= bit; |
68 | 58.3k | } |
69 | 341k | } |
70 | 2.03k | } |
71 | | |
72 | | static void |
73 | | wildcard_extra_bits(struct flow_wildcards *mask) |
74 | 2.00k | { |
75 | 2.00k | uint32_t *mask_u32 = (uint32_t *) &mask->masks; |
76 | 2.00k | int i; |
77 | | |
78 | 339k | for (i = 0; i < FLOW_U32S; i++) { |
79 | 337k | if (mask_u32[i] != 0) { |
80 | 18.3k | uint32_t bit; |
81 | | |
82 | 98.1k | do { |
83 | 98.1k | bit = 1u << random_range(32); |
84 | 98.1k | } while (!(bit & mask_u32[i])); |
85 | 18.3k | mask_u32[i] &= ~bit; |
86 | 18.3k | } |
87 | 337k | } |
88 | 2.00k | } |
89 | | |
90 | | static void |
91 | | test_miniflow(struct flow *flow) |
92 | 2.03k | { |
93 | 2.03k | struct miniflow *miniflow, *miniflow2, *miniflow3; |
94 | 2.03k | struct flow flow2, flow3; |
95 | 2.03k | struct flow_wildcards mask; |
96 | 2.03k | struct minimask *minimask; |
97 | 2.03k | int i; |
98 | | |
99 | 2.03k | const uint64_t *flow_u64 = (const uint64_t *) flow; |
100 | | |
101 | | /* Convert flow to miniflow. */ |
102 | 2.03k | miniflow = miniflow_create(flow); |
103 | | |
104 | | /* Obtain miniflow hash. */ |
105 | 2.03k | uint32_t hash = miniflow_hash_5tuple(miniflow, 0); |
106 | 2.03k | ovs_ignore(hash); |
107 | | |
108 | | /* Check that the flow equals its miniflow. */ |
109 | 6.09k | for (i = 0; i < FLOW_MAX_VLAN_HEADERS; i++) { |
110 | 4.06k | ovs_assert(miniflow_get_vid(miniflow, i) == |
111 | 4.06k | vlan_tci_to_vid(flow->vlans[i].tci)); |
112 | 4.06k | } |
113 | 172k | for (i = 0; i < FLOW_U64S; i++) { |
114 | 170k | ovs_assert(miniflow_get(miniflow, i) == flow_u64[i]); |
115 | 170k | } |
116 | | |
117 | | /* Check that the miniflow equals itself. */ |
118 | 2.03k | ovs_assert(miniflow_equal(miniflow, miniflow)); |
119 | | |
120 | | /* Convert miniflow back to flow and verify that it's the same. */ |
121 | 2.03k | miniflow_expand(miniflow, &flow2); |
122 | 2.03k | ovs_assert(flow_equal(flow, &flow2)); |
123 | | /* Check that copying a miniflow works properly. */ |
124 | 2.03k | miniflow2 = miniflow_clone__(miniflow); |
125 | 2.03k | ovs_assert(miniflow_equal(miniflow, miniflow2)); |
126 | 2.03k | ovs_assert(miniflow_hash__(miniflow, 0) == miniflow_hash__(miniflow2, 0)); |
127 | 2.03k | miniflow_expand(miniflow2, &flow3); |
128 | 2.03k | ovs_assert(flow_equal(flow, &flow3)); |
129 | | |
130 | | /* Check that masked matches work as expected for identical flows and |
131 | | * miniflows. */ |
132 | 2.03k | flow_wildcards_init_for_packet(&mask, flow); |
133 | | /* Ensure that mask is not catchall just in case |
134 | | * flow_wildcards_init_for_packet returns a catchall mask |
135 | | */ |
136 | 2.03k | uint64_t *mask_u64 = (uint64_t *) &mask.masks; |
137 | 2.03k | mask_u64[0] = 1; |
138 | 2.03k | ovs_assert(!flow_wildcards_is_catchall(&mask)); |
139 | 2.03k | minimask = minimask_create(&mask); |
140 | 2.03k | ovs_assert(!minimask_is_catchall(minimask)); |
141 | 2.03k | ovs_assert(miniflow_equal_in_minimask(miniflow, miniflow2, minimask)); |
142 | 2.03k | ovs_assert(miniflow_equal_flow_in_minimask(miniflow, &flow2, minimask)); |
143 | 2.03k | ovs_assert(miniflow_hash_in_minimask(miniflow, minimask, 0x12345678) == |
144 | 2.03k | flow_hash_in_minimask(flow, minimask, 0x12345678)); |
145 | 2.03k | ovs_assert(minimask_hash(minimask, 0) == |
146 | 2.03k | miniflow_hash__(&minimask->masks, 0)); |
147 | | |
148 | | /* Check that masked matches work as expected for differing flows and |
149 | | * miniflows. */ |
150 | 2.03k | toggle_masked_flow_bits(&flow2, &mask); |
151 | 2.03k | ovs_assert(!miniflow_equal_flow_in_minimask(miniflow, &flow2, minimask)); |
152 | 2.03k | miniflow3 = miniflow_create(&flow2); |
153 | 2.03k | ovs_assert(!miniflow_equal_in_minimask(miniflow, miniflow3, minimask)); |
154 | | |
155 | 2.03k | free(miniflow); |
156 | 2.03k | free(miniflow2); |
157 | 2.03k | free(miniflow3); |
158 | 2.03k | free(minimask); |
159 | 2.03k | } |
160 | | |
161 | | static void |
162 | | test_minimask_has_extra(struct flow *flow) |
163 | 2.03k | { |
164 | 2.03k | struct flow_wildcards catchall; |
165 | 2.03k | struct minimask *minicatchall; |
166 | | |
167 | 2.03k | flow_wildcards_init_catchall(&catchall); |
168 | 2.03k | minicatchall = minimask_create(&catchall); |
169 | 2.03k | ovs_assert(minimask_is_catchall(minicatchall)); |
170 | | |
171 | 2.03k | struct flow_wildcards mask; |
172 | 2.03k | struct minimask *minimask; |
173 | | |
174 | 2.03k | mask.masks = *flow; |
175 | 2.03k | minimask = minimask_create(&mask); |
176 | 2.03k | ovs_assert(!minimask_has_extra(minimask, minimask)); |
177 | 2.03k | ovs_assert(minimask_has_extra(minicatchall, minimask) |
178 | 2.03k | == !minimask_is_catchall(minimask)); |
179 | 2.03k | if (!minimask_is_catchall(minimask)) { |
180 | 2.00k | struct minimask *minimask2; |
181 | | |
182 | 2.00k | wildcard_extra_bits(&mask); |
183 | 2.00k | minimask2 = minimask_create(&mask); |
184 | 2.00k | ovs_assert(minimask_has_extra(minimask2, minimask)); |
185 | 2.00k | ovs_assert(!minimask_has_extra(minimask, minimask2)); |
186 | 2.00k | free(minimask2); |
187 | 2.00k | } |
188 | | |
189 | 2.03k | free(minimask); |
190 | 2.03k | free(minicatchall); |
191 | 2.03k | } |
192 | | |
193 | | static void |
194 | | test_minimask_combine(struct flow *flow) |
195 | 2.03k | { |
196 | 2.03k | struct flow_wildcards catchall; |
197 | 2.03k | struct minimask *minicatchall; |
198 | | |
199 | 2.03k | flow_wildcards_init_catchall(&catchall); |
200 | 2.03k | minicatchall = minimask_create(&catchall); |
201 | 2.03k | ovs_assert(minimask_is_catchall(minicatchall)); |
202 | | |
203 | 2.03k | struct minimask *minimask, *minimask2; |
204 | 2.03k | struct flow_wildcards mask, mask2, combined, combined2; |
205 | 2.03k | struct { |
206 | 2.03k | struct minimask minicombined; |
207 | 2.03k | uint64_t storage[FLOW_U64S]; |
208 | 2.03k | } m; |
209 | 2.03k | struct flow flow2; |
210 | | |
211 | 2.03k | memset(&flow2, 0, sizeof flow2); |
212 | 2.03k | mask.masks = *flow; |
213 | 2.03k | minimask = minimask_create(&mask); |
214 | | |
215 | 2.03k | minimask_combine(&m.minicombined, minimask, minicatchall, m.storage); |
216 | 2.03k | ovs_assert(minimask_is_catchall(&m.minicombined)); |
217 | | |
218 | | /* Create mask based on zero flow */ |
219 | 2.03k | mask2.masks = flow2; |
220 | 2.03k | minimask2 = minimask_create(&mask2); |
221 | | |
222 | 2.03k | minimask_combine(&m.minicombined, minimask, minimask2, m.storage); |
223 | 2.03k | flow_wildcards_and(&combined, &mask, &mask2); |
224 | 2.03k | minimask_expand(&m.minicombined, &combined2); |
225 | 2.03k | ovs_assert(flow_wildcards_equal(&combined, &combined2)); |
226 | | |
227 | 2.03k | free(minimask); |
228 | 2.03k | free(minimask2); |
229 | | |
230 | 2.03k | free(minicatchall); |
231 | 2.03k | } |
232 | | |
233 | | int |
234 | | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
235 | 2.03k | { |
236 | 2.03k | struct dp_packet packet; |
237 | 2.03k | struct flow flow; |
238 | 2.03k | dp_packet_use_const(&packet, data, size); |
239 | 2.03k | flow_extract(&packet, &flow); |
240 | | |
241 | | /* Do miniflow tests. */ |
242 | 2.03k | test_miniflow(&flow); |
243 | 2.03k | test_minimask_has_extra(&flow); |
244 | 2.03k | test_minimask_combine(&flow); |
245 | | |
246 | 2.03k | return 0; |
247 | 2.03k | } |