]>
Commit | Line | Data |
---|---|---|
982697a4 | 1 | /* |
0a96a21b | 2 | * Copyright (c) 2012, 2013, 2014, 2015, 2016 Nicira, Inc. |
982697a4 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> | |
982697a4 | 18 | #include "byte-order.h" |
982697a4 | 19 | #include "hash.h" |
ee89ea7b | 20 | #include "openvswitch/hmap.h" |
982697a4 BP |
21 | #include "openflow/nicira-ext.h" |
22 | #include "openflow/openflow.h" | |
d271907f BW |
23 | #include "openvswitch/dynamic-string.h" |
24 | #include "openvswitch/ofp-msgs.h" | |
25 | #include "openvswitch/ofpbuf.h" | |
e6211adc | 26 | #include "openvswitch/vlog.h" |
d271907f | 27 | #include "ovs-thread.h" |
ee89ea7b | 28 | #include "util.h" |
982697a4 BP |
29 | |
30 | VLOG_DEFINE_THIS_MODULE(ofp_msgs); | |
31 | ||
32 | #define OFPT_VENDOR 4 | |
33 | #define OFPT10_STATS_REQUEST 16 | |
34 | #define OFPT10_STATS_REPLY 17 | |
35 | #define OFPT11_STATS_REQUEST 18 | |
36 | #define OFPT11_STATS_REPLY 19 | |
37 | #define OFPST_VENDOR 0xffff | |
38 | ||
2123bc8c BP |
39 | /* Vendor extension message. */ |
40 | struct ofp_vendor_header { | |
41 | struct ofp_header header; /* OFPT_VENDOR. */ | |
42 | ovs_be32 vendor; /* Vendor ID: | |
43 | * - MSB 0: low-order bytes are IEEE OUI. | |
44 | * - MSB != 0: defined by OpenFlow | |
45 | * consortium. */ | |
46 | ||
47 | /* In theory everything after 'vendor' is vendor specific. In practice, | |
48 | * the vendors we support put a 32-bit subtype here. We'll change this | |
49 | * structure if we start adding support for other vendor formats. */ | |
50 | ovs_be32 subtype; /* Vendor-specific subtype. */ | |
51 | ||
52 | /* Followed by vendor-defined additional data. */ | |
53 | }; | |
54 | OFP_ASSERT(sizeof(struct ofp_vendor_header) == 16); | |
55 | ||
df63a142 BP |
56 | /* Statistics request or reply message. */ |
57 | struct ofp10_stats_msg { | |
58 | struct ofp_header header; | |
59 | ovs_be16 type; /* One of the OFPST_* constants. */ | |
60 | ovs_be16 flags; /* Requests: always 0. | |
61 | * Replies: 0 or OFPSF_REPLY_MORE. */ | |
62 | }; | |
63 | OFP_ASSERT(sizeof(struct ofp10_stats_msg) == 12); | |
64 | ||
65 | /* Vendor extension stats message. */ | |
66 | struct ofp10_vendor_stats_msg { | |
67 | struct ofp10_stats_msg osm; /* Type OFPST_VENDOR. */ | |
68 | ovs_be32 vendor; /* Vendor ID: | |
69 | * - MSB 0: low-order bytes are IEEE OUI. | |
70 | * - MSB != 0: defined by OpenFlow | |
71 | * consortium. */ | |
72 | /* Followed by vendor-defined arbitrary additional data. */ | |
73 | }; | |
74 | OFP_ASSERT(sizeof(struct ofp10_vendor_stats_msg) == 16); | |
75 | ||
76 | struct ofp11_stats_msg { | |
77 | struct ofp_header header; | |
78 | ovs_be16 type; /* One of the OFPST_* constants. */ | |
79 | ovs_be16 flags; /* OFPSF_REQ_* flags (none yet defined). */ | |
80 | uint8_t pad[4]; | |
81 | /* Followed by the body of the request. */ | |
82 | }; | |
83 | OFP_ASSERT(sizeof(struct ofp11_stats_msg) == 16); | |
84 | ||
2123bc8c BP |
85 | /* Vendor extension stats message. */ |
86 | struct ofp11_vendor_stats_msg { | |
87 | struct ofp11_stats_msg osm; /* Type OFPST_VENDOR. */ | |
88 | ovs_be32 vendor; /* Vendor ID: | |
89 | * - MSB 0: low-order bytes are IEEE OUI. | |
90 | * - MSB != 0: defined by OpenFlow | |
91 | * consortium. */ | |
92 | ||
93 | /* In theory everything after 'vendor' is vendor specific. In practice, | |
94 | * the vendors we support put a 32-bit subtype here. We'll change this | |
95 | * structure if we start adding support for other vendor formats. */ | |
96 | ovs_be32 subtype; /* Vendor-specific subtype. */ | |
97 | ||
98 | /* Followed by vendor-defined additional data. */ | |
99 | }; | |
100 | OFP_ASSERT(sizeof(struct ofp11_vendor_stats_msg) == 24); | |
df63a142 BP |
101 | |
102 | /* Header for Nicira vendor stats request and reply messages in OpenFlow | |
103 | * 1.0. */ | |
104 | struct nicira10_stats_msg { | |
105 | struct ofp10_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */ | |
106 | ovs_be32 subtype; /* One of NXST_* below. */ | |
107 | uint8_t pad[4]; /* Align to 64-bits. */ | |
108 | }; | |
109 | OFP_ASSERT(sizeof(struct nicira10_stats_msg) == 24); | |
110 | ||
982697a4 BP |
111 | /* A thin abstraction of OpenFlow headers: |
112 | * | |
113 | * - 'version' and 'type' come straight from struct ofp_header, so these are | |
114 | * always present and meaningful. | |
115 | * | |
116 | * - 'stat' comes from the 'type' member in statistics messages only. It is | |
117 | * meaningful, therefore, only if 'version' and 'type' taken together | |
118 | * specify a statistics request or reply. Otherwise it is 0. | |
119 | * | |
120 | * - 'vendor' is meaningful only for vendor messages, that is, if 'version' | |
121 | * and 'type' specify a vendor message or if 'version' and 'type' specify | |
122 | * a statistics message and 'stat' specifies a vendor statistic type. | |
123 | * Otherwise it is 0. | |
124 | * | |
125 | * - 'subtype' is meaningful only for vendor messages and otherwise 0. It | |
126 | * specifies a vendor-defined subtype. There is no standard format for | |
127 | * these but 32 bits seems like it should be enough. */ | |
128 | struct ofphdrs { | |
129 | uint8_t version; /* From ofp_header. */ | |
130 | uint8_t type; /* From ofp_header. */ | |
131 | uint16_t stat; /* From ofp10_stats_msg or ofp11_stats_msg. */ | |
132 | uint32_t vendor; /* From ofp_vendor_header, | |
133 | * ofp10_vendor_stats_msg, or | |
134 | * ofp11_vendor_stats_msg. */ | |
135 | uint32_t subtype; /* From nicira_header, nicira10_stats_msg, or | |
136 | * nicira11_stats_msg. */ | |
137 | }; | |
138 | BUILD_ASSERT_DECL(sizeof(struct ofphdrs) == 12); | |
139 | ||
140 | /* A mapping from OpenFlow headers to OFPRAW_*. */ | |
141 | struct raw_instance { | |
142 | struct hmap_node hmap_node; /* In 'raw_instance_map'. */ | |
143 | struct ofphdrs hdrs; /* Key. */ | |
144 | enum ofpraw raw; /* Value. */ | |
145 | unsigned int hdrs_len; /* ofphdrs_len(hdrs). */ | |
146 | }; | |
147 | ||
148 | /* Information about a particular 'enum ofpraw'. */ | |
149 | struct raw_info { | |
150 | /* All possible instantiations of this OFPRAW_* into OpenFlow headers. */ | |
151 | struct raw_instance *instances; /* min_version - max_version + 1 elems. */ | |
152 | uint8_t min_version; | |
153 | uint8_t max_version; | |
154 | ||
155 | unsigned int min_body; | |
156 | unsigned int extra_multiple; | |
157 | enum ofptype type; | |
158 | const char *name; | |
159 | }; | |
160 | ||
161 | /* All understood OpenFlow message types, indexed by their 'struct ofphdrs'. */ | |
162 | static struct hmap raw_instance_map; | |
163 | #include "ofp-msgs.inc" | |
164 | ||
165 | static ovs_be32 alloc_xid(void); | |
166 | ||
167 | /* ofphdrs functions. */ | |
168 | static uint32_t ofphdrs_hash(const struct ofphdrs *); | |
169 | static bool ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b); | |
170 | static enum ofperr ofphdrs_decode(struct ofphdrs *, | |
171 | const struct ofp_header *oh, size_t length); | |
172 | static void ofphdrs_decode_assert(struct ofphdrs *, | |
173 | const struct ofp_header *oh, size_t length); | |
174 | size_t ofphdrs_len(const struct ofphdrs *); | |
175 | ||
176 | static const struct raw_info *raw_info_get(enum ofpraw); | |
177 | static struct raw_instance *raw_instance_get(const struct raw_info *, | |
178 | uint8_t version); | |
179 | ||
180 | static enum ofperr ofpraw_from_ofphdrs(enum ofpraw *, const struct ofphdrs *); | |
181 | \f | |
182 | /* Returns a transaction ID to use for an outgoing OpenFlow message. */ | |
183 | static ovs_be32 | |
184 | alloc_xid(void) | |
185 | { | |
ca4fbdfe | 186 | static atomic_count next_xid = ATOMIC_COUNT_INIT(1); |
d0c79f7f | 187 | |
ca4fbdfe | 188 | return htonl(atomic_count_inc(&next_xid)); |
982697a4 BP |
189 | } |
190 | \f | |
191 | static uint32_t | |
192 | ofphdrs_hash(const struct ofphdrs *hdrs) | |
193 | { | |
0a96a21b BP |
194 | BUILD_ASSERT_DECL(sizeof *hdrs % 4 == 0); |
195 | return hash_bytes32((const uint32_t *) hdrs, sizeof *hdrs, 0); | |
982697a4 BP |
196 | } |
197 | ||
198 | static bool | |
199 | ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b) | |
200 | { | |
201 | return !memcmp(a, b, sizeof *a); | |
202 | } | |
203 | ||
204 | static void | |
205 | log_bad_vendor(uint32_t vendor) | |
206 | { | |
207 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); | |
208 | ||
209 | VLOG_WARN_RL(&rl, "OpenFlow message has unknown vendor %#"PRIx32, vendor); | |
210 | } | |
211 | ||
212 | static enum ofperr | |
213 | ofphdrs_decode(struct ofphdrs *hdrs, | |
214 | const struct ofp_header *oh, size_t length) | |
215 | { | |
216 | memset(hdrs, 0, sizeof *hdrs); | |
217 | if (length < sizeof *oh) { | |
218 | return OFPERR_OFPBRC_BAD_LEN; | |
219 | } | |
220 | ||
221 | /* Get base message version and type (OFPT_*). */ | |
222 | hdrs->version = oh->version; | |
223 | hdrs->type = oh->type; | |
224 | ||
225 | if (hdrs->type == OFPT_VENDOR) { | |
226 | /* Get vendor. */ | |
227 | const struct ofp_vendor_header *ovh; | |
228 | ||
229 | if (length < sizeof *ovh) { | |
230 | return OFPERR_OFPBRC_BAD_LEN; | |
231 | } | |
232 | ||
233 | ovh = (const struct ofp_vendor_header *) oh; | |
234 | hdrs->vendor = ntohl(ovh->vendor); | |
2123bc8c BP |
235 | if (hdrs->vendor == NX_VENDOR_ID || hdrs->vendor == ONF_VENDOR_ID) { |
236 | hdrs->subtype = ntohl(ovh->subtype); | |
982697a4 BP |
237 | } else { |
238 | log_bad_vendor(hdrs->vendor); | |
239 | return OFPERR_OFPBRC_BAD_VENDOR; | |
240 | } | |
241 | } else if (hdrs->version == OFP10_VERSION | |
242 | && (hdrs->type == OFPT10_STATS_REQUEST || | |
243 | hdrs->type == OFPT10_STATS_REPLY)) { | |
e2b9ac44 | 244 | const struct ofp10_stats_msg *osm; |
982697a4 BP |
245 | |
246 | /* Get statistic type (OFPST_*). */ | |
247 | if (length < sizeof *osm) { | |
248 | return OFPERR_OFPBRC_BAD_LEN; | |
249 | } | |
e2b9ac44 | 250 | osm = (const struct ofp10_stats_msg *) oh; |
982697a4 BP |
251 | hdrs->stat = ntohs(osm->type); |
252 | ||
253 | if (hdrs->stat == OFPST_VENDOR) { | |
254 | /* Get vendor. */ | |
255 | const struct ofp10_vendor_stats_msg *ovsm; | |
256 | ||
257 | if (length < sizeof *ovsm) { | |
258 | return OFPERR_OFPBRC_BAD_LEN; | |
259 | } | |
260 | ||
261 | ovsm = (const struct ofp10_vendor_stats_msg *) oh; | |
262 | hdrs->vendor = ntohl(ovsm->vendor); | |
263 | if (hdrs->vendor == NX_VENDOR_ID) { | |
264 | /* Get Nicira statistic type (NXST_*). */ | |
265 | const struct nicira10_stats_msg *nsm; | |
266 | ||
267 | if (length < sizeof *nsm) { | |
268 | return OFPERR_OFPBRC_BAD_LEN; | |
269 | } | |
270 | nsm = (const struct nicira10_stats_msg *) oh; | |
271 | hdrs->subtype = ntohl(nsm->subtype); | |
272 | } else { | |
273 | log_bad_vendor(hdrs->vendor); | |
274 | return OFPERR_OFPBRC_BAD_VENDOR; | |
275 | } | |
276 | } | |
277 | } else if (hdrs->version != OFP10_VERSION | |
278 | && (hdrs->type == OFPT11_STATS_REQUEST || | |
279 | hdrs->type == OFPT11_STATS_REPLY)) { | |
280 | const struct ofp11_stats_msg *osm; | |
281 | ||
282 | /* Get statistic type (OFPST_*). */ | |
283 | if (length < sizeof *osm) { | |
284 | return OFPERR_OFPBRC_BAD_LEN; | |
285 | } | |
286 | osm = (const struct ofp11_stats_msg *) oh; | |
287 | hdrs->stat = ntohs(osm->type); | |
288 | ||
289 | if (hdrs->stat == OFPST_VENDOR) { | |
290 | /* Get vendor. */ | |
291 | const struct ofp11_vendor_stats_msg *ovsm; | |
292 | ||
293 | if (length < sizeof *ovsm) { | |
294 | return OFPERR_OFPBRC_BAD_LEN; | |
295 | } | |
296 | ||
297 | ovsm = (const struct ofp11_vendor_stats_msg *) oh; | |
298 | hdrs->vendor = ntohl(ovsm->vendor); | |
2123bc8c BP |
299 | if (hdrs->vendor == NX_VENDOR_ID || |
300 | hdrs->vendor == ONF_VENDOR_ID) { | |
301 | hdrs->subtype = ntohl(ovsm->subtype); | |
982697a4 BP |
302 | } else { |
303 | log_bad_vendor(hdrs->vendor); | |
304 | return OFPERR_OFPBRC_BAD_VENDOR; | |
305 | } | |
306 | } | |
307 | } | |
308 | ||
309 | return 0; | |
310 | } | |
311 | ||
312 | static void | |
313 | ofphdrs_decode_assert(struct ofphdrs *hdrs, | |
314 | const struct ofp_header *oh, size_t length) | |
315 | { | |
500db308 | 316 | ovs_assert(!ofphdrs_decode(hdrs, oh, length)); |
982697a4 BP |
317 | } |
318 | ||
319 | static bool | |
76ec08e0 | 320 | ofp_is_stat_request(enum ofp_version version, uint8_t type) |
982697a4 | 321 | { |
76ec08e0 YT |
322 | switch (version) { |
323 | case OFP10_VERSION: | |
324 | return type == OFPT10_STATS_REQUEST; | |
325 | case OFP11_VERSION: | |
326 | case OFP12_VERSION: | |
327 | case OFP13_VERSION: | |
c37c0382 | 328 | case OFP14_VERSION: |
42dccab5 | 329 | case OFP15_VERSION: |
76ec08e0 YT |
330 | return type == OFPT11_STATS_REQUEST; |
331 | } | |
332 | ||
333 | return false; | |
334 | } | |
335 | ||
336 | static bool | |
337 | ofp_is_stat_reply(enum ofp_version version, uint8_t type) | |
338 | { | |
339 | switch (version) { | |
2e3fa633 | 340 | case OFP10_VERSION: |
76ec08e0 | 341 | return type == OFPT10_STATS_REPLY; |
2e3fa633 SH |
342 | case OFP11_VERSION: |
343 | case OFP12_VERSION: | |
2e1ae200 | 344 | case OFP13_VERSION: |
c37c0382 | 345 | case OFP14_VERSION: |
42dccab5 | 346 | case OFP15_VERSION: |
76ec08e0 | 347 | return type == OFPT11_STATS_REPLY; |
2e3fa633 SH |
348 | } |
349 | ||
350 | return false; | |
982697a4 BP |
351 | } |
352 | ||
76ec08e0 YT |
353 | static bool |
354 | ofp_is_stat(enum ofp_version version, uint8_t type) | |
355 | { | |
356 | return (ofp_is_stat_request(version, type) || | |
357 | ofp_is_stat_reply(version, type)); | |
358 | } | |
359 | ||
360 | static bool | |
361 | ofphdrs_is_stat(const struct ofphdrs *hdrs) | |
362 | { | |
363 | return ofp_is_stat(hdrs->version, hdrs->type); | |
364 | } | |
365 | ||
982697a4 BP |
366 | size_t |
367 | ofphdrs_len(const struct ofphdrs *hdrs) | |
368 | { | |
369 | if (hdrs->type == OFPT_VENDOR) { | |
2123bc8c | 370 | return sizeof(struct ofp_vendor_header); |
982697a4 BP |
371 | } |
372 | ||
2e3fa633 SH |
373 | switch ((enum ofp_version) hdrs->version) { |
374 | case OFP10_VERSION: | |
982697a4 BP |
375 | if (hdrs->type == OFPT10_STATS_REQUEST || |
376 | hdrs->type == OFPT10_STATS_REPLY) { | |
377 | return (hdrs->stat == OFPST_VENDOR | |
378 | ? sizeof(struct nicira10_stats_msg) | |
e2b9ac44 | 379 | : sizeof(struct ofp10_stats_msg)); |
982697a4 | 380 | } |
2e3fa633 SH |
381 | break; |
382 | ||
383 | case OFP11_VERSION: | |
384 | case OFP12_VERSION: | |
2e1ae200 | 385 | case OFP13_VERSION: |
c37c0382 | 386 | case OFP14_VERSION: |
42dccab5 | 387 | case OFP15_VERSION: |
982697a4 BP |
388 | if (hdrs->type == OFPT11_STATS_REQUEST || |
389 | hdrs->type == OFPT11_STATS_REPLY) { | |
390 | return (hdrs->stat == OFPST_VENDOR | |
2123bc8c | 391 | ? sizeof(struct ofp11_vendor_stats_msg) |
982697a4 BP |
392 | : sizeof(struct ofp11_stats_msg)); |
393 | } | |
2e3fa633 | 394 | break; |
982697a4 BP |
395 | } |
396 | ||
397 | return sizeof(struct ofp_header); | |
398 | } | |
399 | \f | |
400 | /* Determines the OFPRAW_* type of the OpenFlow message at 'oh', which has | |
401 | * length 'oh->length'. (The caller must ensure that 'oh->length' bytes of | |
402 | * data are readable at 'oh'.) On success, returns 0 and stores the type into | |
403 | * '*raw'. On failure, returns an OFPERR_* error code and zeros '*raw'. | |
404 | * | |
405 | * This function checks that 'oh' is a valid length for its particular type of | |
406 | * message, and returns an error if not. */ | |
407 | enum ofperr | |
408 | ofpraw_decode(enum ofpraw *raw, const struct ofp_header *oh) | |
409 | { | |
0a2869d5 | 410 | struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
982697a4 BP |
411 | return ofpraw_pull(raw, &msg); |
412 | } | |
413 | ||
964a5f60 BP |
414 | /* Does the same job as ofpraw_decode(), except that it assert-fails if |
415 | * ofpraw_decode() would have reported an error. Thus, it's able to use the | |
416 | * return value for the OFPRAW_* message type instead of an error code. | |
417 | * | |
418 | * (It only makes sense to use this function if you previously called | |
419 | * ofpraw_decode() on the message and thus know that it's OK.) */ | |
420 | enum ofpraw | |
421 | ofpraw_decode_assert(const struct ofp_header *oh) | |
422 | { | |
964a5f60 | 423 | enum ofpraw raw; |
500db308 | 424 | ovs_assert(!ofpraw_decode(&raw, oh)); |
964a5f60 BP |
425 | return raw; |
426 | } | |
427 | ||
fd4b7a0e BP |
428 | /* Checks that 'len' is a valid length for an OpenFlow message that corresponds |
429 | * to 'info' and 'instance'. Returns 0 if so, otherwise an OpenFlow error. */ | |
430 | static enum ofperr | |
431 | ofpraw_check_length(const struct raw_info *info, | |
432 | const struct raw_instance *instance, | |
433 | unsigned int len) | |
982697a4 BP |
434 | { |
435 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
436 | ||
fd4b7a0e | 437 | unsigned int min_len = instance->hdrs_len + info->min_body; |
982697a4 BP |
438 | switch (info->extra_multiple) { |
439 | case 0: | |
440 | if (len != min_len) { | |
441 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected " | |
442 | "length %u)", info->name, len, min_len); | |
443 | return OFPERR_OFPBRC_BAD_LEN; | |
444 | } | |
445 | break; | |
446 | ||
447 | case 1: | |
448 | if (len < min_len) { | |
449 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected " | |
450 | "length at least %u bytes)", | |
451 | info->name, len, min_len); | |
452 | return OFPERR_OFPBRC_BAD_LEN; | |
453 | } | |
454 | break; | |
455 | ||
456 | default: | |
457 | if (len < min_len || (len - min_len) % info->extra_multiple) { | |
458 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (must be " | |
459 | "exactly %u bytes or longer by an integer multiple " | |
460 | "of %u bytes)", | |
461 | info->name, len, min_len, info->extra_multiple); | |
462 | return OFPERR_OFPBRC_BAD_LEN; | |
463 | } | |
464 | break; | |
465 | } | |
466 | ||
fd4b7a0e BP |
467 | return 0; |
468 | } | |
469 | ||
470 | /* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts | |
471 | * at 'msg->data' and has length 'msg->size' bytes. On success, | |
472 | * returns 0 and stores the type into '*rawp'. On failure, returns an OFPERR_* | |
473 | * error code and zeros '*rawp'. | |
474 | * | |
475 | * This function checks that the message has a valid length for its particular | |
476 | * type of message, and returns an error if not. | |
477 | * | |
478 | * In addition to setting '*rawp', this function pulls off the OpenFlow header | |
479 | * (including the stats headers, vendor header, and any subtype header) with | |
480 | * ofpbuf_pull(). It also sets 'msg->header' to the start of the OpenFlow | |
481 | * header and 'msg->msg' just beyond the headers (that is, to the final value | |
482 | * of msg->data). */ | |
483 | enum ofperr | |
484 | ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg) | |
485 | { | |
486 | /* Set default outputs. */ | |
487 | msg->header = msg->data; | |
488 | msg->msg = msg->header; | |
489 | *rawp = 0; | |
490 | ||
491 | struct ofphdrs hdrs; | |
492 | enum ofperr error = ofphdrs_decode(&hdrs, msg->data, msg->size); | |
493 | if (error) { | |
494 | return error; | |
495 | } | |
496 | ||
497 | enum ofpraw raw; | |
498 | error = ofpraw_from_ofphdrs(&raw, &hdrs); | |
499 | if (error) { | |
500 | return error; | |
501 | } | |
502 | ||
503 | const struct raw_info *info = raw_info_get(raw); | |
504 | const struct raw_instance *instance = raw_instance_get(info, hdrs.version); | |
505 | error = ofpraw_check_length(info, instance, msg->size); | |
506 | if (error) { | |
507 | return error; | |
508 | } | |
509 | ||
510 | msg->header = ofpbuf_pull(msg, instance->hdrs_len); | |
511 | msg->msg = msg->data; | |
982697a4 BP |
512 | *rawp = raw; |
513 | return 0; | |
514 | } | |
515 | ||
516 | /* Does the same job as ofpraw_pull(), except that it assert-fails if | |
e032c086 | 517 | * ofpraw_pull() would have reported an error. Thus, it's able to use the |
982697a4 BP |
518 | * return value for the OFPRAW_* message type instead of an error code. |
519 | * | |
520 | * (It only makes sense to use this function if you previously called | |
e032c086 | 521 | * ofpraw_decode() on the message and thus know that it's OK.) */ |
982697a4 BP |
522 | enum ofpraw |
523 | ofpraw_pull_assert(struct ofpbuf *msg) | |
524 | { | |
982697a4 | 525 | enum ofpraw raw; |
500db308 | 526 | ovs_assert(!ofpraw_pull(&raw, msg)); |
982697a4 BP |
527 | return raw; |
528 | } | |
529 | ||
530 | /* Determines the OFPRAW_* type of the OpenFlow message that starts at 'oh' and | |
531 | * has length 'length' bytes. On success, returns 0 and stores the type into | |
532 | * '*rawp'. On failure, returns an OFPERR_* error code and zeros '*rawp'. | |
533 | * | |
534 | * Unlike other functions for decoding message types, this one is not picky | |
535 | * about message length. For example, it will successfully decode a message | |
536 | * whose body is shorter than the minimum length for a message of its type. | |
537 | * Thus, this is the correct function to use for decoding the type of a message | |
538 | * that might have been truncated, such as the payload of an OpenFlow error | |
539 | * message (which is allowed to be truncated to 64 bytes). */ | |
540 | enum ofperr | |
541 | ofpraw_decode_partial(enum ofpraw *raw, | |
542 | const struct ofp_header *oh, size_t length) | |
543 | { | |
544 | struct ofphdrs hdrs; | |
545 | enum ofperr error; | |
546 | ||
547 | error = ofphdrs_decode(&hdrs, oh, length); | |
548 | if (!error) { | |
549 | error = ofpraw_from_ofphdrs(raw, &hdrs); | |
550 | } | |
551 | ||
552 | if (error) { | |
553 | *raw = 0; | |
554 | } | |
555 | return error; | |
556 | } | |
557 | \f | |
558 | /* Encoding messages using OFPRAW_* values. */ | |
559 | ||
560 | static void ofpraw_put__(enum ofpraw, uint8_t version, ovs_be32 xid, | |
561 | size_t extra_tailroom, struct ofpbuf *); | |
562 | ||
563 | /* Allocates and returns a new ofpbuf that contains an OpenFlow header for | |
564 | * 'raw' with OpenFlow version 'version' and a fresh OpenFlow transaction ID. | |
565 | * The ofpbuf has enough tailroom for the minimum body length of 'raw', plus | |
566 | * 'extra_tailroom' additional bytes. | |
567 | * | |
568 | * Each 'raw' value is valid only for certain OpenFlow versions. The caller | |
569 | * must specify a valid (raw, version) pair. | |
570 | * | |
77a9bb31 BP |
571 | * In the returned ofpbuf, 'header' points to the beginning of the |
572 | * OpenFlow header and 'msg' points just after it, to where the | |
cf3b7538 JR |
573 | * message's body will start. The caller must actually allocate the |
574 | * body into the space reserved for it, e.g. with ofpbuf_put_uninit(). | |
982697a4 BP |
575 | * |
576 | * The caller owns the returned ofpbuf and must free it when it is no longer | |
577 | * needed, e.g. with ofpbuf_delete(). */ | |
578 | struct ofpbuf * | |
579 | ofpraw_alloc(enum ofpraw raw, uint8_t version, size_t extra_tailroom) | |
580 | { | |
581 | return ofpraw_alloc_xid(raw, version, alloc_xid(), extra_tailroom); | |
582 | } | |
583 | ||
584 | /* Same as ofpraw_alloc() but the caller provides the transaction ID. */ | |
585 | struct ofpbuf * | |
586 | ofpraw_alloc_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid, | |
587 | size_t extra_tailroom) | |
588 | { | |
589 | struct ofpbuf *buf = ofpbuf_new(0); | |
590 | ofpraw_put__(raw, version, xid, extra_tailroom, buf); | |
591 | return buf; | |
592 | } | |
593 | ||
594 | /* Same as ofpraw_alloc(), but obtains the OpenFlow version and transaction ID | |
595 | * from 'request->version' and 'request->xid', respectively. | |
596 | * | |
597 | * Even though the version comes from 'request->version', the caller must still | |
598 | * know what it is doing, by specifying a valid pairing of 'raw' and | |
599 | * 'request->version', just like ofpraw_alloc(). */ | |
600 | struct ofpbuf * | |
601 | ofpraw_alloc_reply(enum ofpraw raw, const struct ofp_header *request, | |
602 | size_t extra_tailroom) | |
603 | { | |
604 | return ofpraw_alloc_xid(raw, request->version, request->xid, | |
605 | extra_tailroom); | |
606 | } | |
607 | ||
608 | /* Allocates and returns a new ofpbuf that contains an OpenFlow header that is | |
609 | * a stats reply to the stats request in 'request', using the same OpenFlow | |
610 | * version and transaction ID as 'request'. The ofpbuf has enough tailroom for | |
611 | * the stats reply's minimum body length, plus 'extra_tailroom' additional | |
612 | * bytes. | |
613 | * | |
614 | * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST* | |
615 | * value. Every stats request has a corresponding reply, so the (raw, version) | |
616 | * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here. | |
617 | * | |
77a9bb31 BP |
618 | * In the returned ofpbuf, 'header' points to the beginning of the |
619 | * OpenFlow header and 'msg' points just after it, to where the | |
cf3b7538 JR |
620 | * message's body will start. The caller must actually allocate the |
621 | * body into the space reserved for it, e.g. with ofpbuf_put_uninit(). | |
982697a4 BP |
622 | * |
623 | * The caller owns the returned ofpbuf and must free it when it is no longer | |
624 | * needed, e.g. with ofpbuf_delete(). */ | |
625 | struct ofpbuf * | |
626 | ofpraw_alloc_stats_reply(const struct ofp_header *request, | |
627 | size_t extra_tailroom) | |
628 | { | |
629 | enum ofpraw request_raw; | |
630 | enum ofpraw reply_raw; | |
982697a4 | 631 | |
500db308 BP |
632 | ovs_assert(!ofpraw_decode_partial(&request_raw, request, |
633 | ntohs(request->length))); | |
982697a4 BP |
634 | |
635 | reply_raw = ofpraw_stats_request_to_reply(request_raw, request->version); | |
cb22974d | 636 | ovs_assert(reply_raw); |
982697a4 BP |
637 | |
638 | return ofpraw_alloc_reply(reply_raw, request, extra_tailroom); | |
639 | } | |
640 | ||
641 | /* Appends to 'buf' an OpenFlow header for 'raw' with OpenFlow version | |
642 | * 'version' and a fresh OpenFlow transaction ID. Preallocates enough tailroom | |
643 | * in 'buf' for the minimum body length of 'raw', plus 'extra_tailroom' | |
644 | * additional bytes. | |
645 | * | |
646 | * Each 'raw' value is valid only for certain OpenFlow versions. The caller | |
647 | * must specify a valid (raw, version) pair. | |
648 | * | |
77a9bb31 BP |
649 | * Upon return, 'buf->header' points to the beginning of the OpenFlow header |
650 | * and 'buf->msg' points just after it, to where the message's body will start. | |
651 | * The caller must actually allocating the body into the space reserved for it, | |
982697a4 BP |
652 | * e.g. with ofpbuf_put_uninit(). */ |
653 | void | |
654 | ofpraw_put(enum ofpraw raw, uint8_t version, struct ofpbuf *buf) | |
655 | { | |
656 | ofpraw_put__(raw, version, alloc_xid(), 0, buf); | |
657 | } | |
658 | ||
659 | /* Same as ofpraw_put() but the caller provides the transaction ID. */ | |
660 | void | |
661 | ofpraw_put_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid, | |
662 | struct ofpbuf *buf) | |
663 | { | |
664 | ofpraw_put__(raw, version, xid, 0, buf); | |
665 | } | |
666 | ||
667 | /* Same as ofpraw_put(), but obtains the OpenFlow version and transaction ID | |
668 | * from 'request->version' and 'request->xid', respectively. | |
669 | * | |
670 | * Even though the version comes from 'request->version', the caller must still | |
671 | * know what it is doing, by specifying a valid pairing of 'raw' and | |
672 | * 'request->version', just like ofpraw_put(). */ | |
673 | void | |
674 | ofpraw_put_reply(enum ofpraw raw, const struct ofp_header *request, | |
675 | struct ofpbuf *buf) | |
676 | { | |
677 | ofpraw_put__(raw, request->version, request->xid, 0, buf); | |
678 | } | |
679 | ||
680 | /* Appends to 'buf' an OpenFlow header that is a stats reply to the stats | |
681 | * request in 'request', using the same OpenFlow version and transaction ID as | |
682 | * 'request'. Preallocate enough tailroom in 'buf for the stats reply's | |
683 | * minimum body length, plus 'extra_tailroom' additional bytes. | |
684 | * | |
685 | * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST* | |
686 | * value. Every stats request has a corresponding reply, so the (raw, version) | |
687 | * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here. | |
688 | * | |
77a9bb31 BP |
689 | * In the returned ofpbuf, 'header' points to the beginning of the |
690 | * OpenFlow header and 'msg' points just after it, to where the | |
cf3b7538 JR |
691 | * message's body will start. The caller must actually allocate the |
692 | * body into the space reserved for it, e.g. with ofpbuf_put_uninit(). | |
982697a4 BP |
693 | * |
694 | * The caller owns the returned ofpbuf and must free it when it is no longer | |
695 | * needed, e.g. with ofpbuf_delete(). */ | |
696 | void | |
697 | ofpraw_put_stats_reply(const struct ofp_header *request, struct ofpbuf *buf) | |
698 | { | |
982697a4 BP |
699 | enum ofpraw raw; |
700 | ||
500db308 | 701 | ovs_assert(!ofpraw_decode_partial(&raw, request, ntohs(request->length))); |
982697a4 BP |
702 | |
703 | raw = ofpraw_stats_request_to_reply(raw, request->version); | |
cb22974d | 704 | ovs_assert(raw); |
982697a4 BP |
705 | |
706 | ofpraw_put__(raw, request->version, request->xid, 0, buf); | |
707 | } | |
708 | ||
709 | static void | |
710 | ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid, | |
711 | size_t extra_tailroom, struct ofpbuf *buf) | |
712 | { | |
713 | const struct raw_info *info = raw_info_get(raw); | |
714 | const struct raw_instance *instance = raw_instance_get(info, version); | |
715 | const struct ofphdrs *hdrs = &instance->hdrs; | |
716 | struct ofp_header *oh; | |
717 | ||
718 | ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body | |
719 | + extra_tailroom)); | |
6fd6ed71 PS |
720 | buf->header = ofpbuf_put_uninit(buf, instance->hdrs_len); |
721 | buf->msg = ofpbuf_tail(buf); | |
982697a4 | 722 | |
6fd6ed71 | 723 | oh = buf->header; |
982697a4 BP |
724 | oh->version = version; |
725 | oh->type = hdrs->type; | |
6fd6ed71 | 726 | oh->length = htons(buf->size); |
982697a4 BP |
727 | oh->xid = xid; |
728 | ||
729 | if (hdrs->type == OFPT_VENDOR) { | |
2123bc8c | 730 | struct ofp_vendor_header *ovh = buf->header; |
982697a4 | 731 | |
2123bc8c BP |
732 | ovh->vendor = htonl(hdrs->vendor); |
733 | ovh->subtype = htonl(hdrs->subtype); | |
982697a4 BP |
734 | } else if (version == OFP10_VERSION |
735 | && (hdrs->type == OFPT10_STATS_REQUEST || | |
736 | hdrs->type == OFPT10_STATS_REPLY)) { | |
6fd6ed71 | 737 | struct ofp10_stats_msg *osm = buf->header; |
982697a4 BP |
738 | |
739 | osm->type = htons(hdrs->stat); | |
740 | osm->flags = htons(0); | |
741 | ||
742 | if (hdrs->stat == OFPST_VENDOR) { | |
6fd6ed71 | 743 | struct ofp10_vendor_stats_msg *ovsm = buf->header; |
982697a4 BP |
744 | |
745 | ovsm->vendor = htonl(hdrs->vendor); | |
746 | if (hdrs->vendor == NX_VENDOR_ID) { | |
6fd6ed71 | 747 | struct nicira10_stats_msg *nsm = buf->header; |
982697a4 BP |
748 | |
749 | nsm->subtype = htonl(hdrs->subtype); | |
750 | memset(nsm->pad, 0, sizeof nsm->pad); | |
751 | } else { | |
428b2edd | 752 | OVS_NOT_REACHED(); |
982697a4 BP |
753 | } |
754 | } | |
755 | } else if (version != OFP10_VERSION | |
756 | && (hdrs->type == OFPT11_STATS_REQUEST || | |
757 | hdrs->type == OFPT11_STATS_REPLY)) { | |
6fd6ed71 | 758 | struct ofp11_stats_msg *osm = buf->header; |
982697a4 BP |
759 | |
760 | osm->type = htons(hdrs->stat); | |
761 | osm->flags = htons(0); | |
762 | memset(osm->pad, 0, sizeof osm->pad); | |
763 | ||
764 | if (hdrs->stat == OFPST_VENDOR) { | |
6fd6ed71 | 765 | struct ofp11_vendor_stats_msg *ovsm = buf->header; |
982697a4 BP |
766 | |
767 | ovsm->vendor = htonl(hdrs->vendor); | |
2123bc8c | 768 | ovsm->subtype = htonl(hdrs->subtype); |
982697a4 BP |
769 | } |
770 | } | |
771 | } | |
772 | \f | |
773 | /* Returns 'raw''s name. | |
774 | * | |
775 | * The name is the name used for 'raw' in the OpenFlow specification. For | |
776 | * example, ofpraw_get_name(OFPRAW_OFPT10_FEATURES_REPLY) is | |
777 | * "OFPT_FEATURES_REPLY". | |
778 | * | |
779 | * The caller must not modify or free the returned string. */ | |
780 | const char * | |
781 | ofpraw_get_name(enum ofpraw raw) | |
782 | { | |
783 | return raw_info_get(raw)->name; | |
784 | } | |
785 | ||
786 | /* Returns the stats reply that corresponds to 'raw' in the given OpenFlow | |
787 | * 'version'. */ | |
788 | enum ofpraw | |
789 | ofpraw_stats_request_to_reply(enum ofpraw raw, uint8_t version) | |
790 | { | |
791 | const struct raw_info *info = raw_info_get(raw); | |
792 | const struct raw_instance *instance = raw_instance_get(info, version); | |
793 | enum ofpraw reply_raw; | |
794 | struct ofphdrs hdrs; | |
982697a4 BP |
795 | |
796 | hdrs = instance->hdrs; | |
2e3fa633 SH |
797 | switch ((enum ofp_version)hdrs.version) { |
798 | case OFP10_VERSION: | |
cb22974d | 799 | ovs_assert(hdrs.type == OFPT10_STATS_REQUEST); |
982697a4 | 800 | hdrs.type = OFPT10_STATS_REPLY; |
2e3fa633 SH |
801 | break; |
802 | case OFP11_VERSION: | |
803 | case OFP12_VERSION: | |
2e1ae200 | 804 | case OFP13_VERSION: |
c37c0382 | 805 | case OFP14_VERSION: |
42dccab5 | 806 | case OFP15_VERSION: |
cb22974d | 807 | ovs_assert(hdrs.type == OFPT11_STATS_REQUEST); |
982697a4 | 808 | hdrs.type = OFPT11_STATS_REPLY; |
2e3fa633 SH |
809 | break; |
810 | default: | |
428b2edd | 811 | OVS_NOT_REACHED(); |
982697a4 BP |
812 | } |
813 | ||
500db308 | 814 | ovs_assert(!ofpraw_from_ofphdrs(&reply_raw, &hdrs)); |
982697a4 BP |
815 | |
816 | return reply_raw; | |
817 | } | |
818 | \f | |
819 | /* Determines the OFPTYPE_* type of the OpenFlow message at 'oh', which has | |
820 | * length 'oh->length'. (The caller must ensure that 'oh->length' bytes of | |
821 | * data are readable at 'oh'.) On success, returns 0 and stores the type into | |
822 | * '*typep'. On failure, returns an OFPERR_* error code and zeros '*typep'. | |
823 | * | |
824 | * This function checks that 'oh' is a valid length for its particular type of | |
825 | * message, and returns an error if not. */ | |
826 | enum ofperr | |
827 | ofptype_decode(enum ofptype *typep, const struct ofp_header *oh) | |
828 | { | |
829 | enum ofperr error; | |
830 | enum ofpraw raw; | |
831 | ||
832 | error = ofpraw_decode(&raw, oh); | |
833 | *typep = error ? 0 : ofptype_from_ofpraw(raw); | |
834 | return error; | |
835 | } | |
836 | ||
837 | /* Determines the OFPTYPE_* type of the OpenFlow message in 'msg', which starts | |
6fd6ed71 | 838 | * at 'msg->data' and has length 'msg->size' bytes. On success, |
cf3b7538 JR |
839 | * returns 0 and stores the type into '*typep'. On failure, returns an |
840 | * OFPERR_* error code and zeros '*typep'. | |
982697a4 BP |
841 | * |
842 | * This function checks that the message has a valid length for its particular | |
843 | * type of message, and returns an error if not. | |
844 | * | |
845 | * In addition to setting '*typep', this function pulls off the OpenFlow header | |
846 | * (including the stats headers, vendor header, and any subtype header) with | |
77a9bb31 BP |
847 | * ofpbuf_pull(). It also sets 'msg->header' to the start of the OpenFlow |
848 | * header and 'msg->msg' just beyond the headers (that is, to the final value | |
849 | * of msg->data). */ | |
982697a4 BP |
850 | enum ofperr |
851 | ofptype_pull(enum ofptype *typep, struct ofpbuf *buf) | |
852 | { | |
853 | enum ofperr error; | |
854 | enum ofpraw raw; | |
855 | ||
856 | error = ofpraw_pull(&raw, buf); | |
857 | *typep = error ? 0 : ofptype_from_ofpraw(raw); | |
858 | return error; | |
859 | } | |
860 | ||
861 | /* Returns the OFPTYPE_* type that corresponds to 'raw'. | |
862 | * | |
863 | * (This is a one-way trip, because the mapping from ofpraw to ofptype is | |
864 | * many-to-one.) */ | |
865 | enum ofptype | |
866 | ofptype_from_ofpraw(enum ofpraw raw) | |
867 | { | |
868 | return raw_info_get(raw)->type; | |
869 | } | |
64795a0d BP |
870 | |
871 | const char * | |
872 | ofptype_get_name(enum ofptype type) | |
873 | { | |
874 | ovs_assert(type < ARRAY_SIZE(type_names)); | |
875 | return type_names[type]; | |
876 | } | |
982697a4 BP |
877 | \f |
878 | /* Updates the 'length' field of the OpenFlow message in 'buf' to | |
6fd6ed71 | 879 | * 'buf->size'. */ |
982697a4 BP |
880 | void |
881 | ofpmsg_update_length(struct ofpbuf *buf) | |
882 | { | |
883 | struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof *oh); | |
6fd6ed71 | 884 | oh->length = htons(buf->size); |
982697a4 BP |
885 | } |
886 | ||
ea274df9 | 887 | /* Returns just past the OpenFlow header (including the stats headers, vendor |
982697a4 BP |
888 | * header, and any subtype header) in 'oh'. */ |
889 | const void * | |
890 | ofpmsg_body(const struct ofp_header *oh) | |
891 | { | |
892 | struct ofphdrs hdrs; | |
893 | ||
894 | ofphdrs_decode_assert(&hdrs, oh, ntohs(oh->length)); | |
895 | return (const uint8_t *) oh + ofphdrs_len(&hdrs); | |
896 | } | |
76ec08e0 | 897 | |
e428148a | 898 | /* Return if 'oh' is a stat/multipart (OFPST) request message. */ |
76ec08e0 YT |
899 | bool |
900 | ofpmsg_is_stat_request(const struct ofp_header *oh) | |
901 | { | |
902 | return ofp_is_stat_request(oh->version, oh->type); | |
903 | } | |
e428148a BP |
904 | |
905 | /* Return if 'oh' is a stat/multipart (OFPST) reply message. */ | |
906 | bool | |
907 | ofpmsg_is_stat_reply(const struct ofp_header *oh) | |
908 | { | |
909 | return ofp_is_stat_reply(oh->version, oh->type); | |
910 | } | |
911 | ||
912 | /* Return if 'oh' is a stat/multipart (OFPST) request or reply message. */ | |
913 | bool | |
914 | ofpmsg_is_stat(const struct ofp_header *oh) | |
915 | { | |
916 | return ofp_is_stat(oh->version, oh->type); | |
917 | } | |
982697a4 | 918 | \f |
79b8c36c BP |
919 | static ovs_be16 *ofpmp_flags__(const struct ofp_header *); |
920 | ||
982697a4 BP |
921 | /* Initializes 'replies' as a new list of stats messages that reply to |
922 | * 'request', which must be a stats request message. Initially the list will | |
923 | * consist of only a single reply part without any body. The caller should | |
924 | * use calls to the other ofpmp_*() functions to add to the body and split the | |
925 | * message into multiple parts, if necessary. */ | |
926 | void | |
ca6ba700 | 927 | ofpmp_init(struct ovs_list *replies, const struct ofp_header *request) |
982697a4 BP |
928 | { |
929 | struct ofpbuf *msg; | |
930 | ||
417e7e66 | 931 | ovs_list_init(replies); |
982697a4 BP |
932 | |
933 | msg = ofpraw_alloc_stats_reply(request, 1000); | |
417e7e66 | 934 | ovs_list_push_back(replies, &msg->list_node); |
982697a4 BP |
935 | } |
936 | ||
937 | /* Prepares to append up to 'len' bytes to the series of statistics replies in | |
938 | * 'replies', which should have been initialized with ofpmp_init(), if | |
939 | * necessary adding a new reply to the list. | |
940 | * | |
941 | * Returns an ofpbuf with at least 'len' bytes of tailroom. The 'len' bytes | |
942 | * have not actually been allocated, so the caller must do so with | |
943 | * e.g. ofpbuf_put_uninit(). */ | |
944 | struct ofpbuf * | |
ca6ba700 | 945 | ofpmp_reserve(struct ovs_list *replies, size_t len) |
982697a4 | 946 | { |
417e7e66 | 947 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
982697a4 | 948 | |
6fd6ed71 | 949 | if (msg->size + len <= UINT16_MAX) { |
982697a4 BP |
950 | ofpbuf_prealloc_tailroom(msg, len); |
951 | return msg; | |
952 | } else { | |
953 | unsigned int hdrs_len; | |
954 | struct ofpbuf *next; | |
955 | struct ofphdrs hdrs; | |
956 | ||
6fd6ed71 | 957 | ofphdrs_decode_assert(&hdrs, msg->data, msg->size); |
982697a4 BP |
958 | hdrs_len = ofphdrs_len(&hdrs); |
959 | ||
960 | next = ofpbuf_new(MAX(1024, hdrs_len + len)); | |
6fd6ed71 PS |
961 | ofpbuf_put(next, msg->data, hdrs_len); |
962 | next->header = next->data; | |
963 | next->msg = ofpbuf_tail(next); | |
417e7e66 | 964 | ovs_list_push_back(replies, &next->list_node); |
982697a4 | 965 | |
6fd6ed71 | 966 | *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE); |
79b8c36c | 967 | |
982697a4 BP |
968 | return next; |
969 | } | |
970 | } | |
971 | ||
972 | /* Appends 'len' bytes to the series of statistics replies in 'replies', and | |
973 | * returns the first byte. */ | |
974 | void * | |
ca6ba700 | 975 | ofpmp_append(struct ovs_list *replies, size_t len) |
982697a4 BP |
976 | { |
977 | return ofpbuf_put_uninit(ofpmp_reserve(replies, len), len); | |
978 | } | |
979 | ||
980 | /* Sometimes, when composing stats replies, it's difficult to predict how long | |
981 | * an individual reply chunk will be before actually encoding it into the reply | |
982 | * buffer. This function allows easy handling of this case: just encode the | |
983 | * reply, then use this function to break the message into two pieces if it | |
984 | * exceeds the OpenFlow message limit. | |
985 | * | |
986 | * In detail, if the final stats message in 'replies' is too long for OpenFlow, | |
987 | * this function breaks it into two separate stats replies, the first one with | |
988 | * the first 'start_ofs' bytes, the second one containing the bytes from that | |
989 | * offset onward. */ | |
990 | void | |
ca6ba700 | 991 | ofpmp_postappend(struct ovs_list *replies, size_t start_ofs) |
982697a4 | 992 | { |
417e7e66 | 993 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
982697a4 | 994 | |
cb22974d | 995 | ovs_assert(start_ofs <= UINT16_MAX); |
6fd6ed71 PS |
996 | if (msg->size > UINT16_MAX) { |
997 | size_t len = msg->size - start_ofs; | |
982697a4 | 998 | memcpy(ofpmp_append(replies, len), |
6fd6ed71 PS |
999 | (const uint8_t *) msg->data + start_ofs, len); |
1000 | msg->size = start_ofs; | |
982697a4 BP |
1001 | } |
1002 | } | |
1003 | ||
e28ac5cf BP |
1004 | /* Returns the OpenFlow version of the replies being constructed in 'replies', |
1005 | * which should have been initialized by ofpmp_init(). */ | |
1006 | enum ofp_version | |
ca6ba700 | 1007 | ofpmp_version(struct ovs_list *replies) |
e28ac5cf | 1008 | { |
417e7e66 | 1009 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
6fd6ed71 | 1010 | const struct ofp_header *oh = msg->data; |
e28ac5cf BP |
1011 | |
1012 | return oh->version; | |
1013 | } | |
1014 | ||
1015 | /* Determines the OFPRAW_* type of the OpenFlow messages in 'replies', which | |
1016 | * should have been initialized by ofpmp_init(). */ | |
1017 | enum ofpraw | |
ca6ba700 | 1018 | ofpmp_decode_raw(struct ovs_list *replies) |
e28ac5cf | 1019 | { |
417e7e66 | 1020 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
e28ac5cf | 1021 | enum ofpraw raw; |
500db308 | 1022 | ovs_assert(!ofpraw_decode_partial(&raw, msg->data, msg->size)); |
e28ac5cf BP |
1023 | return raw; |
1024 | } | |
1025 | ||
982697a4 BP |
1026 | static ovs_be16 * |
1027 | ofpmp_flags__(const struct ofp_header *oh) | |
1028 | { | |
2e3fa633 SH |
1029 | switch ((enum ofp_version)oh->version) { |
1030 | case OFP10_VERSION: | |
1031 | return &((struct ofp10_stats_msg *) oh)->flags; | |
1032 | case OFP11_VERSION: | |
1033 | case OFP12_VERSION: | |
2e1ae200 | 1034 | case OFP13_VERSION: |
c37c0382 | 1035 | case OFP14_VERSION: |
42dccab5 | 1036 | case OFP15_VERSION: |
2e3fa633 SH |
1037 | return &((struct ofp11_stats_msg *) oh)->flags; |
1038 | default: | |
428b2edd | 1039 | OVS_NOT_REACHED(); |
2e3fa633 | 1040 | } |
982697a4 BP |
1041 | } |
1042 | ||
1043 | /* Returns the OFPSF_* flags found in the OpenFlow stats header of 'oh', which | |
1044 | * must be an OpenFlow stats request or reply. | |
1045 | * | |
1046 | * (OFPSF_REPLY_MORE is the only defined flag.) */ | |
1047 | uint16_t | |
1048 | ofpmp_flags(const struct ofp_header *oh) | |
1049 | { | |
1050 | return ntohs(*ofpmp_flags__(oh)); | |
1051 | } | |
1052 | ||
1053 | /* Returns true if the OFPSF_REPLY_MORE flag is set in the OpenFlow stats | |
1054 | * header of 'oh', which must be an OpenFlow stats request or reply, false if | |
1055 | * it is not set. */ | |
1056 | bool | |
1057 | ofpmp_more(const struct ofp_header *oh) | |
1058 | { | |
1059 | return (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; | |
1060 | } | |
1061 | \f | |
fd4b7a0e BP |
1062 | /* Multipart request assembler. */ |
1063 | ||
1064 | struct ofpmp_partial { | |
1065 | struct hmap_node hmap_node; /* In struct ofpmp_assembler's 'msgs'. */ | |
1066 | ovs_be32 xid; | |
1067 | enum ofpraw raw; | |
1068 | long long int timeout; | |
1069 | struct ovs_list msgs; | |
1070 | size_t size; | |
1071 | bool has_body; | |
1072 | }; | |
1073 | ||
1074 | static uint32_t | |
1075 | hash_xid(ovs_be32 xid) | |
1076 | { | |
1077 | return hash_int((OVS_FORCE uint32_t) xid, 0); | |
1078 | } | |
1079 | ||
1080 | static struct ofpmp_partial * | |
1081 | ofpmp_assembler_find(struct hmap *assembler, ovs_be32 xid) | |
1082 | { | |
1083 | if (hmap_is_empty(assembler)) { | |
1084 | /* Common case. */ | |
1085 | return NULL; | |
1086 | } | |
1087 | ||
1088 | struct ofpmp_partial *p; | |
1089 | HMAP_FOR_EACH_IN_BUCKET (p, hmap_node, hash_xid(xid), assembler) { | |
1090 | if (p->xid == xid) { | |
1091 | return p; | |
1092 | } | |
1093 | } | |
1094 | return NULL; | |
1095 | } | |
1096 | ||
1097 | static void | |
1098 | ofpmp_partial_destroy(struct hmap *assembler, struct ofpmp_partial *p) | |
1099 | { | |
1100 | if (p) { | |
1101 | hmap_remove(assembler, &p->hmap_node); | |
1102 | ofpbuf_list_delete(&p->msgs); | |
1103 | free(p); | |
1104 | } | |
1105 | } | |
1106 | ||
1107 | static struct ofpbuf * | |
1108 | ofpmp_partial_error(struct hmap *assembler, struct ofpmp_partial *p, | |
1109 | enum ofperr error) | |
1110 | { | |
1111 | const struct ofpbuf *head = ofpbuf_from_list(ovs_list_back(&p->msgs)); | |
1112 | const struct ofp_header *oh = head->data; | |
1113 | struct ofpbuf *reply = ofperr_encode_reply(error, oh); | |
1114 | ||
1115 | ofpmp_partial_destroy(assembler, p); | |
1116 | ||
1117 | return reply; | |
1118 | } | |
1119 | ||
1120 | /* Clears out and frees any messages currently being reassembled. Afterward, | |
1121 | * the caller may destroy the hmap, with hmap_destroy(), without risk of | |
1122 | * leaks. */ | |
1123 | void | |
1124 | ofpmp_assembler_clear(struct hmap *assembler) | |
1125 | { | |
1126 | struct ofpmp_partial *p, *next; | |
1127 | HMAP_FOR_EACH_SAFE (p, next, hmap_node, assembler) { | |
1128 | ofpmp_partial_destroy(assembler, p); | |
1129 | } | |
1130 | } | |
1131 | ||
1132 | /* Does periodic maintenance on 'assembler'. If any partially assembled | |
1133 | * requests have timed out, returns an appropriate error message for the caller | |
1134 | * to send to the controller. | |
1135 | * | |
1136 | * 'now' should be the current time as returned by time_msec(). */ | |
1137 | struct ofpbuf * OVS_WARN_UNUSED_RESULT | |
1138 | ofpmp_assembler_run(struct hmap *assembler, long long int now) | |
1139 | { | |
1140 | struct ofpmp_partial *p; | |
1141 | HMAP_FOR_EACH (p, hmap_node, assembler) { | |
1142 | if (now >= p->timeout) { | |
1143 | return ofpmp_partial_error( | |
1144 | assembler, p, OFPERR_OFPBRC_MULTIPART_REQUEST_TIMEOUT); | |
1145 | } | |
1146 | } | |
1147 | return NULL; | |
1148 | } | |
1149 | ||
1150 | /* Returns the time at which the next partially assembled request times out. | |
1151 | * The caller should pass this time to poll_timer_wait_until(). */ | |
1152 | long long int | |
1153 | ofpmp_assembler_wait(struct hmap *assembler) | |
1154 | { | |
1155 | long long int timeout = LLONG_MAX; | |
1156 | ||
1157 | struct ofpmp_partial *p; | |
1158 | HMAP_FOR_EACH (p, hmap_node, assembler) { | |
1159 | timeout = MIN(timeout, p->timeout); | |
1160 | } | |
1161 | ||
1162 | return timeout; | |
1163 | } | |
1164 | ||
1165 | /* Submits 'msg' to 'assembler' for reassembly. | |
1166 | * | |
1167 | * If 'msg' was accepted, returns 0 and initializes 'out' either to an empty | |
1168 | * list (if 'msg' is being held for reassembly) or to a list of one or more | |
1169 | * reassembled messages. The reassembler takes ownership of 'msg'; the caller | |
1170 | * takes ownership of the messages in 'out'. | |
1171 | * | |
1172 | * If 'msg' was rejected, returns an OpenFlow error that the caller should | |
1173 | * reply to the caller and initializes 'out' as empty. The caller retains | |
1174 | * ownership of 'msg'. | |
1175 | * | |
1176 | * 'now' should be the current time as returned by time_msec(). */ | |
1177 | enum ofperr | |
1178 | ofpmp_assembler_execute(struct hmap *assembler, struct ofpbuf *msg, | |
1179 | struct ovs_list *out, long long int now) | |
1180 | { | |
1181 | ovs_list_init(out); | |
1182 | ||
1183 | /* If the message is not a multipart request, pass it along without further | |
1184 | * inspection. | |
1185 | * | |
1186 | * We could also do this kind of early-out for multipart requests that have | |
1187 | * only a single piece, or for pre-OF1.3 multipart requests (since only | |
1188 | * OF1.3 introduced multipart requests with more than one piece), but we | |
1189 | * don't because this allows us to assure code that runs after us that | |
1190 | * invariants checked below on correct message lengths are always | |
1191 | * satisfied, even if there's only a single piece. */ | |
1192 | struct ofp_header *oh = msg->data; | |
1193 | if (!ofpmsg_is_stat_request(oh)) { | |
1194 | ovs_list_push_back(out, &msg->list_node); | |
1195 | return 0; | |
1196 | } | |
1197 | ||
1198 | /* Decode the multipart request. */ | |
1199 | struct ofphdrs hdrs; | |
1200 | enum ofperr error = ofphdrs_decode(&hdrs, msg->data, msg->size); | |
1201 | if (error) { | |
1202 | return error; | |
1203 | } | |
1204 | ||
1205 | enum ofpraw raw; | |
1206 | error = ofpraw_from_ofphdrs(&raw, &hdrs); | |
1207 | if (error) { | |
1208 | return error; | |
1209 | } | |
1210 | ||
1211 | /* If the message has a nonempty body, check that it is a valid length. | |
1212 | * | |
1213 | * The OpenFlow spec says that pieces with empty bodies are allowed | |
1214 | * anywhere in a multipart sequence, so for now we allow such messages even | |
1215 | * if the overall multipart request requires a body. */ | |
1216 | const struct raw_info *info = raw_info_get(raw); | |
1217 | const struct raw_instance *instance = raw_instance_get(info, hdrs.version); | |
1218 | unsigned int min_len = ofphdrs_len(&hdrs); | |
1219 | bool has_body = msg->size > min_len; | |
1220 | if (has_body) { | |
1221 | error = ofpraw_check_length(info, instance, msg->size); | |
1222 | if (error) { | |
1223 | return error; | |
1224 | } | |
1225 | } | |
1226 | ||
1227 | /* Find or create an ofpmp_partial record. */ | |
1228 | struct ofpmp_partial *p = ofpmp_assembler_find(assembler, oh->xid); | |
1229 | if (!p) { | |
1230 | p = xzalloc(sizeof *p); | |
1231 | hmap_insert(assembler, &p->hmap_node, hash_xid(oh->xid)); | |
1232 | p->xid = oh->xid; | |
1233 | ovs_list_init(&p->msgs); | |
1234 | p->raw = raw; | |
1235 | } | |
1236 | p->timeout = now + 1000; | |
1237 | ||
1238 | /* Check that the type is the same as any previous messages in this | |
1239 | * sequence. */ | |
1240 | if (p->raw != raw) { | |
1241 | ofpmp_partial_destroy(assembler, p); | |
1242 | return OFPERR_OFPBRC_BAD_STAT; | |
1243 | } | |
1244 | ||
1245 | /* Limit the size of a multipart sequence. | |
1246 | * | |
1247 | * (Table features requests can actually be over 1 MB.) */ | |
1248 | p->size += msg->size; | |
1249 | if (p->size > 4 * 1024 * 1024) { | |
1250 | ofpmp_partial_destroy(assembler, p); | |
1251 | return OFPERR_OFPBRC_MULTIPART_BUFFER_OVERFLOW; | |
1252 | } | |
1253 | ||
1254 | /* If a multipart request type requires a body, ensure that at least one of | |
1255 | * the pieces in a multipart request has one. */ | |
1256 | bool more = oh->version >= OFP13_VERSION && ofpmp_more(oh); | |
1257 | if (has_body) { | |
1258 | p->has_body = true; | |
1259 | } | |
1260 | if (!more && !p->has_body && info->min_body) { | |
1261 | ofpmp_partial_destroy(assembler, p); | |
1262 | return OFPERR_OFPBRC_BAD_LEN; | |
1263 | } | |
1264 | ||
1265 | /* Append the part to the list. | |
1266 | * | |
1267 | * If there are more pieces to come, we're done for now. */ | |
1268 | ovs_list_push_back(&p->msgs, &msg->list_node); | |
1269 | if (more) { | |
1270 | return 0; | |
1271 | } | |
1272 | ||
1273 | /* This multipart request is complete. Move the messages from 'p' to 'out' | |
1274 | * and discard 'p'. */ | |
1275 | ovs_list_move(out, &p->msgs); | |
1276 | ovs_list_init(&p->msgs); | |
1277 | ofpmp_partial_destroy(assembler, p); | |
1278 | ||
1279 | /* Delete pieces with empty bodies from 'out' (but leave at least one | |
1280 | * piece). | |
1281 | * | |
1282 | * Most types of multipart requests have fixed-size bodies. For example, | |
1283 | * OFPMP_PORT_DESCRIPTION has an 8-byte body. Thus, it doesn't really make | |
1284 | * sense for a controller to use multiple pieces for these messages, and | |
1285 | * it's simpler to implement OVS as if they weren't really multipart. | |
1286 | * | |
1287 | * However, the OpenFlow spec says that messages with empty bodies are | |
1288 | * allowed anywhere in a multipart sequence, so in theory a controller | |
1289 | * could send an OFPMP_PORT_DESCRIPTION with an 8-byte body bracketed | |
1290 | * on either side by parts with 0-byte bodies. We remove the 0-byte | |
1291 | * ones here to simplify processing later. | |
1292 | */ | |
1293 | struct ofpbuf *b, *next; | |
1294 | LIST_FOR_EACH_SAFE (b, next, list_node, out) { | |
1295 | if (b->size <= min_len && !ovs_list_is_short(out)) { | |
1296 | ovs_list_remove(&b->list_node); | |
1297 | ofpbuf_delete(b); | |
1298 | } | |
1299 | } | |
1300 | return 0; | |
1301 | } | |
1302 | \f | |
982697a4 BP |
1303 | static void ofpmsgs_init(void); |
1304 | ||
1305 | static const struct raw_info * | |
1306 | raw_info_get(enum ofpraw raw) | |
1307 | { | |
1308 | ofpmsgs_init(); | |
1309 | ||
cb22974d | 1310 | ovs_assert(raw < ARRAY_SIZE(raw_infos)); |
982697a4 BP |
1311 | return &raw_infos[raw]; |
1312 | } | |
1313 | ||
1314 | static struct raw_instance * | |
1315 | raw_instance_get(const struct raw_info *info, uint8_t version) | |
1316 | { | |
cb22974d | 1317 | ovs_assert(version >= info->min_version && version <= info->max_version); |
982697a4 BP |
1318 | return &info->instances[version - info->min_version]; |
1319 | } | |
1320 | ||
1321 | static enum ofperr | |
1322 | ofpraw_from_ofphdrs(enum ofpraw *raw, const struct ofphdrs *hdrs) | |
1323 | { | |
1324 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); | |
1325 | ||
1326 | struct raw_instance *raw_hdrs; | |
1327 | uint32_t hash; | |
1328 | ||
1329 | ofpmsgs_init(); | |
1330 | ||
1331 | hash = ofphdrs_hash(hdrs); | |
1332 | HMAP_FOR_EACH_WITH_HASH (raw_hdrs, hmap_node, hash, &raw_instance_map) { | |
1333 | if (ofphdrs_equal(hdrs, &raw_hdrs->hdrs)) { | |
1334 | *raw = raw_hdrs->raw; | |
1335 | return 0; | |
1336 | } | |
1337 | } | |
1338 | ||
1339 | if (!VLOG_DROP_WARN(&rl)) { | |
1340 | struct ds s; | |
1341 | ||
1342 | ds_init(&s); | |
1343 | ds_put_format(&s, "version %"PRIu8", type %"PRIu8, | |
1344 | hdrs->version, hdrs->type); | |
1345 | if (ofphdrs_is_stat(hdrs)) { | |
1346 | ds_put_format(&s, ", stat %"PRIu16, hdrs->stat); | |
1347 | } | |
1348 | if (hdrs->vendor) { | |
1349 | ds_put_format(&s, ", vendor 0x%"PRIx32", subtype %"PRIu32, | |
1350 | hdrs->vendor, hdrs->subtype); | |
1351 | } | |
1352 | VLOG_WARN("unknown OpenFlow message (%s)", ds_cstr(&s)); | |
1353 | ds_destroy(&s); | |
1354 | } | |
1355 | ||
1356 | return (hdrs->vendor ? OFPERR_OFPBRC_BAD_SUBTYPE | |
1357 | : ofphdrs_is_stat(hdrs) ? OFPERR_OFPBRC_BAD_STAT | |
1358 | : OFPERR_OFPBRC_BAD_TYPE); | |
1359 | } | |
1360 | ||
1361 | static void | |
1362 | ofpmsgs_init(void) | |
1363 | { | |
06717cbd | 1364 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
982697a4 BP |
1365 | const struct raw_info *info; |
1366 | ||
06717cbd | 1367 | if (!ovsthread_once_start(&once)) { |
982697a4 BP |
1368 | return; |
1369 | } | |
1370 | ||
1371 | hmap_init(&raw_instance_map); | |
1372 | for (info = raw_infos; info < &raw_infos[ARRAY_SIZE(raw_infos)]; info++) | |
1373 | { | |
1374 | int n_instances = info->max_version - info->min_version + 1; | |
1375 | struct raw_instance *inst; | |
1376 | ||
1377 | for (inst = info->instances; | |
1378 | inst < &info->instances[n_instances]; | |
1379 | inst++) { | |
1380 | inst->hdrs_len = ofphdrs_len(&inst->hdrs); | |
1381 | hmap_insert(&raw_instance_map, &inst->hmap_node, | |
1382 | ofphdrs_hash(&inst->hdrs)); | |
1383 | } | |
1384 | } | |
06717cbd BP |
1385 | |
1386 | ovsthread_once_done(&once); | |
982697a4 | 1387 | } |