Coverage Report

Created: 2026-01-31 06:26

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