2 #include "classifier.h"
6 #include "openvswitch/ofp-match.h"
7 #include "openvswitch/ofp-print.h"
8 #include "openvswitch/match.h"
9 #include "classifier-private.h"
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
)
20 data_size
= miniflow_alloc(&dst
, 1, src
);
21 miniflow_clone(dst
, src
, data_size
/ sizeof(uint64_t));
25 /* Returns a hash value for 'flow', given 'basis'. */
26 static inline uint32_t
27 miniflow_hash__(const struct miniflow
*flow
, uint32_t basis
)
29 const uint64_t *p
= miniflow_get_values(flow
);
30 size_t n_values
= miniflow_n_values(flow
);
31 struct flowmap hash_map
= FLOWMAP_EMPTY_INITIALIZER
;
32 uint32_t hash
= basis
;
35 FLOWMAP_FOR_EACH_INDEX (idx
, flow
->map
) {
36 uint64_t value
= *p
++;
39 hash
= hash_add64(hash
, value
);
40 flowmap_set(&hash_map
, idx
, 1);
44 FLOWMAP_FOR_EACH_MAP (map
, hash_map
) {
45 hash
= hash_add64(hash
, map
);
48 return hash_finish(hash
, n_values
);
51 #define FLOW_U32S (FLOW_U64S * 2)
54 toggle_masked_flow_bits(struct flow
*flow
, const struct flow_wildcards
*mask
)
56 const uint32_t *mask_u32
= (const uint32_t *) &mask
->masks
;
57 uint32_t *flow_u32
= (uint32_t *) flow
;
60 for (i
= 0; i
< FLOW_U32S
; i
++) {
61 if (mask_u32
[i
] != 0) {
65 bit
= 1u << random_range(32);
66 } while (!(bit
& mask_u32
[i
]));
73 wildcard_extra_bits(struct flow_wildcards
*mask
)
75 uint32_t *mask_u32
= (uint32_t *) &mask
->masks
;
78 for (i
= 0; i
< FLOW_U32S
; i
++) {
79 if (mask_u32
[i
] != 0) {
83 bit
= 1u << random_range(32);
84 } while (!(bit
& mask_u32
[i
]));
91 test_miniflow(struct flow
*flow
)
93 struct miniflow
*miniflow
, *miniflow2
, *miniflow3
;
94 struct flow flow2
, flow3
;
95 struct flow_wildcards mask
;
96 struct minimask
*minimask
;
99 const uint64_t *flow_u64
= (const uint64_t *) flow
;
101 /* Convert flow to miniflow. */
102 miniflow
= miniflow_create(flow
);
104 /* Obtain miniflow hash. */
105 uint32_t hash
= miniflow_hash_5tuple(miniflow
, 0);
108 /* Check that the flow equals its miniflow. */
109 for (i
= 0; i
< FLOW_MAX_VLAN_HEADERS
; i
++) {
110 ovs_assert(miniflow_get_vid(miniflow
, i
) ==
111 vlan_tci_to_vid(flow
->vlans
[i
].tci
));
113 for (i
= 0; i
< FLOW_U64S
; i
++) {
114 ovs_assert(miniflow_get(miniflow
, i
) == flow_u64
[i
]);
117 /* Check that the miniflow equals itself. */
118 ovs_assert(miniflow_equal(miniflow
, miniflow
));
120 /* Convert miniflow back to flow and verify that it's the same. */
121 miniflow_expand(miniflow
, &flow2
);
122 ovs_assert(flow_equal(flow
, &flow2
));
123 /* Check that copying a miniflow works properly. */
124 miniflow2
= miniflow_clone__(miniflow
);
125 ovs_assert(miniflow_equal(miniflow
, miniflow2
));
126 ovs_assert(miniflow_hash__(miniflow
, 0) == miniflow_hash__(miniflow2
, 0));
127 miniflow_expand(miniflow2
, &flow3
);
128 ovs_assert(flow_equal(flow
, &flow3
));
130 /* Check that masked matches work as expected for identical flows and
132 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
136 uint64_t *mask_u64
= (uint64_t *) &mask
.masks
;
138 ovs_assert(!flow_wildcards_is_catchall(&mask
));
139 minimask
= minimask_create(&mask
);
140 ovs_assert(!minimask_is_catchall(minimask
));
141 ovs_assert(miniflow_equal_in_minimask(miniflow
, miniflow2
, minimask
));
142 ovs_assert(miniflow_equal_flow_in_minimask(miniflow
, &flow2
, minimask
));
143 ovs_assert(miniflow_hash_in_minimask(miniflow
, minimask
, 0x12345678) ==
144 flow_hash_in_minimask(flow
, minimask
, 0x12345678));
145 ovs_assert(minimask_hash(minimask
, 0) ==
146 miniflow_hash__(&minimask
->masks
, 0));
148 /* Check that masked matches work as expected for differing flows and
150 toggle_masked_flow_bits(&flow2
, &mask
);
151 ovs_assert(!miniflow_equal_flow_in_minimask(miniflow
, &flow2
, minimask
));
152 miniflow3
= miniflow_create(&flow2
);
153 ovs_assert(!miniflow_equal_in_minimask(miniflow
, miniflow3
, minimask
));
162 test_minimask_has_extra(struct flow
*flow
)
164 struct flow_wildcards catchall
;
165 struct minimask
*minicatchall
;
167 flow_wildcards_init_catchall(&catchall
);
168 minicatchall
= minimask_create(&catchall
);
169 ovs_assert(minimask_is_catchall(minicatchall
));
171 struct flow_wildcards mask
;
172 struct minimask
*minimask
;
175 minimask
= minimask_create(&mask
);
176 ovs_assert(!minimask_has_extra(minimask
, minimask
));
177 ovs_assert(minimask_has_extra(minicatchall
, minimask
)
178 == !minimask_is_catchall(minimask
));
179 if (!minimask_is_catchall(minimask
)) {
180 struct minimask
*minimask2
;
182 wildcard_extra_bits(&mask
);
183 minimask2
= minimask_create(&mask
);
184 ovs_assert(minimask_has_extra(minimask2
, minimask
));
185 ovs_assert(!minimask_has_extra(minimask
, minimask2
));
194 test_minimask_combine(struct flow
*flow
)
196 struct flow_wildcards catchall
;
197 struct minimask
*minicatchall
;
199 flow_wildcards_init_catchall(&catchall
);
200 minicatchall
= minimask_create(&catchall
);
201 ovs_assert(minimask_is_catchall(minicatchall
));
203 struct minimask
*minimask
, *minimask2
;
204 struct flow_wildcards mask
, mask2
, combined
, combined2
;
206 struct minimask minicombined
;
207 uint64_t storage
[FLOW_U64S
];
211 memset(&flow2
, 0, sizeof flow2
);
213 minimask
= minimask_create(&mask
);
215 minimask_combine(&m
.minicombined
, minimask
, minicatchall
, m
.storage
);
216 ovs_assert(minimask_is_catchall(&m
.minicombined
));
218 /* Create mask based on zero flow */
220 minimask2
= minimask_create(&mask2
);
222 minimask_combine(&m
.minicombined
, minimask
, minimask2
, m
.storage
);
223 flow_wildcards_and(&combined
, &mask
, &mask2
);
224 minimask_expand(&m
.minicombined
, &combined2
);
225 ovs_assert(flow_wildcards_equal(&combined
, &combined2
));
234 LLVMFuzzerTestOneInput(const uint8_t *data
, size_t size
)
236 struct dp_packet packet
;
238 dp_packet_use_const(&packet
, data
, size
);
239 flow_extract(&packet
, &flow
);
241 /* Do miniflow tests. */
242 test_miniflow(&flow
);
243 test_minimask_has_extra(&flow
);
244 test_minimask_combine(&flow
);