]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ofp-util.c
netdev-offload-tc: Use single 'once' variable for probing tc features
[mirror_ovs.git] / lib / ofp-util.c
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 \f
61 static bool
62 ofputil_decode_hello_bitmap(const struct ofp_hello_elem_header *oheh,
63 uint32_t *allowed_versionsp)
64 {
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;
68
69 if (!bitmap_len || bitmap_len % sizeof *bitmap) {
70 return false;
71 }
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 allowed_versions = ntohl(bitmap[0]);
79
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;
85 }
86
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;
91 }
92
93 *allowed_versionsp = allowed_versions;
94 return true;
95 }
96
97 static uint32_t
98 version_bitmap_from_version(uint8_t ofp_version)
99 {
100 return ((ofp_version < 32 ? 1u << ofp_version : 0) - 1) << 1;
101 }
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 {
113 struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length));
114 ofpbuf_pull(&msg, sizeof *oh);
115
116 *allowed_versions = version_bitmap_from_version(oh->version);
117
118 bool ok = true;
119 while (msg.size) {
120 const struct ofp_hello_elem_header *oheh;
121 unsigned int len;
122
123 if (msg.size < sizeof *oheh) {
124 return false;
125 }
126
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;
131 }
132
133 if (oheh->type != htons(OFPHET_VERSIONBITMAP)
134 || !ofputil_decode_hello_bitmap(oheh, allowed_versions)) {
135 ok = false;
136 }
137 }
138
139 return ok;
140 }
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 {
147 return !is_pow2((allowed_versions >> 1) + 1);
148 }
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 {
155 enum ofp_version ofp_version;
156 struct ofpbuf *msg;
157
158 ofp_version = leftmost_1bit_idx(allowed_versions);
159 msg = ofpraw_alloc(OFPRAW_OFPT_HELLO, ofp_version, 0);
160
161 if (should_send_version_bitmap(allowed_versions)) {
162 struct ofp_hello_elem_header *oheh;
163 uint16_t map_len;
164
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);
170
171 ofpmsg_update_length(msg);
172 }
173
174 return msg;
175 }
176
177 void
178 ofputil_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 }
193 \f
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 {
198 return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, ofp_version,
199 htonl(0), 0);
200 }
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 {
207 struct ofpbuf rq_buf = ofpbuf_const_initializer(rq, ntohs(rq->length));
208 ofpraw_pull_assert(&rq_buf);
209
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;
214 }
215
216 struct ofpbuf *
217 ofputil_encode_barrier_request(enum ofp_version ofp_version)
218 {
219 enum ofpraw type;
220
221 switch (ofp_version) {
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;
229
230 case OFP10_VERSION:
231 type = OFPRAW_OFPT10_BARRIER_REQUEST;
232 break;
233
234 default:
235 OVS_NOT_REACHED();
236 }
237
238 return ofpraw_alloc(type, ofp_version, 0);
239 }