Coverage Report

Created: 2025-07-11 06:12

/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
7.38k
{
33
7.38k
    uint16_t prop_class = ntohs((*ofp_prop)->prop_class);
34
7.38k
    uint8_t prop_type = (*ofp_prop)->type;
35
7.38k
    size_t len = (*ofp_prop)->len;
36
7.38k
    size_t pad_len = ROUND_UP(len, 8);
37
38
7.38k
    if (len < sizeof **ofp_prop || pad_len > *remaining) {
39
1.16k
        return OFPERR_OFPBAC_BAD_LEN;
40
1.16k
    }
41
42
6.21k
    switch (prop_class) {
43
5.50k
    case OFPPPC_NSH: {
44
5.50k
        switch (prop_type) {
45
1.13k
        case OFPPPT_PROP_NSH_MDTYPE: {
46
1.13k
            struct ofp_ed_prop_nsh_md_type *opnmt =
47
1.13k
                ALIGNED_CAST(struct ofp_ed_prop_nsh_md_type *, *ofp_prop);
48
1.13k
            if (len > sizeof(*opnmt) || len > *remaining) {
49
6
                return OFPERR_NXBAC_BAD_ED_PROP;
50
6
            }
51
1.12k
            struct ofpact_ed_prop_nsh_md_type *pnmt =
52
1.12k
                    ofpbuf_put_zeros(out, sizeof *pnmt);
53
1.12k
            pnmt->header.prop_class = prop_class;
54
1.12k
            pnmt->header.type = prop_type;
55
1.12k
            pnmt->header.len = len;
56
1.12k
            pnmt->md_type = opnmt->md_type;
57
1.12k
            break;
58
1.13k
        }
59
4.35k
        case OFPPPT_PROP_NSH_TLV: {
60
4.35k
            struct ofp_ed_prop_nsh_tlv *opnt =
61
4.35k
                ALIGNED_CAST(struct ofp_ed_prop_nsh_tlv *, *ofp_prop);
62
4.35k
            size_t tlv_pad_len = ROUND_UP(opnt->tlv_len, 8);
63
4.35k
            if (len != sizeof(*opnt) + tlv_pad_len || len > *remaining) {
64
454
                return OFPERR_NXBAC_BAD_ED_PROP;
65
454
            }
66
3.89k
            struct ofpact_ed_prop_nsh_tlv *pnt =
67
3.89k
                    ofpbuf_put_uninit(out, sizeof(*pnt));
68
3.89k
            pnt->header.prop_class = prop_class;
69
3.89k
            pnt->header.type = prop_type;
70
3.89k
            pnt->header.len = len;
71
3.89k
            pnt->tlv_class = opnt->tlv_class;
72
3.89k
            pnt->tlv_type = opnt->tlv_type;
73
3.89k
            pnt->tlv_len = opnt->tlv_len;
74
3.89k
            ofpbuf_put(out, opnt->data, tlv_pad_len);
75
3.89k
            break;
76
4.35k
        }
77
24
        default:
78
24
            return OFPERR_NXBAC_UNKNOWN_ED_PROP;
79
5.50k
        }
80
5.02k
        break;
81
5.50k
    }
82
5.02k
    default:
83
713
        return OFPERR_NXBAC_UNKNOWN_ED_PROP;
84
6.21k
    }
85
86
5.02k
    *remaining -= pad_len;
87
5.02k
    *ofp_prop = ALIGNED_CAST(const struct ofp_ed_prop_header *,
88
5.02k
                             ((char *)(*ofp_prop) + pad_len));
89
5.02k
    return 0;
90
6.21k
}
91
92
enum ofperr
93
encode_ed_prop(const struct ofpact_ed_prop **prop,
94
               struct ofpbuf *out OVS_UNUSED)
95
0
{
96
0
    size_t prop_len;
97
98
0
    switch ((*prop)->prop_class) {
99
0
    case OFPPPC_NSH: {
100
0
        switch ((*prop)->type) {
101
0
        case OFPPPT_PROP_NSH_MDTYPE: {
102
0
            struct ofpact_ed_prop_nsh_md_type *pnmt =
103
0
                ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, *prop);
104
0
            struct ofp_ed_prop_nsh_md_type *opnmt =
105
0
                    ofpbuf_put_uninit(out, sizeof(*opnmt));
106
0
            opnmt->header.prop_class = htons((*prop)->prop_class);
107
0
            opnmt->header.type = (*prop)->type;
108
0
            opnmt->header.len =
109
0
                    offsetof(struct ofp_ed_prop_nsh_md_type, pad);
110
0
            opnmt->md_type = pnmt->md_type;
111
0
            memset(opnmt->pad, 0, sizeof opnmt->pad);
112
0
            prop_len = sizeof(*pnmt);
113
0
            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
0
        }
135
0
        break;
136
0
    }
137
0
    default:
138
0
        return OFPERR_OFPBAC_BAD_ARGUMENT;
139
0
    }
140
141
0
    *prop = ALIGNED_CAST(const struct ofpact_ed_prop *,
142
0
                         ((char *)(*prop) + prop_len));
143
0
    return 0;
144
0
}
145
146
bool
147
parse_ed_prop_class(const char *str OVS_UNUSED,
148
                    uint16_t *prop_class)
149
0
{
150
0
    if (!strcmp(str,"basic")) {
151
0
        *prop_class = OFPPPC_BASIC;
152
0
    } else if (!strcmp(str,"ethernet")) {
153
0
        *prop_class = OFPPPC_BASIC;
154
0
    } else if (!strcmp(str,"mpls")) {
155
0
        *prop_class = OFPPPC_MPLS;
156
0
    } else if (!strcmp(str,"mpls_mc")) {
157
0
        *prop_class = OFPPPC_MPLS;
158
0
    } else if (!strcmp(str,"gre")) {
159
0
        *prop_class = OFPPPC_GRE;
160
0
    } else if (!strcmp(str,"gtp")) {
161
0
        *prop_class = OFPPPC_GTP;
162
0
    } else if (!strcmp(str,"nsh")) {
163
0
        *prop_class = OFPPPC_NSH;
164
0
    } else {
165
0
        return false;
166
0
    }
167
0
    return true;
168
0
}
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
0
{
175
0
    switch (prop_class) {
176
0
    case OFPPPC_NSH:
177
0
        if (!strcmp(str, "md_type")) {
178
0
            *type = OFPPPT_PROP_NSH_MDTYPE;
179
0
            return true;
180
0
        } else if (!strcmp(str, "tlv")) {
181
0
            *type = OFPPPT_PROP_NSH_TLV;
182
0
            return true;
183
0
        } else {
184
0
            return false;
185
0
        }
186
0
    default:
187
0
        return false;
188
0
    }
189
0
}
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
0
{
202
0
    char *error = NULL;
203
204
0
    if (value == NULL || *value == '\0') {
205
0
        return xstrdup("Value missing for encap property");
206
0
    }
207
208
0
    switch (prop_class) {
209
0
    case OFPPPC_NSH:
210
0
        switch (prop_type) {
211
0
        case OFPPPT_PROP_NSH_MDTYPE: {
212
            /* Format: "<md_type>:uint8_t". */
213
0
            uint8_t md_type;
214
0
            error = str_to_u8(value, "md_type", &md_type);
215
0
            if (error != NULL) {
216
0
                return error;
217
0
            }
218
0
            if (md_type < 1 || md_type > 2) {
219
0
                return xstrdup("invalid md_type");
220
0
            }
221
0
            struct ofpact_ed_prop_nsh_md_type *pnmt =
222
0
                    ofpbuf_put_uninit(out, sizeof(*pnmt));
223
0
            pnmt->header.prop_class = prop_class;
224
0
            pnmt->header.type = prop_type;
225
0
            pnmt->header.len =
226
0
                    offsetof(struct ofp_ed_prop_nsh_md_type, pad);
227
0
            pnmt->md_type = md_type;
228
0
            break;
229
0
        }
230
0
        case OFPPPT_PROP_NSH_TLV: {
231
            /* Format: "<class>:ovs_be16,<type>:uint8_t,<val>:hex_string" */
232
0
            struct ofpact_ed_prop_nsh_tlv *pnt;
233
0
            uint16_t tlv_class;
234
0
            uint8_t tlv_type;
235
0
            char buf[256];
236
0
            size_t tlv_value_len, padding;
237
0
            size_t start_ofs = out->size;
238
239
0
            if (!ovs_scan(value, "0x%"SCNx16",%"SCNu8",0x%251[0-9a-fA-F]",
240
0
                          &tlv_class, &tlv_type, buf)) {
241
0
                return xasprintf("Invalid NSH TLV header: %s", value);
242
0
            }
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
0
        }
259
0
        default:
260
            /* Unsupported property types rejected before. */
261
0
            OVS_NOT_REACHED();
262
0
        }
263
0
        break;
264
0
    default:
265
        /* Unsupported property classes rejected before. */
266
0
        OVS_NOT_REACHED();
267
0
    }
268
269
0
    return NULL;
270
0
}
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
779
{
294
779
    switch (prop->prop_class) {
295
779
    case OFPPPC_NSH:
296
779
        switch (prop->type) {
297
29
        case OFPPPT_PROP_NSH_MDTYPE:
298
29
            return "md_type";
299
750
        case OFPPPT_PROP_NSH_TLV:
300
750
            return "tlv";
301
0
        default:
302
0
            OVS_NOT_REACHED();
303
779
        }
304
0
        break;
305
0
    default:
306
0
        OVS_NOT_REACHED();
307
779
    }
308
779
}
309
310
void
311
format_ed_prop(struct ds *s OVS_UNUSED,
312
                     const struct ofpact_ed_prop *prop)
313
779
{
314
779
    switch (prop->prop_class) {
315
779
    case OFPPPC_NSH:
316
779
        switch (prop->type) {
317
29
        case OFPPPT_PROP_NSH_MDTYPE: {
318
29
            struct ofpact_ed_prop_nsh_md_type *pnmt =
319
29
                ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, prop);
320
29
            ds_put_format(s, "%s=%d", format_ed_prop_type(prop),
321
29
                          pnmt->md_type);
322
29
            return;
323
0
        }
324
750
        case OFPPPT_PROP_NSH_TLV: {
325
750
            struct ofpact_ed_prop_nsh_tlv *pnt =
326
750
                ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, prop);
327
750
            ds_put_format(s, "%s(0x%04x,%d,",
328
750
                          format_ed_prop_type(prop),
329
750
                          ntohs(pnt->tlv_class), pnt->tlv_type);
330
750
            ds_put_hex(s, pnt->data, pnt->tlv_len);
331
750
            ds_put_cstr(s,")");
332
750
            return;
333
0
        }
334
0
        default:
335
0
            OVS_NOT_REACHED();
336
779
        }
337
0
    default:
338
0
        OVS_NOT_REACHED();
339
779
    }
340
779
}