Coverage Report

Created: 2023-03-26 07:42

/src/openvswitch/lib/ofp-ed-props.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2017 Intel, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at:
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <config.h>
18
#include <sys/types.h>
19
#include <netinet/in.h>
20
#include <arpa/inet.h>
21
#include "openvswitch/ofp-ed-props.h"
22
#include "openvswitch/ofpbuf.h"
23
#include "openvswitch/ofp-parse.h"
24
#include "util.h"
25
#include "lib/packets.h"
26
27
28
enum ofperr
29
decode_ed_prop(const struct ofp_ed_prop_header **ofp_prop,
30
               struct ofpbuf *out OVS_UNUSED,
31
               size_t *remaining)
32
5.82k
{
33
5.82k
    uint16_t prop_class = ntohs((*ofp_prop)->prop_class);
34
5.82k
    uint8_t prop_type = (*ofp_prop)->type;
35
5.82k
    size_t len = (*ofp_prop)->len;
36
5.82k
    size_t pad_len = ROUND_UP(len, 8);
37
38
5.82k
    if (len < sizeof **ofp_prop || pad_len > *remaining) {
39
569
        return OFPERR_OFPBAC_BAD_LEN;
40
569
    }
41
42
5.25k
    switch (prop_class) {
43
4.80k
    case OFPPPC_NSH: {
44
4.80k
        switch (prop_type) {
45
2.84k
        case OFPPPT_PROP_NSH_MDTYPE: {
46
2.84k
            struct ofp_ed_prop_nsh_md_type *opnmt =
47
2.84k
                ALIGNED_CAST(struct ofp_ed_prop_nsh_md_type *, *ofp_prop);
48
2.84k
            if (len > sizeof(*opnmt) || len > *remaining) {
49
35
                return OFPERR_NXBAC_BAD_ED_PROP;
50
35
            }
51
2.80k
            struct ofpact_ed_prop_nsh_md_type *pnmt =
52
2.80k
                    ofpbuf_put_zeros(out, sizeof *pnmt);
53
2.80k
            pnmt->header.prop_class = prop_class;
54
2.80k
            pnmt->header.type = prop_type;
55
2.80k
            pnmt->header.len = len;
56
2.80k
            pnmt->md_type = opnmt->md_type;
57
2.80k
            break;
58
2.84k
        }
59
1.41k
        case OFPPPT_PROP_NSH_TLV: {
60
1.41k
            struct ofp_ed_prop_nsh_tlv *opnt =
61
1.41k
                ALIGNED_CAST(struct ofp_ed_prop_nsh_tlv *, *ofp_prop);
62
1.41k
            size_t tlv_pad_len = ROUND_UP(opnt->tlv_len, 8);
63
1.41k
            if (len != sizeof(*opnt) + tlv_pad_len || len > *remaining) {
64
193
                return OFPERR_NXBAC_BAD_ED_PROP;
65
193
            }
66
1.21k
            struct ofpact_ed_prop_nsh_tlv *pnt =
67
1.21k
                    ofpbuf_put_uninit(out, sizeof(*pnt));
68
1.21k
            pnt->header.prop_class = prop_class;
69
1.21k
            pnt->header.type = prop_type;
70
1.21k
            pnt->header.len = len;
71
1.21k
            pnt->tlv_class = opnt->tlv_class;
72
1.21k
            pnt->tlv_type = opnt->tlv_type;
73
1.21k
            pnt->tlv_len = opnt->tlv_len;
74
1.21k
            ofpbuf_put(out, opnt->data, tlv_pad_len);
75
1.21k
            break;
76
1.41k
        }
77
556
        default:
78
556
            return OFPERR_NXBAC_UNKNOWN_ED_PROP;
79
4.80k
        }
80
4.02k
        break;
81
4.80k
    }
82
4.02k
    default:
83
444
        return OFPERR_NXBAC_UNKNOWN_ED_PROP;
84
5.25k
    }
85
86
4.02k
    *remaining -= pad_len;
87
4.02k
    *ofp_prop = ALIGNED_CAST(const struct ofp_ed_prop_header *,
88
4.02k
                             ((char *)(*ofp_prop) + pad_len));
89
4.02k
    return 0;
90
5.25k
}
91
92
enum ofperr
93
encode_ed_prop(const struct ofpact_ed_prop **prop,
94
               struct ofpbuf *out OVS_UNUSED)
95
477
{
96
477
    size_t prop_len;
97
98
477
    switch ((*prop)->prop_class) {
99
477
    case OFPPPC_NSH: {
100
477
        switch ((*prop)->type) {
101
477
        case OFPPPT_PROP_NSH_MDTYPE: {
102
477
            struct ofpact_ed_prop_nsh_md_type *pnmt =
103
477
                ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, *prop);
104
477
            struct ofp_ed_prop_nsh_md_type *opnmt =
105
477
                    ofpbuf_put_uninit(out, sizeof(*opnmt));
106
477
            opnmt->header.prop_class = htons((*prop)->prop_class);
107
477
            opnmt->header.type = (*prop)->type;
108
477
            opnmt->header.len =
109
477
                    offsetof(struct ofp_ed_prop_nsh_md_type, pad);
110
477
            opnmt->md_type = pnmt->md_type;
111
477
            memset(opnmt->pad, 0, sizeof opnmt->pad);
112
477
            prop_len = sizeof(*pnmt);
113
477
            break;
114
0
        }
115
0
        case OFPPPT_PROP_NSH_TLV: {
116
0
            struct ofpact_ed_prop_nsh_tlv *pnt =
117
0
                ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, *prop);
118
0
            struct ofp_ed_prop_nsh_tlv *opnt;
119
0
            size_t tlv_pad_len = ROUND_UP(pnt->tlv_len, 8);
120
0
            size_t len = sizeof(*opnt) + tlv_pad_len;
121
0
            opnt = ofpbuf_put_uninit(out, len);
122
0
            opnt->header.prop_class = htons((*prop)->prop_class);
123
0
            opnt->header.type = (*prop)->type;
124
0
            opnt->header.len = len;
125
0
            opnt->tlv_class = pnt->tlv_class;
126
0
            opnt->tlv_type = pnt->tlv_type;
127
0
            opnt->tlv_len = pnt->tlv_len;
128
0
            memcpy(opnt->data, pnt->data, tlv_pad_len);
129
0
            prop_len = sizeof(*pnt) + tlv_pad_len;
130
0
            break;
131
0
        }
132
0
        default:
133
0
            return OFPERR_OFPBAC_BAD_ARGUMENT;
134
477
        }
135
477
        break;
136
477
    }
137
477
    default:
138
0
        return OFPERR_OFPBAC_BAD_ARGUMENT;
139
477
    }
140
141
477
    *prop = ALIGNED_CAST(const struct ofpact_ed_prop *,
142
477
                         ((char *)(*prop) + prop_len));
143
477
    return 0;
144
477
}
145
146
bool
147
parse_ed_prop_class(const char *str OVS_UNUSED,
148
                    uint16_t *prop_class)
149
2.70k
{
150
2.70k
    if (!strcmp(str,"basic")) {
151
0
        *prop_class = OFPPPC_BASIC;
152
2.70k
    } else if (!strcmp(str,"ethernet")) {
153
675
        *prop_class = OFPPPC_BASIC;
154
2.02k
    } else if (!strcmp(str,"mpls")) {
155
1.22k
        *prop_class = OFPPPC_MPLS;
156
1.22k
    } else if (!strcmp(str,"mpls_mc")) {
157
292
        *prop_class = OFPPPC_MPLS;
158
507
    } else if (!strcmp(str,"gre")) {
159
0
        *prop_class = OFPPPC_GRE;
160
507
    } else if (!strcmp(str,"gtp")) {
161
0
        *prop_class = OFPPPC_GTP;
162
507
    } else if (!strcmp(str,"nsh")) {
163
507
        *prop_class = OFPPPC_NSH;
164
507
    } else {
165
0
        return false;
166
0
    }
167
2.70k
    return true;
168
2.70k
}
169
170
bool
171
parse_ed_prop_type(uint16_t prop_class,
172
                   const char *str OVS_UNUSED,
173
                   uint8_t *type OVS_UNUSED)
174
765
{
175
765
    switch (prop_class) {
176
762
    case OFPPPC_NSH:
177
762
        if (!strcmp(str, "md_type")) {
178
684
            *type = OFPPPT_PROP_NSH_MDTYPE;
179
684
            return true;
180
684
        } else if (!strcmp(str, "tlv")) {
181
4
            *type = OFPPPT_PROP_NSH_TLV;
182
4
            return true;
183
74
        } else {
184
74
            return false;
185
74
        }
186
3
    default:
187
3
        return false;
188
765
    }
189
765
}
190
191
/* Parse the value of an encap/decap property based on property class
192
 * and type and append the parsed property in internal format to the
193
 * ofpbuf out.
194
 * Returns a malloced string in the event of a parse error. The caller
195
 * must free the string.
196
 */
197
198
char *
199
parse_ed_prop_value(uint16_t prop_class, uint8_t prop_type OVS_UNUSED,
200
                    const char *value, struct ofpbuf *out OVS_UNUSED)
201
688
{
202
688
    char *error = NULL;
203
204
688
    if (value == NULL || *value == '\0') {
205
6
        return xstrdup("Value missing for encap property");
206
6
    }
207
208
682
    switch (prop_class) {
209
682
    case OFPPPC_NSH:
210
682
        switch (prop_type) {
211
681
        case OFPPPT_PROP_NSH_MDTYPE: {
212
            /* Format: "<md_type>:uint8_t". */
213
681
            uint8_t md_type;
214
681
            error = str_to_u8(value, "md_type", &md_type);
215
681
            if (error != NULL) {
216
1
                return error;
217
1
            }
218
680
            if (md_type < 1 || md_type > 2) {
219
3
                return xstrdup("invalid md_type");
220
3
            }
221
677
            struct ofpact_ed_prop_nsh_md_type *pnmt =
222
677
                    ofpbuf_put_uninit(out, sizeof(*pnmt));
223
677
            pnmt->header.prop_class = prop_class;
224
677
            pnmt->header.type = prop_type;
225
677
            pnmt->header.len =
226
677
                    offsetof(struct ofp_ed_prop_nsh_md_type, pad);
227
677
            pnmt->md_type = md_type;
228
677
            break;
229
680
        }
230
1
        case OFPPPT_PROP_NSH_TLV: {
231
            /* Format: "<class>:ovs_be16,<type>:uint8_t,<val>:hex_string" */
232
1
            struct ofpact_ed_prop_nsh_tlv *pnt;
233
1
            uint16_t tlv_class;
234
1
            uint8_t tlv_type;
235
1
            char buf[256];
236
1
            size_t tlv_value_len, padding;
237
1
            size_t start_ofs = out->size;
238
239
1
            if (!ovs_scan(value, "0x%"SCNx16",%"SCNu8",0x%251[0-9a-fA-F]",
240
1
                          &tlv_class, &tlv_type, buf)) {
241
1
                return xasprintf("Invalid NSH TLV header: %s", value);
242
1
            }
243
0
            ofpbuf_put_uninit(out, sizeof(*pnt));
244
0
            ofpbuf_put_hex(out, buf, &tlv_value_len);
245
0
            pnt = ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *,
246
0
                               ((char *)out->data + start_ofs));
247
0
            padding = ROUND_UP(tlv_value_len, 8) - tlv_value_len;
248
0
            pnt->header.prop_class = prop_class;
249
0
            pnt->header.type = prop_type;
250
0
            pnt->header.len = sizeof(*pnt) + tlv_value_len + padding;
251
0
            pnt->tlv_class = htons(tlv_class);
252
0
            pnt->tlv_type = tlv_type;
253
0
            pnt->tlv_len = tlv_value_len;
254
0
            if (padding > 0) {
255
0
                ofpbuf_put_zeros(out, padding);
256
0
            }
257
0
            break;
258
1
        }
259
0
        default:
260
            /* Unsupported property types rejected before. */
261
0
            OVS_NOT_REACHED();
262
682
        }
263
677
        break;
264
677
    default:
265
        /* Unsupported property classes rejected before. */
266
0
        OVS_NOT_REACHED();
267
682
    }
268
269
677
    return NULL;
270
682
}
271
272
char *
273
format_ed_prop_class(const struct ofpact_ed_prop *prop)
274
0
{
275
0
    switch (prop->prop_class) {
276
0
    case OFPPPC_BASIC:
277
0
        return "basic";
278
0
    case OFPPPC_MPLS:
279
0
        return "mpls";
280
0
    case OFPPPC_GRE:
281
0
        return "gre";
282
0
    case OFPPPC_GTP:
283
0
        return "gtp";
284
0
    case OFPPPC_NSH:
285
0
        return "nsh";
286
0
    default:
287
0
        OVS_NOT_REACHED();
288
0
    }
289
0
}
290
291
char *
292
format_ed_prop_type(const struct ofpact_ed_prop *prop)
293
1.07k
{
294
1.07k
    switch (prop->prop_class) {
295
1.07k
    case OFPPPC_NSH:
296
1.07k
        switch (prop->type) {
297
800
        case OFPPPT_PROP_NSH_MDTYPE:
298
800
            return "md_type";
299
272
        case OFPPPT_PROP_NSH_TLV:
300
272
            return "tlv";
301
0
        default:
302
0
            OVS_NOT_REACHED();
303
1.07k
        }
304
0
        break;
305
0
    default:
306
0
        OVS_NOT_REACHED();
307
1.07k
    }
308
1.07k
}
309
310
void
311
format_ed_prop(struct ds *s OVS_UNUSED,
312
                     const struct ofpact_ed_prop *prop)
313
1.07k
{
314
1.07k
    switch (prop->prop_class) {
315
1.07k
    case OFPPPC_NSH:
316
1.07k
        switch (prop->type) {
317
800
        case OFPPPT_PROP_NSH_MDTYPE: {
318
800
            struct ofpact_ed_prop_nsh_md_type *pnmt =
319
800
                ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, prop);
320
800
            ds_put_format(s, "%s=%d", format_ed_prop_type(prop),
321
800
                          pnmt->md_type);
322
800
            return;
323
0
        }
324
272
        case OFPPPT_PROP_NSH_TLV: {
325
272
            struct ofpact_ed_prop_nsh_tlv *pnt =
326
272
                ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, prop);
327
272
            ds_put_format(s, "%s(0x%04x,%d,",
328
272
                          format_ed_prop_type(prop),
329
272
                          ntohs(pnt->tlv_class), pnt->tlv_type);
330
272
            ds_put_hex(s, pnt->data, pnt->tlv_len);
331
272
            ds_put_cstr(s,")");
332
272
            return;
333
0
        }
334
0
        default:
335
0
            OVS_NOT_REACHED();
336
1.07k
        }
337
0
    default:
338
0
        OVS_NOT_REACHED();
339
1.07k
    }
340
1.07k
}