]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-util.c
netdev-offload-tc: Use single 'once' variable for probing tc features
[mirror_ovs.git] / lib / ofp-util.c
CommitLineData
fa37b408 1/*
04f48a68 2 * Copyright (c) 2008-2017 Nicira, Inc.
fa37b408
BP
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>
0d71302e 18#include "openvswitch/ofp-util.h"
03e1125c 19#include <ctype.h>
dc4762ed 20#include <errno.h>
fa37b408 21#include <inttypes.h>
6ca00f6f
ETN
22#include <sys/types.h>
23#include <netinet/in.h>
b459a924 24#include <netinet/icmp6.h>
fa37b408 25#include <stdlib.h>
25d436fb 26#include "bitmap.h"
daff3353 27#include "bundle.h"
10a24935 28#include "byte-order.h"
d8ae4d67 29#include "classifier.h"
75a75043 30#include "learn.h"
9e1fd49b 31#include "multipath.h"
6c038611 32#include "netdev.h"
b6c9e612 33#include "nx-match.h"
18ac06d3 34#include "id-pool.h"
d271907f
BW
35#include "openflow/netronome-ext.h"
36#include "openvswitch/dynamic-string.h"
50f96b10 37#include "openvswitch/json.h"
d271907f 38#include "openvswitch/meta-flow.h"
b598f214 39#include "openvswitch/ofp-actions.h"
d271907f
BW
40#include "openvswitch/ofp-errors.h"
41#include "openvswitch/ofp-msgs.h"
25d436fb 42#include "openvswitch/ofp-print.h"
66bd43fa 43#include "openvswitch/ofp-prop.h"
64c96779 44#include "openvswitch/ofpbuf.h"
d271907f
BW
45#include "openvswitch/type-props.h"
46#include "openvswitch/vlog.h"
d6e3feb5 47#include "openflow/intel-ext.h"
fa37b408
BP
48#include "packets.h"
49#include "random.h"
6159c531 50#include "tun-metadata.h"
4ffd1b43 51#include "unaligned.h"
ee89ea7b 52#include "util.h"
d5dc60f0 53#include "uuid.h"
fa37b408 54
d98e6007 55VLOG_DEFINE_THIS_MODULE(ofp_util);
fa37b408
BP
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. */
59static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5);
0d71302e
BP
60\f
61static bool
62ofputil_decode_hello_bitmap(const struct ofp_hello_elem_header *oheh,
63 uint32_t *allowed_versionsp)
d8ae4d67 64{
0d71302e
BP
65 uint16_t bitmap_len = ntohs(oheh->length) - sizeof *oheh;
66 const ovs_be32 *bitmap = ALIGNED_CAST(const ovs_be32 *, oheh + 1);
67 uint32_t allowed_versions;
5d9499c4 68
0d71302e
BP
69 if (!bitmap_len || bitmap_len % sizeof *bitmap) {
70 return false;
d8ae4d67 71 }
7257b535 72
0d71302e
BP
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 allowed_versions = ntohl(bitmap[0]);
d8ae4d67 79
0d71302e
BP
80 if (allowed_versions & 1) {
81 /* There's no OpenFlow version 0. */
82 VLOG_WARN_RL(&bad_ofmsg_rl, "peer claims to support invalid OpenFlow "
83 "version 0x00");
84 allowed_versions &= ~1u;
73f33563
BP
85 }
86
0d71302e
BP
87 if (!allowed_versions) {
88 VLOG_WARN_RL(&bad_ofmsg_rl, "peer does not support any OpenFlow "
89 "version (between 0x01 and 0x1f)");
90 return false;
e2170cff 91 }
d8ae4d67 92
0d71302e
BP
93 *allowed_versionsp = allowed_versions;
94 return true;
eb6f28db
BP
95}
96
0d71302e
BP
97static uint32_t
98version_bitmap_from_version(uint8_t ofp_version)
81a76618 99{
0d71302e 100 return ((ofp_version < 32 ? 1u << ofp_version : 0) - 1) << 1;
d8ae4d67
BP
101}
102
0d71302e
BP
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. */
110bool
111ofputil_decode_hello(const struct ofp_header *oh, uint32_t *allowed_versions)
d8ae4d67 112{
0d71302e
BP
113 struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length));
114 ofpbuf_pull(&msg, sizeof *oh);
d8ae4d67 115
0d71302e 116 *allowed_versions = version_bitmap_from_version(oh->version);
ff9d3826 117
0d71302e
BP
118 bool ok = true;
119 while (msg.size) {
120 const struct ofp_hello_elem_header *oheh;
121 unsigned int len;
66642cb4 122
0d71302e
BP
123 if (msg.size < sizeof *oheh) {
124 return false;
66642cb4 125 }
d8ae4d67 126
0d71302e
BP
127 oheh = msg.data;
128 len = ntohs(oheh->length);
129 if (len < sizeof *oheh || !ofpbuf_try_pull(&msg, ROUND_UP(len, 8))) {
130 return false;
36a16881 131 }
36a16881 132
0d71302e
BP
133 if (oheh->type != htons(OFPHET_VERSIONBITMAP)
134 || !ofputil_decode_hello_bitmap(oheh, allowed_versions)) {
135 ok = false;
36a16881 136 }
aa319503 137 }
0d71302e
BP
138
139 return ok;
aa319503
BP
140}
141
0d71302e
BP
142/* Returns true if 'allowed_versions' needs to be accompanied by a version
143 * bitmap to be correctly expressed in an OFPT_HELLO message. */
144static bool
145should_send_version_bitmap(uint32_t allowed_versions)
410698cf 146{
0d71302e 147 return !is_pow2((allowed_versions >> 1) + 1);
410698cf
BP
148}
149
0d71302e
BP
150/* Create an OFPT_HELLO message that expresses support for the OpenFlow
151 * versions in the 'allowed_versions' bitmaps and returns the message. */
152struct ofpbuf *
153ofputil_encode_hello(uint32_t allowed_versions)
410698cf 154{
0d71302e
BP
155 enum ofp_version ofp_version;
156 struct ofpbuf *msg;
410698cf 157
0d71302e
BP
158 ofp_version = leftmost_1bit_idx(allowed_versions);
159 msg = ofpraw_alloc(OFPRAW_OFPT_HELLO, ofp_version, 0);
410698cf 160
0d71302e
BP
161 if (should_send_version_bitmap(allowed_versions)) {
162 struct ofp_hello_elem_header *oheh;
163 uint16_t map_len;
410698cf 164
0d71302e
BP
165 map_len = sizeof allowed_versions;
166 oheh = ofpbuf_put_zeros(msg, ROUND_UP(map_len + sizeof *oheh, 8));
167 oheh->type = htons(OFPHET_VERSIONBITMAP);
168 oheh->length = htons(map_len + sizeof *oheh);
169 *ALIGNED_CAST(ovs_be32 *, oheh + 1) = htonl(allowed_versions);
097d4939 170
0d71302e 171 ofpmsg_update_length(msg);
097d4939 172 }
410698cf 173
0d71302e 174 return msg;
410698cf 175}
dfc77282
BP
176
177void
178ofputil_hello_format(struct ds *string, const struct ofp_header *oh)
179{
180 uint32_t allowed_versions;
181 bool ok;
182
183 ok = ofputil_decode_hello(oh, &allowed_versions);
184
185 ds_put_cstr(string, "\n version bitmap: ");
186 ofputil_format_version_bitmap(string, allowed_versions);
187
188 if (!ok) {
189 ds_put_cstr(string, "\n unknown data in hello:\n");
190 ds_put_hex_dump(string, oh, ntohs(oh->length), 0, true);
191 }
192}
0d71302e
BP
193\f
194/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
195struct ofpbuf *
d9cea8f5 196ofputil_encode_echo_request(enum ofp_version ofp_version)
75fa58f8 197{
0d71302e
BP
198 return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, ofp_version,
199 htonl(0), 0);
75fa58f8
BP
200}
201
0d71302e
BP
202/* Creates and returns an OFPT_ECHO_REPLY message matching the
203 * OFPT_ECHO_REQUEST message in 'rq'. */
204struct ofpbuf *
d9cea8f5 205ofputil_encode_echo_reply(const struct ofp_header *rq)
75fa58f8 206{
0d71302e
BP
207 struct ofpbuf rq_buf = ofpbuf_const_initializer(rq, ntohs(rq->length));
208 ofpraw_pull_assert(&rq_buf);
75fa58f8 209
0d71302e
BP
210 struct ofpbuf *reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY,
211 rq, rq_buf.size);
212 ofpbuf_put(reply, rq_buf.data, rq_buf.size);
213 return reply;
36956a7d
BP
214}
215
0d71302e
BP
216struct ofpbuf *
217ofputil_encode_barrier_request(enum ofp_version ofp_version)
36956a7d 218{
0d71302e 219 enum ofpraw type;
27527aa0 220
0d71302e 221 switch (ofp_version) {
0d71302e
BP
222 case OFP15_VERSION:
223 case OFP14_VERSION:
224 case OFP13_VERSION:
225 case OFP12_VERSION:
226 case OFP11_VERSION:
227 type = OFPRAW_OFPT11_BARRIER_REQUEST;
228 break;
27527aa0 229
0d71302e
BP
230 case OFP10_VERSION:
231 type = OFPRAW_OFPT10_BARRIER_REQUEST;
232 break;
4f13da56 233
0d71302e
BP
234 default:
235 OVS_NOT_REACHED();
9e1fd49b
BP
236 }
237
0d71302e 238 return ofpraw_alloc(type, ofp_version, 0);
6c6eedc5 239}