/src/openvswitch/lib/ofp-msgs.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2012, 2013, 2014, 2015, 2016 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 "byte-order.h" |
19 | | #include "hash.h" |
20 | | #include "openvswitch/hmap.h" |
21 | | #include "openflow/nicira-ext.h" |
22 | | #include "openflow/openflow.h" |
23 | | #include "openvswitch/dynamic-string.h" |
24 | | #include "openvswitch/ofp-msgs.h" |
25 | | #include "openvswitch/ofpbuf.h" |
26 | | #include "openvswitch/vlog.h" |
27 | | #include "ovs-thread.h" |
28 | | #include "util.h" |
29 | | |
30 | | VLOG_DEFINE_THIS_MODULE(ofp_msgs); |
31 | | |
32 | 0 | #define OFPT_VENDOR 4 |
33 | 0 | #define OFPT10_STATS_REQUEST 16 |
34 | 0 | #define OFPT10_STATS_REPLY 17 |
35 | 0 | #define OFPT11_STATS_REQUEST 18 |
36 | 0 | #define OFPT11_STATS_REPLY 19 |
37 | 0 | #define OFPST_VENDOR 0xffff |
38 | | |
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 | | |
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 | | |
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); |
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 | | |
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; /* max_version - min_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 | | |
182 | | /* Returns a transaction ID to use for an outgoing OpenFlow message. */ |
183 | | static ovs_be32 |
184 | | alloc_xid(void) |
185 | 0 | { |
186 | 0 | static atomic_count next_xid = ATOMIC_COUNT_INIT(1); |
187 | |
|
188 | 0 | return htonl(atomic_count_inc(&next_xid)); |
189 | 0 | } |
190 | | |
191 | | static uint32_t |
192 | | ofphdrs_hash(const struct ofphdrs *hdrs) |
193 | 0 | { |
194 | 0 | BUILD_ASSERT_DECL(sizeof *hdrs % 4 == 0); |
195 | 0 | return hash_bytes32((const uint32_t *) hdrs, sizeof *hdrs, 0); |
196 | 0 | } |
197 | | |
198 | | static bool |
199 | | ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b) |
200 | 0 | { |
201 | 0 | return !memcmp(a, b, sizeof *a); |
202 | 0 | } |
203 | | |
204 | | static void |
205 | | log_bad_vendor(uint32_t vendor) |
206 | 0 | { |
207 | 0 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); |
208 | |
|
209 | 0 | VLOG_WARN_RL(&rl, "OpenFlow message has unknown vendor %#"PRIx32, vendor); |
210 | 0 | } |
211 | | |
212 | | static enum ofperr |
213 | | ofphdrs_decode(struct ofphdrs *hdrs, |
214 | | const struct ofp_header *oh, size_t length) |
215 | 0 | { |
216 | 0 | memset(hdrs, 0, sizeof *hdrs); |
217 | 0 | if (length < sizeof *oh) { |
218 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
219 | 0 | } |
220 | | |
221 | | /* Get base message version and type (OFPT_*). */ |
222 | 0 | hdrs->version = oh->version; |
223 | 0 | hdrs->type = oh->type; |
224 | |
|
225 | 0 | if (hdrs->type == OFPT_VENDOR) { |
226 | | /* Get vendor. */ |
227 | 0 | const struct ofp_vendor_header *ovh; |
228 | |
|
229 | 0 | if (length < sizeof *ovh) { |
230 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
231 | 0 | } |
232 | | |
233 | 0 | ovh = (const struct ofp_vendor_header *) oh; |
234 | 0 | hdrs->vendor = ntohl(ovh->vendor); |
235 | 0 | if (hdrs->vendor == NX_VENDOR_ID || hdrs->vendor == ONF_VENDOR_ID) { |
236 | 0 | hdrs->subtype = ntohl(ovh->subtype); |
237 | 0 | } else { |
238 | 0 | log_bad_vendor(hdrs->vendor); |
239 | 0 | return OFPERR_OFPBRC_BAD_VENDOR; |
240 | 0 | } |
241 | 0 | } else if (hdrs->version == OFP10_VERSION |
242 | 0 | && (hdrs->type == OFPT10_STATS_REQUEST || |
243 | 0 | hdrs->type == OFPT10_STATS_REPLY)) { |
244 | 0 | const struct ofp10_stats_msg *osm; |
245 | | |
246 | | /* Get statistic type (OFPST_*). */ |
247 | 0 | if (length < sizeof *osm) { |
248 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
249 | 0 | } |
250 | 0 | osm = (const struct ofp10_stats_msg *) oh; |
251 | 0 | hdrs->stat = ntohs(osm->type); |
252 | |
|
253 | 0 | if (hdrs->stat == OFPST_VENDOR) { |
254 | | /* Get vendor. */ |
255 | 0 | const struct ofp10_vendor_stats_msg *ovsm; |
256 | |
|
257 | 0 | if (length < sizeof *ovsm) { |
258 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
259 | 0 | } |
260 | | |
261 | 0 | ovsm = (const struct ofp10_vendor_stats_msg *) oh; |
262 | 0 | hdrs->vendor = ntohl(ovsm->vendor); |
263 | 0 | if (hdrs->vendor == NX_VENDOR_ID) { |
264 | | /* Get Nicira statistic type (NXST_*). */ |
265 | 0 | const struct nicira10_stats_msg *nsm; |
266 | |
|
267 | 0 | if (length < sizeof *nsm) { |
268 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
269 | 0 | } |
270 | 0 | nsm = (const struct nicira10_stats_msg *) oh; |
271 | 0 | hdrs->subtype = ntohl(nsm->subtype); |
272 | 0 | } else { |
273 | 0 | log_bad_vendor(hdrs->vendor); |
274 | 0 | return OFPERR_OFPBRC_BAD_VENDOR; |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } else if (hdrs->version != OFP10_VERSION |
278 | 0 | && (hdrs->type == OFPT11_STATS_REQUEST || |
279 | 0 | hdrs->type == OFPT11_STATS_REPLY)) { |
280 | 0 | const struct ofp11_stats_msg *osm; |
281 | | |
282 | | /* Get statistic type (OFPST_*). */ |
283 | 0 | if (length < sizeof *osm) { |
284 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
285 | 0 | } |
286 | 0 | osm = (const struct ofp11_stats_msg *) oh; |
287 | 0 | hdrs->stat = ntohs(osm->type); |
288 | |
|
289 | 0 | if (hdrs->stat == OFPST_VENDOR) { |
290 | | /* Get vendor. */ |
291 | 0 | const struct ofp11_vendor_stats_msg *ovsm; |
292 | |
|
293 | 0 | if (length < sizeof *ovsm) { |
294 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
295 | 0 | } |
296 | | |
297 | 0 | ovsm = (const struct ofp11_vendor_stats_msg *) oh; |
298 | 0 | hdrs->vendor = ntohl(ovsm->vendor); |
299 | 0 | if (hdrs->vendor == NX_VENDOR_ID || |
300 | 0 | hdrs->vendor == ONF_VENDOR_ID) { |
301 | 0 | hdrs->subtype = ntohl(ovsm->subtype); |
302 | 0 | } else { |
303 | 0 | log_bad_vendor(hdrs->vendor); |
304 | 0 | return OFPERR_OFPBRC_BAD_VENDOR; |
305 | 0 | } |
306 | 0 | } |
307 | 0 | } |
308 | | |
309 | 0 | return 0; |
310 | 0 | } |
311 | | |
312 | | static void |
313 | | ofphdrs_decode_assert(struct ofphdrs *hdrs, |
314 | | const struct ofp_header *oh, size_t length) |
315 | 0 | { |
316 | 0 | ovs_assert(!ofphdrs_decode(hdrs, oh, length)); |
317 | 0 | } |
318 | | |
319 | | static bool |
320 | | ofp_is_stat_request(enum ofp_version version, uint8_t type) |
321 | 0 | { |
322 | 0 | switch (version) { |
323 | 0 | case OFP10_VERSION: |
324 | 0 | return type == OFPT10_STATS_REQUEST; |
325 | 0 | case OFP11_VERSION: |
326 | 0 | case OFP12_VERSION: |
327 | 0 | case OFP13_VERSION: |
328 | 0 | case OFP14_VERSION: |
329 | 0 | case OFP15_VERSION: |
330 | 0 | return type == OFPT11_STATS_REQUEST; |
331 | 0 | } |
332 | | |
333 | 0 | return false; |
334 | 0 | } |
335 | | |
336 | | static bool |
337 | | ofp_is_stat_reply(enum ofp_version version, uint8_t type) |
338 | 0 | { |
339 | 0 | switch (version) { |
340 | 0 | case OFP10_VERSION: |
341 | 0 | return type == OFPT10_STATS_REPLY; |
342 | 0 | case OFP11_VERSION: |
343 | 0 | case OFP12_VERSION: |
344 | 0 | case OFP13_VERSION: |
345 | 0 | case OFP14_VERSION: |
346 | 0 | case OFP15_VERSION: |
347 | 0 | return type == OFPT11_STATS_REPLY; |
348 | 0 | } |
349 | | |
350 | 0 | return false; |
351 | 0 | } |
352 | | |
353 | | static bool |
354 | | ofp_is_stat(enum ofp_version version, uint8_t type) |
355 | 0 | { |
356 | 0 | return (ofp_is_stat_request(version, type) || |
357 | 0 | ofp_is_stat_reply(version, type)); |
358 | 0 | } |
359 | | |
360 | | static bool |
361 | | ofphdrs_is_stat(const struct ofphdrs *hdrs) |
362 | 0 | { |
363 | 0 | return ofp_is_stat(hdrs->version, hdrs->type); |
364 | 0 | } |
365 | | |
366 | | size_t |
367 | | ofphdrs_len(const struct ofphdrs *hdrs) |
368 | 0 | { |
369 | 0 | if (hdrs->type == OFPT_VENDOR) { |
370 | 0 | return sizeof(struct ofp_vendor_header); |
371 | 0 | } |
372 | | |
373 | 0 | switch ((enum ofp_version) hdrs->version) { |
374 | 0 | case OFP10_VERSION: |
375 | 0 | if (hdrs->type == OFPT10_STATS_REQUEST || |
376 | 0 | hdrs->type == OFPT10_STATS_REPLY) { |
377 | 0 | return (hdrs->stat == OFPST_VENDOR |
378 | 0 | ? sizeof(struct nicira10_stats_msg) |
379 | 0 | : sizeof(struct ofp10_stats_msg)); |
380 | 0 | } |
381 | 0 | break; |
382 | | |
383 | 0 | case OFP11_VERSION: |
384 | 0 | case OFP12_VERSION: |
385 | 0 | case OFP13_VERSION: |
386 | 0 | case OFP14_VERSION: |
387 | 0 | case OFP15_VERSION: |
388 | 0 | if (hdrs->type == OFPT11_STATS_REQUEST || |
389 | 0 | hdrs->type == OFPT11_STATS_REPLY) { |
390 | 0 | return (hdrs->stat == OFPST_VENDOR |
391 | 0 | ? sizeof(struct ofp11_vendor_stats_msg) |
392 | 0 | : sizeof(struct ofp11_stats_msg)); |
393 | 0 | } |
394 | 0 | break; |
395 | 0 | } |
396 | | |
397 | 0 | return sizeof(struct ofp_header); |
398 | 0 | } |
399 | | |
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 | 0 | { |
410 | 0 | struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
411 | 0 | return ofpraw_pull(raw, &msg); |
412 | 0 | } |
413 | | |
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 | 0 | { |
423 | 0 | enum ofpraw raw; |
424 | 0 | ovs_assert(!ofpraw_decode(&raw, oh)); |
425 | 0 | return raw; |
426 | 0 | } |
427 | | |
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) |
434 | 0 | { |
435 | 0 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); |
436 | |
|
437 | 0 | unsigned int min_len = instance->hdrs_len + info->min_body; |
438 | 0 | switch (info->extra_multiple) { |
439 | 0 | case 0: |
440 | 0 | if (len != min_len) { |
441 | 0 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected " |
442 | 0 | "length %u)", info->name, len, min_len); |
443 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
444 | 0 | } |
445 | 0 | break; |
446 | | |
447 | 0 | case 1: |
448 | 0 | if (len < min_len) { |
449 | 0 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected " |
450 | 0 | "length at least %u bytes)", |
451 | 0 | info->name, len, min_len); |
452 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
453 | 0 | } |
454 | 0 | break; |
455 | | |
456 | 0 | default: |
457 | 0 | if (len < min_len || (len - min_len) % info->extra_multiple) { |
458 | 0 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (must be " |
459 | 0 | "exactly %u bytes or longer by an integer multiple " |
460 | 0 | "of %u bytes)", |
461 | 0 | info->name, len, min_len, info->extra_multiple); |
462 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
463 | 0 | } |
464 | 0 | break; |
465 | 0 | } |
466 | | |
467 | 0 | return 0; |
468 | 0 | } |
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 | 0 | { |
486 | | /* Set default outputs. */ |
487 | 0 | msg->header = msg->data; |
488 | 0 | msg->msg = msg->header; |
489 | 0 | *rawp = 0; |
490 | |
|
491 | 0 | struct ofphdrs hdrs; |
492 | 0 | enum ofperr error = ofphdrs_decode(&hdrs, msg->data, msg->size); |
493 | 0 | if (error) { |
494 | 0 | return error; |
495 | 0 | } |
496 | | |
497 | 0 | enum ofpraw raw; |
498 | 0 | error = ofpraw_from_ofphdrs(&raw, &hdrs); |
499 | 0 | if (error) { |
500 | 0 | return error; |
501 | 0 | } |
502 | | |
503 | 0 | const struct raw_info *info = raw_info_get(raw); |
504 | 0 | const struct raw_instance *instance = raw_instance_get(info, hdrs.version); |
505 | 0 | error = ofpraw_check_length(info, instance, msg->size); |
506 | 0 | if (error) { |
507 | 0 | return error; |
508 | 0 | } |
509 | | |
510 | 0 | msg->header = ofpbuf_pull(msg, instance->hdrs_len); |
511 | 0 | msg->msg = msg->data; |
512 | 0 | *rawp = raw; |
513 | 0 | return 0; |
514 | 0 | } |
515 | | |
516 | | /* Does the same job as ofpraw_pull(), except that it assert-fails if |
517 | | * ofpraw_pull() would have reported an error. Thus, it's able to use the |
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 |
521 | | * ofpraw_decode() on the message and thus know that it's OK.) */ |
522 | | enum ofpraw |
523 | | ofpraw_pull_assert(struct ofpbuf *msg) |
524 | 0 | { |
525 | 0 | enum ofpraw raw; |
526 | 0 | ovs_assert(!ofpraw_pull(&raw, msg)); |
527 | 0 | return raw; |
528 | 0 | } |
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 | 0 | { |
544 | 0 | struct ofphdrs hdrs; |
545 | 0 | enum ofperr error; |
546 | |
|
547 | 0 | error = ofphdrs_decode(&hdrs, oh, length); |
548 | 0 | if (!error) { |
549 | 0 | error = ofpraw_from_ofphdrs(raw, &hdrs); |
550 | 0 | } |
551 | |
|
552 | 0 | if (error) { |
553 | 0 | *raw = 0; |
554 | 0 | } |
555 | 0 | return error; |
556 | 0 | } |
557 | | |
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 | | * |
571 | | * In the returned ofpbuf, 'header' points to the beginning of the |
572 | | * OpenFlow header and 'msg' points just after it, to where the |
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(). |
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 | 0 | { |
581 | 0 | return ofpraw_alloc_xid(raw, version, alloc_xid(), extra_tailroom); |
582 | 0 | } |
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 | 0 | { |
589 | 0 | struct ofpbuf *buf = ofpbuf_new(0); |
590 | 0 | ofpraw_put__(raw, version, xid, extra_tailroom, buf); |
591 | 0 | return buf; |
592 | 0 | } |
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 | 0 | { |
604 | 0 | return ofpraw_alloc_xid(raw, request->version, request->xid, |
605 | 0 | extra_tailroom); |
606 | 0 | } |
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 | | * |
618 | | * In the returned ofpbuf, 'header' points to the beginning of the |
619 | | * OpenFlow header and 'msg' points just after it, to where the |
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(). |
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 | 0 | { |
629 | 0 | enum ofpraw request_raw; |
630 | 0 | enum ofpraw reply_raw; |
631 | |
|
632 | 0 | ovs_assert(!ofpraw_decode_partial(&request_raw, request, |
633 | 0 | ntohs(request->length))); |
634 | |
|
635 | 0 | reply_raw = ofpraw_stats_request_to_reply(request_raw, request->version); |
636 | 0 | ovs_assert(reply_raw); |
637 | |
|
638 | 0 | return ofpraw_alloc_reply(reply_raw, request, extra_tailroom); |
639 | 0 | } |
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 | | * |
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, |
652 | | * e.g. with ofpbuf_put_uninit(). */ |
653 | | void |
654 | | ofpraw_put(enum ofpraw raw, uint8_t version, struct ofpbuf *buf) |
655 | 0 | { |
656 | 0 | ofpraw_put__(raw, version, alloc_xid(), 0, buf); |
657 | 0 | } |
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 | 0 | { |
664 | 0 | ofpraw_put__(raw, version, xid, 0, buf); |
665 | 0 | } |
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 | 0 | { |
677 | 0 | ofpraw_put__(raw, request->version, request->xid, 0, buf); |
678 | 0 | } |
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 | | * |
689 | | * In the returned ofpbuf, 'header' points to the beginning of the |
690 | | * OpenFlow header and 'msg' points just after it, to where the |
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(). |
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 | 0 | { |
699 | 0 | enum ofpraw raw; |
700 | |
|
701 | 0 | ovs_assert(!ofpraw_decode_partial(&raw, request, ntohs(request->length))); |
702 | |
|
703 | 0 | raw = ofpraw_stats_request_to_reply(raw, request->version); |
704 | 0 | ovs_assert(raw); |
705 | |
|
706 | 0 | ofpraw_put__(raw, request->version, request->xid, 0, buf); |
707 | 0 | } |
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 | 0 | { |
713 | 0 | const struct raw_info *info = raw_info_get(raw); |
714 | 0 | const struct raw_instance *instance = raw_instance_get(info, version); |
715 | 0 | const struct ofphdrs *hdrs = &instance->hdrs; |
716 | 0 | struct ofp_header *oh; |
717 | |
|
718 | 0 | ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body |
719 | 0 | + extra_tailroom)); |
720 | 0 | buf->header = ofpbuf_put_uninit(buf, instance->hdrs_len); |
721 | 0 | buf->msg = ofpbuf_tail(buf); |
722 | |
|
723 | 0 | oh = buf->header; |
724 | 0 | oh->version = version; |
725 | 0 | oh->type = hdrs->type; |
726 | 0 | oh->length = htons(buf->size); |
727 | 0 | oh->xid = xid; |
728 | |
|
729 | 0 | if (hdrs->type == OFPT_VENDOR) { |
730 | 0 | struct ofp_vendor_header *ovh = buf->header; |
731 | |
|
732 | 0 | ovh->vendor = htonl(hdrs->vendor); |
733 | 0 | ovh->subtype = htonl(hdrs->subtype); |
734 | 0 | } else if (version == OFP10_VERSION |
735 | 0 | && (hdrs->type == OFPT10_STATS_REQUEST || |
736 | 0 | hdrs->type == OFPT10_STATS_REPLY)) { |
737 | 0 | struct ofp10_stats_msg *osm = buf->header; |
738 | |
|
739 | 0 | osm->type = htons(hdrs->stat); |
740 | 0 | osm->flags = htons(0); |
741 | |
|
742 | 0 | if (hdrs->stat == OFPST_VENDOR) { |
743 | 0 | struct ofp10_vendor_stats_msg *ovsm = buf->header; |
744 | |
|
745 | 0 | ovsm->vendor = htonl(hdrs->vendor); |
746 | 0 | if (hdrs->vendor == NX_VENDOR_ID) { |
747 | 0 | struct nicira10_stats_msg *nsm = buf->header; |
748 | |
|
749 | 0 | nsm->subtype = htonl(hdrs->subtype); |
750 | 0 | memset(nsm->pad, 0, sizeof nsm->pad); |
751 | 0 | } else { |
752 | 0 | OVS_NOT_REACHED(); |
753 | 0 | } |
754 | 0 | } |
755 | 0 | } else if (version != OFP10_VERSION |
756 | 0 | && (hdrs->type == OFPT11_STATS_REQUEST || |
757 | 0 | hdrs->type == OFPT11_STATS_REPLY)) { |
758 | 0 | struct ofp11_stats_msg *osm = buf->header; |
759 | |
|
760 | 0 | osm->type = htons(hdrs->stat); |
761 | 0 | osm->flags = htons(0); |
762 | 0 | memset(osm->pad, 0, sizeof osm->pad); |
763 | |
|
764 | 0 | if (hdrs->stat == OFPST_VENDOR) { |
765 | 0 | struct ofp11_vendor_stats_msg *ovsm = buf->header; |
766 | |
|
767 | 0 | ovsm->vendor = htonl(hdrs->vendor); |
768 | 0 | ovsm->subtype = htonl(hdrs->subtype); |
769 | 0 | } |
770 | 0 | } |
771 | 0 | } |
772 | | |
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 | 0 | { |
783 | 0 | return raw_info_get(raw)->name; |
784 | 0 | } |
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 | 0 | { |
791 | 0 | const struct raw_info *info = raw_info_get(raw); |
792 | 0 | const struct raw_instance *instance = raw_instance_get(info, version); |
793 | 0 | enum ofpraw reply_raw; |
794 | 0 | struct ofphdrs hdrs; |
795 | |
|
796 | 0 | hdrs = instance->hdrs; |
797 | 0 | switch ((enum ofp_version)hdrs.version) { |
798 | 0 | case OFP10_VERSION: |
799 | 0 | ovs_assert(hdrs.type == OFPT10_STATS_REQUEST); |
800 | 0 | hdrs.type = OFPT10_STATS_REPLY; |
801 | 0 | break; |
802 | 0 | case OFP11_VERSION: |
803 | 0 | case OFP12_VERSION: |
804 | 0 | case OFP13_VERSION: |
805 | 0 | case OFP14_VERSION: |
806 | 0 | case OFP15_VERSION: |
807 | 0 | ovs_assert(hdrs.type == OFPT11_STATS_REQUEST); |
808 | 0 | hdrs.type = OFPT11_STATS_REPLY; |
809 | 0 | break; |
810 | 0 | default: |
811 | 0 | OVS_NOT_REACHED(); |
812 | 0 | } |
813 | | |
814 | 0 | ovs_assert(!ofpraw_from_ofphdrs(&reply_raw, &hdrs)); |
815 | |
|
816 | 0 | return reply_raw; |
817 | 0 | } |
818 | | |
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 | 0 | { |
829 | 0 | enum ofperr error; |
830 | 0 | enum ofpraw raw; |
831 | |
|
832 | 0 | error = ofpraw_decode(&raw, oh); |
833 | 0 | *typep = error ? 0 : ofptype_from_ofpraw(raw); |
834 | 0 | return error; |
835 | 0 | } |
836 | | |
837 | | /* Determines the OFPTYPE_* type of the OpenFlow message in 'msg', which starts |
838 | | * at 'msg->data' and has length 'msg->size' bytes. On success, |
839 | | * returns 0 and stores the type into '*typep'. On failure, returns an |
840 | | * OFPERR_* error code and zeros '*typep'. |
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 |
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). */ |
850 | | enum ofperr |
851 | | ofptype_pull(enum ofptype *typep, struct ofpbuf *buf) |
852 | 0 | { |
853 | 0 | enum ofperr error; |
854 | 0 | enum ofpraw raw; |
855 | |
|
856 | 0 | error = ofpraw_pull(&raw, buf); |
857 | 0 | *typep = error ? 0 : ofptype_from_ofpraw(raw); |
858 | 0 | return error; |
859 | 0 | } |
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 | 0 | { |
868 | 0 | return raw_info_get(raw)->type; |
869 | 0 | } |
870 | | |
871 | | const char * |
872 | | ofptype_get_name(enum ofptype type) |
873 | 0 | { |
874 | 0 | ovs_assert(type < ARRAY_SIZE(type_names)); |
875 | 0 | return type_names[type]; |
876 | 0 | } |
877 | | |
878 | | /* Updates the 'length' field of the OpenFlow message in 'buf' to |
879 | | * 'buf->size'. */ |
880 | | void |
881 | | ofpmsg_update_length(struct ofpbuf *buf) |
882 | 0 | { |
883 | 0 | struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof *oh); |
884 | 0 | oh->length = htons(buf->size); |
885 | 0 | } |
886 | | |
887 | | /* Returns just past the OpenFlow header (including the stats headers, vendor |
888 | | * header, and any subtype header) in 'oh'. */ |
889 | | const void * |
890 | | ofpmsg_body(const struct ofp_header *oh) |
891 | 0 | { |
892 | 0 | struct ofphdrs hdrs; |
893 | |
|
894 | 0 | ofphdrs_decode_assert(&hdrs, oh, ntohs(oh->length)); |
895 | 0 | return (const uint8_t *) oh + ofphdrs_len(&hdrs); |
896 | 0 | } |
897 | | |
898 | | /* Return if 'oh' is a stat/multipart (OFPST) request message. */ |
899 | | bool |
900 | | ofpmsg_is_stat_request(const struct ofp_header *oh) |
901 | 0 | { |
902 | 0 | return ofp_is_stat_request(oh->version, oh->type); |
903 | 0 | } |
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 | 0 | { |
909 | 0 | return ofp_is_stat_reply(oh->version, oh->type); |
910 | 0 | } |
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 | 0 | { |
916 | 0 | return ofp_is_stat(oh->version, oh->type); |
917 | 0 | } |
918 | | |
919 | | static ovs_be16 *ofpmp_flags__(const struct ofp_header *); |
920 | | |
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 |
927 | | ofpmp_init(struct ovs_list *replies, const struct ofp_header *request) |
928 | 0 | { |
929 | 0 | struct ofpbuf *msg; |
930 | |
|
931 | 0 | ovs_list_init(replies); |
932 | |
|
933 | 0 | msg = ofpraw_alloc_stats_reply(request, 1000); |
934 | 0 | ovs_list_push_back(replies, &msg->list_node); |
935 | 0 | } |
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 * |
945 | | ofpmp_reserve(struct ovs_list *replies, size_t len) |
946 | 0 | { |
947 | 0 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
948 | |
|
949 | 0 | if (msg->size + len <= UINT16_MAX) { |
950 | 0 | ofpbuf_prealloc_tailroom(msg, len); |
951 | 0 | return msg; |
952 | 0 | } else { |
953 | 0 | unsigned int hdrs_len; |
954 | 0 | struct ofpbuf *next; |
955 | 0 | struct ofphdrs hdrs; |
956 | |
|
957 | 0 | ofphdrs_decode_assert(&hdrs, msg->data, msg->size); |
958 | 0 | hdrs_len = ofphdrs_len(&hdrs); |
959 | |
|
960 | 0 | next = ofpbuf_new(MAX(1024, hdrs_len + len)); |
961 | 0 | ofpbuf_put(next, msg->data, hdrs_len); |
962 | 0 | next->header = next->data; |
963 | 0 | next->msg = ofpbuf_tail(next); |
964 | 0 | ovs_list_push_back(replies, &next->list_node); |
965 | |
|
966 | 0 | *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE); |
967 | |
|
968 | 0 | return next; |
969 | 0 | } |
970 | 0 | } |
971 | | |
972 | | /* Appends 'len' bytes to the series of statistics replies in 'replies', and |
973 | | * returns the first byte. */ |
974 | | void * |
975 | | ofpmp_append(struct ovs_list *replies, size_t len) |
976 | 0 | { |
977 | 0 | return ofpbuf_put_uninit(ofpmp_reserve(replies, len), len); |
978 | 0 | } |
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 |
991 | | ofpmp_postappend(struct ovs_list *replies, size_t start_ofs) |
992 | 0 | { |
993 | 0 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
994 | |
|
995 | 0 | ovs_assert(start_ofs <= UINT16_MAX); |
996 | 0 | if (msg->size > UINT16_MAX) { |
997 | 0 | size_t len = msg->size - start_ofs; |
998 | 0 | memcpy(ofpmp_append(replies, len), |
999 | 0 | (const uint8_t *) msg->data + start_ofs, len); |
1000 | 0 | msg->size = start_ofs; |
1001 | 0 | } |
1002 | 0 | } |
1003 | | |
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 |
1007 | | ofpmp_version(struct ovs_list *replies) |
1008 | 0 | { |
1009 | 0 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
1010 | 0 | const struct ofp_header *oh = msg->data; |
1011 | |
|
1012 | 0 | return oh->version; |
1013 | 0 | } |
1014 | | |
1015 | | /* Determines the OFPRAW_* type of the OpenFlow messages in 'replies', which |
1016 | | * should have been initialized by ofpmp_init(). */ |
1017 | | enum ofpraw |
1018 | | ofpmp_decode_raw(struct ovs_list *replies) |
1019 | 0 | { |
1020 | 0 | struct ofpbuf *msg = ofpbuf_from_list(ovs_list_back(replies)); |
1021 | 0 | enum ofpraw raw; |
1022 | 0 | ovs_assert(!ofpraw_decode_partial(&raw, msg->data, msg->size)); |
1023 | 0 | return raw; |
1024 | 0 | } |
1025 | | |
1026 | | static ovs_be16 * |
1027 | | ofpmp_flags__(const struct ofp_header *oh) |
1028 | 0 | { |
1029 | 0 | switch ((enum ofp_version)oh->version) { |
1030 | 0 | case OFP10_VERSION: |
1031 | 0 | return &((struct ofp10_stats_msg *) oh)->flags; |
1032 | 0 | case OFP11_VERSION: |
1033 | 0 | case OFP12_VERSION: |
1034 | 0 | case OFP13_VERSION: |
1035 | 0 | case OFP14_VERSION: |
1036 | 0 | case OFP15_VERSION: |
1037 | 0 | return &((struct ofp11_stats_msg *) oh)->flags; |
1038 | 0 | default: |
1039 | 0 | OVS_NOT_REACHED(); |
1040 | 0 | } |
1041 | 0 | } |
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 | 0 | { |
1050 | 0 | return ntohs(*ofpmp_flags__(oh)); |
1051 | 0 | } |
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 | 0 | { |
1059 | 0 | return (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; |
1060 | 0 | } |
1061 | | |
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 | 0 | { |
1077 | 0 | return hash_int((OVS_FORCE uint32_t) xid, 0); |
1078 | 0 | } |
1079 | | |
1080 | | static struct ofpmp_partial * |
1081 | | ofpmp_assembler_find(struct hmap *assembler, ovs_be32 xid) |
1082 | 0 | { |
1083 | 0 | if (hmap_is_empty(assembler)) { |
1084 | | /* Common case. */ |
1085 | 0 | return NULL; |
1086 | 0 | } |
1087 | | |
1088 | 0 | struct ofpmp_partial *p; |
1089 | 0 | HMAP_FOR_EACH_IN_BUCKET (p, hmap_node, hash_xid(xid), assembler) { |
1090 | 0 | if (p->xid == xid) { |
1091 | 0 | return p; |
1092 | 0 | } |
1093 | 0 | } |
1094 | 0 | return NULL; |
1095 | 0 | } |
1096 | | |
1097 | | static void |
1098 | | ofpmp_partial_destroy(struct hmap *assembler, struct ofpmp_partial *p) |
1099 | 0 | { |
1100 | 0 | if (p) { |
1101 | 0 | hmap_remove(assembler, &p->hmap_node); |
1102 | 0 | ofpbuf_list_delete(&p->msgs); |
1103 | 0 | free(p); |
1104 | 0 | } |
1105 | 0 | } |
1106 | | |
1107 | | static struct ofpbuf * |
1108 | | ofpmp_partial_error(struct hmap *assembler, struct ofpmp_partial *p, |
1109 | | enum ofperr error) |
1110 | 0 | { |
1111 | 0 | const struct ofpbuf *head = ofpbuf_from_list(ovs_list_back(&p->msgs)); |
1112 | 0 | const struct ofp_header *oh = head->data; |
1113 | 0 | struct ofpbuf *reply = ofperr_encode_reply(error, oh); |
1114 | |
|
1115 | 0 | ofpmp_partial_destroy(assembler, p); |
1116 | |
|
1117 | 0 | return reply; |
1118 | 0 | } |
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 | 0 | { |
1126 | 0 | struct ofpmp_partial *p; |
1127 | 0 | HMAP_FOR_EACH_SAFE (p, hmap_node, assembler) { |
1128 | 0 | ofpmp_partial_destroy(assembler, p); |
1129 | 0 | } |
1130 | 0 | } |
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 | 0 | { |
1140 | 0 | struct ofpmp_partial *p; |
1141 | 0 | HMAP_FOR_EACH (p, hmap_node, assembler) { |
1142 | 0 | if (now >= p->timeout) { |
1143 | 0 | return ofpmp_partial_error( |
1144 | 0 | assembler, p, OFPERR_OFPBRC_MULTIPART_REQUEST_TIMEOUT); |
1145 | 0 | } |
1146 | 0 | } |
1147 | 0 | return NULL; |
1148 | 0 | } |
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 | 0 | { |
1155 | 0 | long long int timeout = LLONG_MAX; |
1156 | |
|
1157 | 0 | struct ofpmp_partial *p; |
1158 | 0 | HMAP_FOR_EACH (p, hmap_node, assembler) { |
1159 | 0 | timeout = MIN(timeout, p->timeout); |
1160 | 0 | } |
1161 | |
|
1162 | 0 | return timeout; |
1163 | 0 | } |
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 | 0 | { |
1181 | 0 | 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 | 0 | struct ofp_header *oh = msg->data; |
1193 | 0 | if (!ofpmsg_is_stat_request(oh)) { |
1194 | 0 | ovs_list_push_back(out, &msg->list_node); |
1195 | 0 | return 0; |
1196 | 0 | } |
1197 | | |
1198 | | /* Decode the multipart request. */ |
1199 | 0 | struct ofphdrs hdrs; |
1200 | 0 | enum ofperr error = ofphdrs_decode(&hdrs, msg->data, msg->size); |
1201 | 0 | if (error) { |
1202 | 0 | return error; |
1203 | 0 | } |
1204 | | |
1205 | 0 | enum ofpraw raw; |
1206 | 0 | error = ofpraw_from_ofphdrs(&raw, &hdrs); |
1207 | 0 | if (error) { |
1208 | 0 | return error; |
1209 | 0 | } |
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 | 0 | const struct raw_info *info = raw_info_get(raw); |
1217 | 0 | const struct raw_instance *instance = raw_instance_get(info, hdrs.version); |
1218 | 0 | unsigned int min_len = ofphdrs_len(&hdrs); |
1219 | 0 | bool has_body = msg->size > min_len; |
1220 | 0 | if (has_body) { |
1221 | 0 | error = ofpraw_check_length(info, instance, msg->size); |
1222 | 0 | if (error) { |
1223 | 0 | return error; |
1224 | 0 | } |
1225 | 0 | } |
1226 | | |
1227 | | /* Find or create an ofpmp_partial record. */ |
1228 | 0 | struct ofpmp_partial *p = ofpmp_assembler_find(assembler, oh->xid); |
1229 | 0 | if (!p) { |
1230 | 0 | p = xzalloc(sizeof *p); |
1231 | 0 | hmap_insert(assembler, &p->hmap_node, hash_xid(oh->xid)); |
1232 | 0 | p->xid = oh->xid; |
1233 | 0 | ovs_list_init(&p->msgs); |
1234 | 0 | p->raw = raw; |
1235 | 0 | } |
1236 | 0 | p->timeout = now + 1000; |
1237 | | |
1238 | | /* Check that the type is the same as any previous messages in this |
1239 | | * sequence. */ |
1240 | 0 | if (p->raw != raw) { |
1241 | 0 | ofpmp_partial_destroy(assembler, p); |
1242 | 0 | return OFPERR_OFPBRC_BAD_STAT; |
1243 | 0 | } |
1244 | | |
1245 | | /* Limit the size of a multipart sequence. |
1246 | | * |
1247 | | * (Table features requests can actually be over 1 MB.) */ |
1248 | 0 | p->size += msg->size; |
1249 | 0 | if (p->size > 4 * 1024 * 1024) { |
1250 | 0 | ofpmp_partial_destroy(assembler, p); |
1251 | 0 | return OFPERR_OFPBRC_MULTIPART_BUFFER_OVERFLOW; |
1252 | 0 | } |
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 | 0 | bool more = oh->version >= OFP13_VERSION && ofpmp_more(oh); |
1257 | 0 | if (has_body) { |
1258 | 0 | p->has_body = true; |
1259 | 0 | } |
1260 | 0 | if (!more && !p->has_body && info->min_body) { |
1261 | 0 | ofpmp_partial_destroy(assembler, p); |
1262 | 0 | return OFPERR_OFPBRC_BAD_LEN; |
1263 | 0 | } |
1264 | | |
1265 | | /* Append the part to the list. |
1266 | | * |
1267 | | * If there are more pieces to come, we're done for now. */ |
1268 | 0 | ovs_list_push_back(&p->msgs, &msg->list_node); |
1269 | 0 | if (more) { |
1270 | 0 | return 0; |
1271 | 0 | } |
1272 | | |
1273 | | /* This multipart request is complete. Move the messages from 'p' to 'out' |
1274 | | * and discard 'p'. */ |
1275 | 0 | ovs_list_move(out, &p->msgs); |
1276 | 0 | ovs_list_init(&p->msgs); |
1277 | 0 | 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 | 0 | struct ofpbuf *b; |
1294 | 0 | LIST_FOR_EACH_SAFE (b, list_node, out) { |
1295 | 0 | if (b->size <= min_len && !ovs_list_is_short(out)) { |
1296 | 0 | ovs_list_remove(&b->list_node); |
1297 | 0 | ofpbuf_delete(b); |
1298 | 0 | } |
1299 | 0 | } |
1300 | 0 | return 0; |
1301 | 0 | } |
1302 | | |
1303 | | static void ofpmsgs_init(void); |
1304 | | |
1305 | | static const struct raw_info * |
1306 | | raw_info_get(enum ofpraw raw) |
1307 | 0 | { |
1308 | 0 | ofpmsgs_init(); |
1309 | |
|
1310 | 0 | ovs_assert(raw < ARRAY_SIZE(raw_infos)); |
1311 | 0 | return &raw_infos[raw]; |
1312 | 0 | } |
1313 | | |
1314 | | static struct raw_instance * |
1315 | | raw_instance_get(const struct raw_info *info, uint8_t version) |
1316 | 0 | { |
1317 | 0 | ovs_assert(version >= info->min_version && version <= info->max_version); |
1318 | 0 | return &info->instances[version - info->min_version]; |
1319 | 0 | } |
1320 | | |
1321 | | static enum ofperr |
1322 | | ofpraw_from_ofphdrs(enum ofpraw *raw, const struct ofphdrs *hdrs) |
1323 | 0 | { |
1324 | 0 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); |
1325 | |
|
1326 | 0 | struct raw_instance *raw_hdrs; |
1327 | 0 | uint32_t hash; |
1328 | |
|
1329 | 0 | ofpmsgs_init(); |
1330 | |
|
1331 | 0 | hash = ofphdrs_hash(hdrs); |
1332 | 0 | HMAP_FOR_EACH_WITH_HASH (raw_hdrs, hmap_node, hash, &raw_instance_map) { |
1333 | 0 | if (ofphdrs_equal(hdrs, &raw_hdrs->hdrs)) { |
1334 | 0 | *raw = raw_hdrs->raw; |
1335 | 0 | return 0; |
1336 | 0 | } |
1337 | 0 | } |
1338 | | |
1339 | 0 | if (!VLOG_DROP_WARN(&rl)) { |
1340 | 0 | struct ds s; |
1341 | |
|
1342 | 0 | ds_init(&s); |
1343 | 0 | ds_put_format(&s, "version %"PRIu8", type %"PRIu8, |
1344 | 0 | hdrs->version, hdrs->type); |
1345 | 0 | if (ofphdrs_is_stat(hdrs)) { |
1346 | 0 | ds_put_format(&s, ", stat %"PRIu16, hdrs->stat); |
1347 | 0 | } |
1348 | 0 | if (hdrs->vendor) { |
1349 | 0 | ds_put_format(&s, ", vendor 0x%"PRIx32", subtype %"PRIu32, |
1350 | 0 | hdrs->vendor, hdrs->subtype); |
1351 | 0 | } |
1352 | 0 | VLOG_WARN("unknown OpenFlow message (%s)", ds_cstr(&s)); |
1353 | 0 | ds_destroy(&s); |
1354 | 0 | } |
1355 | |
|
1356 | 0 | return (hdrs->vendor ? OFPERR_OFPBRC_BAD_SUBTYPE |
1357 | 0 | : ofphdrs_is_stat(hdrs) ? OFPERR_OFPBRC_BAD_STAT |
1358 | 0 | : OFPERR_OFPBRC_BAD_TYPE); |
1359 | 0 | } |
1360 | | |
1361 | | static void |
1362 | | ofpmsgs_init(void) |
1363 | 0 | { |
1364 | 0 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
1365 | 0 | const struct raw_info *info; |
1366 | |
|
1367 | 0 | if (!ovsthread_once_start(&once)) { |
1368 | 0 | return; |
1369 | 0 | } |
1370 | | |
1371 | 0 | hmap_init(&raw_instance_map); |
1372 | 0 | for (info = raw_infos; info < &raw_infos[ARRAY_SIZE(raw_infos)]; info++) |
1373 | 0 | { |
1374 | 0 | int n_instances = info->max_version - info->min_version + 1; |
1375 | 0 | struct raw_instance *inst; |
1376 | |
|
1377 | 0 | for (inst = info->instances; |
1378 | 0 | inst < &info->instances[n_instances]; |
1379 | 0 | inst++) { |
1380 | 0 | inst->hdrs_len = ofphdrs_len(&inst->hdrs); |
1381 | 0 | hmap_insert(&raw_instance_map, &inst->hmap_node, |
1382 | 0 | ofphdrs_hash(&inst->hdrs)); |
1383 | 0 | } |
1384 | 0 | } |
1385 | |
|
1386 | 0 | ovsthread_once_done(&once); |
1387 | 0 | } |