/src/openvswitch/tests/oss-fuzz/odp_target.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <config.h> |
2 | | #include "fuzzer.h" |
3 | | #undef NDEBUG |
4 | | #include "odp-util.h" |
5 | | #include <stdio.h> |
6 | | #include "openvswitch/dynamic-string.h" |
7 | | #include "flow.h" |
8 | | #include "openvswitch/match.h" |
9 | | #include "openvswitch/ofpbuf.h" |
10 | | #include "util.h" |
11 | | #include "openvswitch/ofp-flow.h" |
12 | | #include "openvswitch/vlog.h" |
13 | | |
14 | | static int |
15 | | parse_keys(bool wc_keys, const char *in) |
16 | 34.3k | { |
17 | 34.3k | int exit_code = 0; |
18 | | |
19 | 34.3k | enum odp_key_fitness fitness; |
20 | 34.3k | struct ofpbuf odp_key; |
21 | 34.3k | struct ofpbuf odp_mask; |
22 | 34.3k | struct flow flow; |
23 | 34.3k | struct ds out; |
24 | 34.3k | int error; |
25 | | |
26 | | /* Convert string to OVS DP key. */ |
27 | 34.3k | ofpbuf_init(&odp_key, 0); |
28 | 34.3k | ofpbuf_init(&odp_mask, 0); |
29 | 34.3k | error = odp_flow_from_string(in, NULL, |
30 | 34.3k | &odp_key, &odp_mask, NULL); |
31 | 34.3k | if (error) { |
32 | 25.0k | printf("odp_flow_from_string: error\n"); |
33 | 25.0k | goto next; |
34 | 25.0k | } |
35 | | |
36 | 9.35k | if (!wc_keys) { |
37 | 4.67k | struct odp_flow_key_parms odp_parms = { |
38 | 4.67k | .flow = &flow, |
39 | 4.67k | .support = { |
40 | 4.67k | .recirc = true, |
41 | 4.67k | .ct_state = true, |
42 | 4.67k | .ct_zone = true, |
43 | 4.67k | .ct_mark = true, |
44 | 4.67k | .ct_label = true, |
45 | 4.67k | .max_vlan_headers = SIZE_MAX, |
46 | 4.67k | }, |
47 | 4.67k | }; |
48 | | |
49 | | /* Convert odp_key to flow. */ |
50 | 4.67k | fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, |
51 | 4.67k | &flow, NULL); |
52 | 4.67k | switch (fitness) { |
53 | 2.24k | case ODP_FIT_PERFECT: |
54 | 2.24k | break; |
55 | | |
56 | 116 | case ODP_FIT_TOO_LITTLE: |
57 | 116 | printf("ODP_FIT_TOO_LITTLE: "); |
58 | 116 | break; |
59 | | |
60 | 419 | case ODP_FIT_TOO_MUCH: |
61 | 419 | printf("ODP_FIT_TOO_MUCH: "); |
62 | 419 | break; |
63 | | |
64 | 1.90k | case ODP_FIT_ERROR: |
65 | 1.90k | printf("odp_flow_key_to_flow: error\n"); |
66 | 1.90k | goto next; |
67 | 4.67k | } |
68 | | /* Convert cls_rule back to odp_key. */ |
69 | 2.77k | ofpbuf_uninit(&odp_key); |
70 | 2.77k | ofpbuf_init(&odp_key, 0); |
71 | 2.77k | odp_flow_key_from_flow(&odp_parms, &odp_key); |
72 | | |
73 | 2.77k | if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) { |
74 | 0 | printf ("too long: %"PRIu32" > %d\n", |
75 | 0 | odp_key.size, ODPUTIL_FLOW_KEY_BYTES); |
76 | 0 | exit_code = 1; |
77 | 0 | } |
78 | 2.77k | } |
79 | | |
80 | | /* Convert odp_key to string. */ |
81 | 7.45k | ds_init(&out); |
82 | 7.45k | if (wc_keys) { |
83 | 4.67k | odp_flow_format(odp_key.data, odp_key.size, |
84 | 4.67k | odp_mask.data, odp_mask.size, NULL, &out, false); |
85 | 4.67k | } else { |
86 | 2.77k | odp_flow_key_format(odp_key.data, odp_key.size, &out); |
87 | 2.77k | } |
88 | 7.45k | puts(ds_cstr(&out)); |
89 | 7.45k | ds_destroy(&out); |
90 | | |
91 | 34.3k | next: |
92 | 34.3k | ofpbuf_uninit(&odp_key); |
93 | 34.3k | ofpbuf_uninit(&odp_mask); |
94 | | |
95 | 34.3k | return exit_code; |
96 | 7.45k | } |
97 | | |
98 | | static int |
99 | | parse_actions(const char *in) |
100 | 17.1k | { |
101 | 17.1k | struct ofpbuf odp_actions; |
102 | 17.1k | struct ds out; |
103 | 17.1k | int error; |
104 | | |
105 | | /* Convert string to OVS DP actions. */ |
106 | 17.1k | ofpbuf_init(&odp_actions, 0); |
107 | 17.1k | error = odp_actions_from_string(in, NULL, &odp_actions); |
108 | 17.1k | if (error) { |
109 | 14.0k | printf("odp_actions_from_string: error\n"); |
110 | 14.0k | goto next; |
111 | 14.0k | } |
112 | | |
113 | | /* Convert odp_actions back to string. */ |
114 | 3.16k | ds_init(&out); |
115 | 3.16k | format_odp_actions(&out, odp_actions.data, odp_actions.size, NULL); |
116 | 3.16k | puts(ds_cstr(&out)); |
117 | 3.16k | ds_destroy(&out); |
118 | | |
119 | 17.1k | next: |
120 | 17.1k | ofpbuf_uninit(&odp_actions); |
121 | 17.1k | return 0; |
122 | 3.16k | } |
123 | | |
124 | | int |
125 | | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
126 | 17.2k | { |
127 | | /* Bail out if we cannot construct at least a 1 char string. */ |
128 | 17.2k | const char *input = (const char *) data; |
129 | 17.2k | if (size < 2 || input[size - 1] != '\0' || strchr(input, '\n') || |
130 | 17.2k | strlen(input) != size - 1) { |
131 | 31 | return 0; |
132 | 31 | } |
133 | | |
134 | | /* Disable logging to avoid write to disk. */ |
135 | 17.1k | static bool isInit = false; |
136 | 17.1k | if (!isInit) { |
137 | 1 | vlog_set_verbosity("off"); |
138 | 1 | isInit = true; |
139 | 1 | } |
140 | | |
141 | | /* Parse keys and wc keys. */ |
142 | 17.1k | parse_keys(false, input); |
143 | 17.1k | parse_keys(true, input); |
144 | | |
145 | | /* Parse actions. */ |
146 | 17.1k | parse_actions(input); |
147 | | |
148 | 17.1k | return 0; |
149 | 17.2k | } |