2 * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "byte-order.h"
23 #include "openvswitch/ofp-errors.h"
24 #include "openvswitch/vlog.h"
28 struct ofp_prop_be16
{
34 BUILD_ASSERT_DECL(sizeof(struct ofp_prop_be16
) == 8);
36 struct ofp_prop_be32
{
41 BUILD_ASSERT_DECL(sizeof(struct ofp_prop_be32
) == 8);
44 ofpprop_type_to_exp_id(uint64_t type
)
50 ofpprop_type_to_exp_type(uint64_t type
)
52 return type
& UINT32_MAX
;
55 /* Pulls a property, beginning with struct ofp_prop_header, from the beginning
56 * of 'msg'. Stores the type of the property in '*typep' and, if 'property' is
57 * nonnull, the entire property, including the header, in '*property'. Points
58 * 'property->header' to the property header (which could be ofp_prop_header or
59 * ofp_prop_experimenter) and 'property->msg' to just past it. Returns 0 if
60 * successful, otherwise an OpenFlow error code.
62 * This function treats property types 'min_exp' and larger as introducing
63 * experimenter properties. For most kinds of properties, 0xffff is the
64 * appropriate value for 'min_exp', because 0xffff is the only property type
65 * used for experimenters, but async config properties also use 0xfffe. Use
66 * 0x10000 (or higher) if experimenter properties are not supported.
68 * This function pulls the property's stated size padded out to a multiple of
69 * 'alignment' bytes. The common case in OpenFlow is an 'alignment' of 8, so
70 * you can use ofpprop_pull() for that case. */
72 ofpprop_pull__(struct ofpbuf
*msg
, struct ofpbuf
*property
,
73 unsigned int alignment
, unsigned int min_exp
,
76 struct ofp_prop_header
*oph
;
77 unsigned int padded_len
;
80 if (msg
->size
< sizeof *oph
) {
81 return OFPERR_OFPBPC_BAD_LEN
;
85 len
= ntohs(oph
->len
);
86 padded_len
= ROUND_UP(len
, alignment
);
87 if (len
< sizeof *oph
|| padded_len
> msg
->size
) {
88 return OFPERR_OFPBPC_BAD_LEN
;
91 uint16_t type
= ntohs(oph
->type
);
95 struct ofp_prop_experimenter
*ope
= msg
->data
;
96 if (len
< sizeof *ope
) {
97 return OFPERR_OFPBPC_BAD_LEN
;
100 if (!ope
->experimenter
) {
101 /* Reject experimenter 0 because it yields ambiguity with standard
103 return OFPERR_OFPBPC_BAD_EXPERIMENTER
;
106 *typep
= OFPPROP_EXP(ntohl(ope
->experimenter
), ntohl(ope
->exp_type
));
110 ofpbuf_use_const(property
, msg
->data
, len
);
111 property
->header
= property
->data
;
112 property
->msg
= ((uint8_t *) property
->data
114 ? sizeof(struct ofp_prop_header
)
115 : sizeof(struct ofp_prop_experimenter
)));
117 ofpbuf_pull(msg
, padded_len
);
121 /* Pulls a property, beginning with struct ofp_prop_header, from the beginning
122 * of 'msg'. Stores the type of the property in '*typep' and, if 'property' is
123 * nonnull, the entire property, including the header, in '*property'. Points
124 * 'property->header' to the property header (which could be ofp_prop_header or
125 * ofp_prop_experimenter) and 'property->msg' to just past it. Returns 0 if
126 * successful, otherwise an error code.
128 * This function treats property type 0xffff as introducing an experimenter
129 * property. Use ofpprop_pull__() instead if some other behavior is needed.
131 * This function pulls the property's stated size padded out to a multiple of 8
132 * bytes, which is the common case for OpenFlow properties. Use
133 * ofpprop_pull__() instead if some other behavior is needed.*/
135 ofpprop_pull(struct ofpbuf
*msg
, struct ofpbuf
*property
, uint64_t *typep
)
137 return ofpprop_pull__(msg
, property
, 8, 0xffff, typep
);
140 /* Attempts to parse 'property' as a property containing a 16-bit value. If
141 * successful, stores the value into '*value' and returns 0; otherwise returns
142 * an OpenFlow error. */
144 ofpprop_parse_be16(const struct ofpbuf
*property
, ovs_be16
*value
)
146 /* OpenFlow uses 8-byte properties for 16-bit values, which doesn't really
147 * make sense. Be forgiving by allowing any size payload as long as it's
148 * at least big enough. */
149 ovs_be16
*p
= property
->msg
;
150 if (ofpbuf_msgsize(property
) < sizeof *p
) {
151 return OFPERR_OFPBPC_BAD_LEN
;
157 /* Attempts to parse 'property' as a property containing a 32-bit value. If
158 * successful, stores the value into '*value' and returns 0; otherwise returns
159 * an OpenFlow error. */
161 ofpprop_parse_be32(const struct ofpbuf
*property
, ovs_be32
*value
)
163 ovs_be32
*p
= property
->msg
;
164 if (ofpbuf_msgsize(property
) != sizeof *p
) {
165 return OFPERR_OFPBPC_BAD_LEN
;
171 /* Attempts to parse 'property' as a property containing a 64-bit value. If
172 * successful, stores the value into '*value' and returns 0; otherwise returns
173 * an OpenFlow error. */
175 ofpprop_parse_be64(const struct ofpbuf
*property
, ovs_be64
*value
)
178 size_t be64_offset
= ROUND_UP(ofpbuf_headersize(property
), 8);
179 if (property
->size
!= be64_offset
+ sizeof *p
) {
180 return OFPERR_OFPBPC_BAD_LEN
;
183 p
= ALIGNED_CAST(ovs_be64
*, (char *) property
->data
+ be64_offset
);
188 /* Attempts to parse 'property' as a property containing a 8-bit value. If
189 * successful, stores the value into '*value' and returns 0; otherwise returns
190 * an OpenFlow error. */
192 ofpprop_parse_u8(const struct ofpbuf
*property
, uint8_t *value
)
194 /* OpenFlow 1.5 and earlier don't have any 8-bit properties, but it uses
195 * 8-byte properties for 16-bit values, which doesn't really make sense.
196 * Be forgiving by allowing any size payload as long as it's at least big
198 uint8_t *p
= property
->msg
;
199 if (ofpbuf_msgsize(property
) < sizeof *p
) {
200 return OFPERR_OFPBPC_BAD_LEN
;
206 /* Attempts to parse 'property' as a property containing a 16-bit value. If
207 * successful, stores the value into '*value' and returns 0; otherwise returns
208 * an OpenFlow error. */
210 ofpprop_parse_u16(const struct ofpbuf
*property
, uint16_t *value
)
212 /* OpenFlow uses 8-byte properties for 16-bit values, which doesn't really
213 * make sense. Be forgiving by allowing any size payload as long as it's
214 * at least big enough. */
215 ovs_be16
*p
= property
->msg
;
216 if (ofpbuf_msgsize(property
) < sizeof *p
) {
217 return OFPERR_OFPBPC_BAD_LEN
;
223 /* Attempts to parse 'property' as a property containing a 32-bit value. If
224 * successful, stores the value into '*value' and returns 0; otherwise returns
225 * an OpenFlow error. */
227 ofpprop_parse_u32(const struct ofpbuf
*property
, uint32_t *value
)
229 ovs_be32
*p
= property
->msg
;
230 if (ofpbuf_msgsize(property
) != sizeof *p
) {
231 return OFPERR_OFPBPC_BAD_LEN
;
237 /* Attempts to parse 'property' as a property containing a 64-bit value. If
238 * successful, stores the value into '*value' and returns 0; otherwise returns
239 * an OpenFlow error. */
241 ofpprop_parse_u64(const struct ofpbuf
*property
, uint64_t *value
)
244 size_t be64_offset
= ROUND_UP(ofpbuf_headersize(property
), 8);
245 if (property
->size
!= be64_offset
+ sizeof *p
) {
246 return OFPERR_OFPBPC_BAD_LEN
;
249 p
= ALIGNED_CAST(ovs_be64
*, (char *) property
->data
+ be64_offset
);
254 /* Attempts to parse 'property' as a property containing a UUID. If
255 * successful, stores the value into '*uuid' and returns 0; otherwise returns
256 * an OpenFlow error. */
258 ofpprop_parse_uuid(const struct ofpbuf
*property
, struct uuid
*uuid
)
260 struct uuid
*p
= property
->msg
;
261 if (ofpbuf_msgsize(property
) != sizeof *p
) {
262 return OFPERR_OFPBPC_BAD_LEN
;
268 /* Attempts to parse 'property' as a property that contains nested properties.
269 * If successful, stores the nested data into '*nested' and returns 0;
270 * otherwise returns an OpenFlow error.
272 * The only thing special about nested properties is that the property header
273 * is followed by 4 bytes of padding, so that the nested properties begin at an
274 * 8-byte aligned offset. This function can be used in other situations where
275 * this is the case. */
277 ofpprop_parse_nested(const struct ofpbuf
*property
, struct ofpbuf
*nested
)
279 size_t nested_offset
= ROUND_UP(ofpbuf_headersize(property
), 8);
280 if (property
->size
< nested_offset
) {
281 return OFPERR_OFPBPC_BAD_LEN
;
284 ofpbuf_use_const(nested
, property
->data
, property
->size
);
285 ofpbuf_pull(nested
, nested_offset
);
289 /* Adds a property with the given 'type' and 'len'-byte contents 'value' to
290 * 'msg', padding the property out to a multiple of 8 bytes. */
292 ofpprop_put(struct ofpbuf
*msg
, uint64_t type
, const void *value
, size_t len
)
294 size_t start_ofs
= ofpprop_start(msg
, type
);
295 ofpbuf_put(msg
, value
, len
);
296 ofpprop_end(msg
, start_ofs
);
299 /* Adds a property with the given 'type' to 'msg', consisting of a struct
300 * ofp_prop_header or ofp_prop_experimenter followed by enough zero bytes to
301 * total 'len' bytes, followed by padding to bring the property up to a
302 * multiple of 8 bytes. Returns the property header. */
304 ofpprop_put_zeros(struct ofpbuf
*msg
, uint64_t type
, size_t len
)
306 void *header
= ofpbuf_put_zeros(msg
, ROUND_UP(len
, 8));
307 if (!ofpprop_is_experimenter(type
)) {
308 struct ofp_prop_header
*oph
= header
;
309 oph
->type
= htons(type
);
310 oph
->len
= htons(len
);
312 struct ofp_prop_experimenter
*ope
= header
;
313 ope
->type
= htons(0xffff);
314 ope
->len
= htons(len
);
315 ope
->experimenter
= htonl(ofpprop_type_to_exp_id(type
));
316 ope
->exp_type
= htonl(ofpprop_type_to_exp_type(type
));
321 /* Adds a property with the given 'type' and 16-bit 'value' to 'msg'. */
323 ofpprop_put_be16(struct ofpbuf
*msg
, uint64_t type
, ovs_be16 value
)
325 if (!ofpprop_is_experimenter(type
)) {
326 /* The OpenFlow specs consistently (at least they're consistent!) give
327 * properties with a 16-bit integer value a length of 8, not 6, so add
328 * two bytes of padding. */
329 ovs_be16 padded_value
[2] = { value
, 0 };
330 ofpprop_put(msg
, type
, padded_value
, sizeof padded_value
);
332 /* There's no precedent but let's assume that this is generally done
334 ofpprop_put(msg
, type
, &value
, sizeof value
);
338 /* Adds a property with the given 'type' and 32-bit 'value' to 'msg'. */
340 ofpprop_put_be32(struct ofpbuf
*msg
, uint64_t type
, ovs_be32 value
)
342 ofpprop_put(msg
, type
, &value
, sizeof value
);
345 /* Adds a property with the given 'type' and 64-bit 'value' to 'msg'. */
347 ofpprop_put_be64(struct ofpbuf
*msg
, uint64_t type
, ovs_be64 value
)
349 size_t start
= ofpprop_start(msg
, type
);
350 ofpbuf_put_zeros(msg
, 4);
351 ofpbuf_put(msg
, &value
, sizeof value
);
352 ofpprop_end(msg
, start
);
355 /* Adds a property with the given 'type' and 8-bit 'value' to 'msg'. */
357 ofpprop_put_u8(struct ofpbuf
*msg
, uint64_t type
, uint8_t value
)
359 /* There's no precedent for 8-bit properties in OpenFlow 1.5 and earlier
360 * but let's assume they're done sanely. */
361 ofpprop_put(msg
, type
, &value
, 1);
364 /* Adds a property with the given 'type' and 16-bit 'value' to 'msg'. */
366 ofpprop_put_u16(struct ofpbuf
*msg
, uint64_t type
, uint16_t value
)
368 ofpprop_put_be16(msg
, type
, htons(value
));
371 /* Adds a property with the given 'type' and 32-bit 'value' to 'msg'. */
373 ofpprop_put_u32(struct ofpbuf
*msg
, uint64_t type
, uint32_t value
)
375 ofpprop_put_be32(msg
, type
, htonl(value
));
378 /* Adds a property with the given 'type' and 64-bit 'value' to 'msg'. */
380 ofpprop_put_u64(struct ofpbuf
*msg
, uint64_t type
, uint64_t value
)
382 ofpprop_put_be64(msg
, type
, htonll(value
));
385 /* Appends a property to 'msg' whose type is 'type' and whose contents is a
386 * series of property headers, one for each 1-bit in 'bitmap'. */
388 ofpprop_put_bitmap(struct ofpbuf
*msg
, uint64_t type
, uint64_t bitmap
)
390 size_t start_ofs
= ofpprop_start(msg
, type
);
392 for (; bitmap
; bitmap
= zero_rightmost_1bit(bitmap
)) {
393 ofpprop_start(msg
, rightmost_1bit_idx(bitmap
));
395 ofpprop_end(msg
, start_ofs
);
398 /* Appends a content-free property with the given 'type' to 'msg'.
400 * (The idea is that the presence of the property acts as a flag.) */
402 ofpprop_put_flag(struct ofpbuf
*msg
, uint64_t type
)
404 size_t start
= ofpprop_start(msg
, type
);
405 ofpprop_end(msg
, start
);
408 /* Appends a property to 'msg' with the given 'type' and 'uuid' as its
411 ofpprop_put_uuid(struct ofpbuf
*msg
, uint64_t type
, const struct uuid
*uuid
)
413 ofpprop_put(msg
, type
, uuid
, sizeof *uuid
);
416 /* Appends a property of type 'type' to 'msg' whose contents are padding to
417 * 8-byte alignment followed by 'nested'. This is a suitable way to add nested
418 * properties to 'msg'. */
420 ofpprop_put_nested(struct ofpbuf
*msg
, uint64_t type
,
421 const struct ofpbuf
*nested
)
423 size_t start
= ofpprop_start_nested(msg
, type
);
424 ofpbuf_put(msg
, nested
->data
, nested
->size
);
425 ofpprop_end(msg
, start
);
428 /* Appends a header for a property of type 'type' to 'msg'. The caller should
429 * add the contents of the property to 'msg', then finish it by calling
430 * ofpprop_end(). Returns the offset of the beginning of the property (to pass
431 * to ofpprop_end() later). */
433 ofpprop_start(struct ofpbuf
*msg
, uint64_t type
)
435 size_t start_ofs
= msg
->size
;
436 if (!ofpprop_is_experimenter(type
)) {
437 struct ofp_prop_header
*oph
= ofpbuf_put_uninit(msg
, sizeof *oph
);
438 oph
->type
= htons(type
);
441 struct ofp_prop_experimenter
*ope
442 = ofpbuf_put_uninit(msg
, sizeof *ope
);
443 ope
->type
= htons(0xffff);
444 ope
->len
= htons(12);
445 ope
->experimenter
= htonl(ofpprop_type_to_exp_id(type
));
446 ope
->exp_type
= htonl(ofpprop_type_to_exp_type(type
));
451 /* Finishes serializing a property that was begun with ofpprop_start(), by
452 * padding 'msg' to a multiple of 8 bytes and updating the property's length.
453 * 'start_ofs' should be the offset of the beginning of the property, as
454 * returned by ofpprop_start(). */
456 ofpprop_end(struct ofpbuf
*msg
, size_t start_ofs
)
458 struct ofp_prop_header
*oph
;
460 oph
= ofpbuf_at_assert(msg
, start_ofs
, sizeof *oph
);
461 oph
->len
= htons(msg
->size
- start_ofs
);
462 ofpbuf_padto(msg
, ROUND_UP(msg
->size
, 8));
465 /* Appends a header for a property of type 'type' to 'msg', followed by padding
466 * suitable for putting nested properties into the property; that is, padding
467 * to an 8-byte alignment.
469 * This otherwise works like ofpprop_start().
471 * There's no need for ofpprop_end_nested(), because ofpprop_end() works fine
474 ofpprop_start_nested(struct ofpbuf
*msg
, uint64_t type
)
476 size_t start_ofs
= ofpprop_start(msg
, type
);
477 ofpbuf_padto(msg
, ROUND_UP(msg
->size
, 8));
482 ofpprop_unknown(struct vlog_module
*module
, bool loose
, const char *msg
,
485 bool is_experimenter
= ofpprop_is_experimenter(type
);
487 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 5);
488 enum vlog_level level
= loose
? VLL_DBG
: VLL_WARN
;
489 if (!is_experimenter
) {
490 vlog_rate_limit(module
, level
, &rl
, "unknown %s property type %"PRId64
,
493 vlog_rate_limit(module
, level
, &rl
,
494 "unknown %s property type for exp_id 0x%"PRIx32
", "
495 "exp_type %"PRId32
, msg
,
496 ofpprop_type_to_exp_id(type
),
497 ofpprop_type_to_exp_type(type
));
500 /* There's an error OFPBPC_BAD_EXPERIMENTER that we could use for
501 * experimenter IDs that we don't know at all, but that seems like a
502 * difficult distinction and OFPERR_OFPBPC_BAD_EXP_TYPE communicates the
503 * problem quite well. */
505 : is_experimenter
? OFPERR_OFPBPC_BAD_EXP_TYPE
506 : OFPERR_OFPBPC_BAD_TYPE
);