Coverage Report

Created: 2025-07-11 06:11

/src/openvswitch/lib/ofp-util.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2008-2017 Nicira, 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 "openvswitch/ofp-util.h"
19
#include <ctype.h>
20
#include <errno.h>
21
#include <inttypes.h>
22
#include <sys/types.h>
23
#include <netinet/in.h>
24
#include <netinet/icmp6.h>
25
#include <stdlib.h>
26
#include "bitmap.h"
27
#include "bundle.h"
28
#include "byte-order.h"
29
#include "classifier.h"
30
#include "learn.h"
31
#include "multipath.h"
32
#include "netdev.h"
33
#include "nx-match.h"
34
#include "id-pool.h"
35
#include "openflow/netronome-ext.h"
36
#include "openvswitch/dynamic-string.h"
37
#include "openvswitch/json.h"
38
#include "openvswitch/meta-flow.h"
39
#include "openvswitch/ofp-actions.h"
40
#include "openvswitch/ofp-errors.h"
41
#include "openvswitch/ofp-msgs.h"
42
#include "openvswitch/ofp-print.h"
43
#include "openvswitch/ofp-prop.h"
44
#include "openvswitch/ofpbuf.h"
45
#include "openvswitch/type-props.h"
46
#include "openvswitch/vlog.h"
47
#include "openflow/intel-ext.h"
48
#include "packets.h"
49
#include "random.h"
50
#include "tun-metadata.h"
51
#include "unaligned.h"
52
#include "util.h"
53
#include "uuid.h"
54
55
VLOG_DEFINE_THIS_MODULE(ofp_util);
56
57
/* Rate limit for OpenFlow message parse errors.  These always indicate a bug
58
 * in the peer and so there's not much point in showing a lot of them. */
59
static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5);
60

61
static bool
62
ofputil_decode_hello_bitmap(const struct ofp_hello_elem_header *oheh,
63
                            uint32_t *allowed_versionsp)
64
0
{
65
0
    uint16_t bitmap_len = ntohs(oheh->length) - sizeof *oheh;
66
0
    const ovs_be32 *bitmap = ALIGNED_CAST(const ovs_be32 *, oheh + 1);
67
0
    uint32_t allowed_versions;
68
69
0
    if (!bitmap_len || bitmap_len % sizeof *bitmap) {
70
0
        return false;
71
0
    }
72
73
    /* Only use the first 32-bit element of the bitmap as that is all the
74
     * current implementation supports.  Subsequent elements are ignored which
75
     * should have no effect on session negotiation until Open vSwitch supports
76
     * wire-protocol versions greater than 31.
77
     */
78
0
    allowed_versions = ntohl(bitmap[0]);
79
80
0
    if (allowed_versions & 1) {
81
        /* There's no OpenFlow version 0. */
82
0
        VLOG_WARN_RL(&bad_ofmsg_rl, "peer claims to support invalid OpenFlow "
83
0
                     "version 0x00");
84
0
        allowed_versions &= ~1u;
85
0
    }
86
87
0
    if (!allowed_versions) {
88
0
        VLOG_WARN_RL(&bad_ofmsg_rl, "peer does not support any OpenFlow "
89
0
                     "version (between 0x01 and 0x1f)");
90
0
        return false;
91
0
    }
92
93
0
    *allowed_versionsp = allowed_versions;
94
0
    return true;
95
0
}
96
97
static uint32_t
98
version_bitmap_from_version(uint8_t ofp_version)
99
0
{
100
0
    return ((ofp_version < 32 ? 1u << ofp_version : 0) - 1) << 1;
101
0
}
102
103
/* Decodes OpenFlow OFPT_HELLO message 'oh', storing into '*allowed_versions'
104
 * the set of OpenFlow versions for which 'oh' announces support.
105
 *
106
 * Because of how OpenFlow defines OFPT_HELLO messages, this function is always
107
 * successful, and thus '*allowed_versions' is always initialized.  However, it
108
 * returns false if 'oh' contains some data that could not be fully understood,
109
 * true if 'oh' was completely parsed. */
110
bool
111
ofputil_decode_hello(const struct ofp_header *oh, uint32_t *allowed_versions)
112
0
{
113
0
    struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length));
114
0
    ofpbuf_pull(&msg, sizeof *oh);
115
116
0
    *allowed_versions = version_bitmap_from_version(oh->version);
117
118
0
    bool ok = true;
119
0
    while (msg.size) {
120
0
        const struct ofp_hello_elem_header *oheh;
121
0
        unsigned int len;
122
123
0
        if (msg.size < sizeof *oheh) {
124
0
            return false;
125
0
        }
126
127
0
        oheh = msg.data;
128
0
        len = ntohs(oheh->length);
129
0
        if (len < sizeof *oheh || !ofpbuf_try_pull(&msg, ROUND_UP(len, 8))) {
130
0
            return false;
131
0
        }
132
133
0
        if (oheh->type != htons(OFPHET_VERSIONBITMAP)
134
0
            || !ofputil_decode_hello_bitmap(oheh, allowed_versions)) {
135
0
            ok = false;
136
0
        }
137
0
    }
138
139
0
    return ok;
140
0
}
141
142
/* Returns true if 'allowed_versions' needs to be accompanied by a version
143
 * bitmap to be correctly expressed in an OFPT_HELLO message. */
144
static bool
145
should_send_version_bitmap(uint32_t allowed_versions)
146
0
{
147
0
    return !is_pow2((allowed_versions >> 1) + 1);
148
0
}
149
150
/* Create an OFPT_HELLO message that expresses support for the OpenFlow
151
 * versions in the 'allowed_versions' bitmaps and returns the message. */
152
struct ofpbuf *
153
ofputil_encode_hello(uint32_t allowed_versions)
154
0
{
155
0
    enum ofp_version ofp_version;
156
0
    struct ofpbuf *msg;
157
158
0
    ofp_version = leftmost_1bit_idx(allowed_versions);
159
0
    msg = ofpraw_alloc(OFPRAW_OFPT_HELLO, ofp_version, 0);
160
161
0
    if (should_send_version_bitmap(allowed_versions)) {
162
0
        struct ofp_hello_elem_header *oheh;
163
0
        uint16_t map_len;
164
165
0
        map_len = sizeof allowed_versions;
166
0
        oheh = ofpbuf_put_zeros(msg, ROUND_UP(map_len + sizeof *oheh, 8));
167
0
        oheh->type = htons(OFPHET_VERSIONBITMAP);
168
0
        oheh->length = htons(map_len + sizeof *oheh);
169
0
        *ALIGNED_CAST(ovs_be32 *, oheh + 1) = htonl(allowed_versions);
170
171
0
        ofpmsg_update_length(msg);
172
0
    }
173
174
0
    return msg;
175
0
}
176
177
void
178
ofputil_hello_format(struct ds *string, const struct ofp_header *oh)
179
0
{
180
0
    uint32_t allowed_versions;
181
0
    bool ok;
182
183
0
    ok = ofputil_decode_hello(oh, &allowed_versions);
184
185
0
    ds_put_cstr(string, "\n version bitmap: ");
186
0
    ofputil_format_version_bitmap(string, allowed_versions);
187
188
0
    if (!ok) {
189
0
        ds_put_cstr(string, "\n unknown data in hello:\n");
190
0
        ds_put_hex_dump(string, oh, ntohs(oh->length), 0, true);
191
0
    }
192
0
}
193

194
/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
195
struct ofpbuf *
196
ofputil_encode_echo_request(enum ofp_version ofp_version)
197
0
{
198
0
    return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, ofp_version,
199
0
                            htonl(0), 0);
200
0
}
201
202
/* Creates and returns an OFPT_ECHO_REPLY message matching the
203
 * OFPT_ECHO_REQUEST message in 'rq'. */
204
struct ofpbuf *
205
ofputil_encode_echo_reply(const struct ofp_header *rq)
206
0
{
207
0
    struct ofpbuf rq_buf = ofpbuf_const_initializer(rq, ntohs(rq->length));
208
0
    ofpraw_pull_assert(&rq_buf);
209
210
0
    struct ofpbuf *reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY,
211
0
                                              rq, rq_buf.size);
212
0
    ofpbuf_put(reply, rq_buf.data, rq_buf.size);
213
0
    return reply;
214
0
}
215
216
struct ofpbuf *
217
ofputil_encode_barrier_request(enum ofp_version ofp_version)
218
0
{
219
0
    enum ofpraw type;
220
221
0
    switch (ofp_version) {
222
0
    case OFP15_VERSION:
223
0
    case OFP14_VERSION:
224
0
    case OFP13_VERSION:
225
0
    case OFP12_VERSION:
226
0
    case OFP11_VERSION:
227
0
        type = OFPRAW_OFPT11_BARRIER_REQUEST;
228
0
        break;
229
230
0
    case OFP10_VERSION:
231
0
        type = OFPRAW_OFPT10_BARRIER_REQUEST;
232
0
        break;
233
234
0
    default:
235
0
        OVS_NOT_REACHED();
236
0
    }
237
238
0
    return ofpraw_alloc(type, ofp_version, 0);
239
0
}