Coverage Report

Created: 2025-10-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}