]>
Commit | Line | Data |
---|---|---|
982697a4 | 1 | /* |
cb22974d | 2 | * Copyright (c) 2012, 2013 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> | |
18 | #include "ofp-msgs.h" | |
982697a4 BP |
19 | #include "byte-order.h" |
20 | #include "dynamic-string.h" | |
21 | #include "hash.h" | |
22 | #include "hmap.h" | |
23 | #include "ofpbuf.h" | |
24 | #include "openflow/nicira-ext.h" | |
25 | #include "openflow/openflow.h" | |
26 | #include "vlog.h" | |
27 | ||
28 | VLOG_DEFINE_THIS_MODULE(ofp_msgs); | |
29 | ||
30 | #define OFPT_VENDOR 4 | |
31 | #define OFPT10_STATS_REQUEST 16 | |
32 | #define OFPT10_STATS_REPLY 17 | |
33 | #define OFPT11_STATS_REQUEST 18 | |
34 | #define OFPT11_STATS_REPLY 19 | |
35 | #define OFPST_VENDOR 0xffff | |
36 | ||
37 | /* A thin abstraction of OpenFlow headers: | |
38 | * | |
39 | * - 'version' and 'type' come straight from struct ofp_header, so these are | |
40 | * always present and meaningful. | |
41 | * | |
42 | * - 'stat' comes from the 'type' member in statistics messages only. It is | |
43 | * meaningful, therefore, only if 'version' and 'type' taken together | |
44 | * specify a statistics request or reply. Otherwise it is 0. | |
45 | * | |
46 | * - 'vendor' is meaningful only for vendor messages, that is, if 'version' | |
47 | * and 'type' specify a vendor message or if 'version' and 'type' specify | |
48 | * a statistics message and 'stat' specifies a vendor statistic type. | |
49 | * Otherwise it is 0. | |
50 | * | |
51 | * - 'subtype' is meaningful only for vendor messages and otherwise 0. It | |
52 | * specifies a vendor-defined subtype. There is no standard format for | |
53 | * these but 32 bits seems like it should be enough. */ | |
54 | struct ofphdrs { | |
55 | uint8_t version; /* From ofp_header. */ | |
56 | uint8_t type; /* From ofp_header. */ | |
57 | uint16_t stat; /* From ofp10_stats_msg or ofp11_stats_msg. */ | |
58 | uint32_t vendor; /* From ofp_vendor_header, | |
59 | * ofp10_vendor_stats_msg, or | |
60 | * ofp11_vendor_stats_msg. */ | |
61 | uint32_t subtype; /* From nicira_header, nicira10_stats_msg, or | |
62 | * nicira11_stats_msg. */ | |
63 | }; | |
64 | BUILD_ASSERT_DECL(sizeof(struct ofphdrs) == 12); | |
65 | ||
66 | /* A mapping from OpenFlow headers to OFPRAW_*. */ | |
67 | struct raw_instance { | |
68 | struct hmap_node hmap_node; /* In 'raw_instance_map'. */ | |
69 | struct ofphdrs hdrs; /* Key. */ | |
70 | enum ofpraw raw; /* Value. */ | |
71 | unsigned int hdrs_len; /* ofphdrs_len(hdrs). */ | |
72 | }; | |
73 | ||
74 | /* Information about a particular 'enum ofpraw'. */ | |
75 | struct raw_info { | |
76 | /* All possible instantiations of this OFPRAW_* into OpenFlow headers. */ | |
77 | struct raw_instance *instances; /* min_version - max_version + 1 elems. */ | |
78 | uint8_t min_version; | |
79 | uint8_t max_version; | |
80 | ||
81 | unsigned int min_body; | |
82 | unsigned int extra_multiple; | |
83 | enum ofptype type; | |
84 | const char *name; | |
85 | }; | |
86 | ||
87 | /* All understood OpenFlow message types, indexed by their 'struct ofphdrs'. */ | |
88 | static struct hmap raw_instance_map; | |
89 | #include "ofp-msgs.inc" | |
90 | ||
91 | static ovs_be32 alloc_xid(void); | |
92 | ||
93 | /* ofphdrs functions. */ | |
94 | static uint32_t ofphdrs_hash(const struct ofphdrs *); | |
95 | static bool ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b); | |
96 | static enum ofperr ofphdrs_decode(struct ofphdrs *, | |
97 | const struct ofp_header *oh, size_t length); | |
98 | static void ofphdrs_decode_assert(struct ofphdrs *, | |
99 | const struct ofp_header *oh, size_t length); | |
100 | size_t ofphdrs_len(const struct ofphdrs *); | |
101 | ||
102 | static const struct raw_info *raw_info_get(enum ofpraw); | |
103 | static struct raw_instance *raw_instance_get(const struct raw_info *, | |
104 | uint8_t version); | |
105 | ||
106 | static enum ofperr ofpraw_from_ofphdrs(enum ofpraw *, const struct ofphdrs *); | |
107 | \f | |
108 | /* Returns a transaction ID to use for an outgoing OpenFlow message. */ | |
109 | static ovs_be32 | |
110 | alloc_xid(void) | |
111 | { | |
112 | static uint32_t next_xid = 1; | |
113 | return htonl(next_xid++); | |
114 | } | |
115 | \f | |
116 | static uint32_t | |
117 | ofphdrs_hash(const struct ofphdrs *hdrs) | |
118 | { | |
119 | BUILD_ASSERT_DECL(sizeof *hdrs == 12); | |
120 | return hash_words((const uint32_t *) hdrs, 3, 0); | |
121 | } | |
122 | ||
123 | static bool | |
124 | ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b) | |
125 | { | |
126 | return !memcmp(a, b, sizeof *a); | |
127 | } | |
128 | ||
129 | static void | |
130 | log_bad_vendor(uint32_t vendor) | |
131 | { | |
132 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); | |
133 | ||
134 | VLOG_WARN_RL(&rl, "OpenFlow message has unknown vendor %#"PRIx32, vendor); | |
135 | } | |
136 | ||
137 | static enum ofperr | |
138 | ofphdrs_decode(struct ofphdrs *hdrs, | |
139 | const struct ofp_header *oh, size_t length) | |
140 | { | |
141 | memset(hdrs, 0, sizeof *hdrs); | |
142 | if (length < sizeof *oh) { | |
143 | return OFPERR_OFPBRC_BAD_LEN; | |
144 | } | |
145 | ||
146 | /* Get base message version and type (OFPT_*). */ | |
147 | hdrs->version = oh->version; | |
148 | hdrs->type = oh->type; | |
149 | ||
150 | if (hdrs->type == OFPT_VENDOR) { | |
151 | /* Get vendor. */ | |
152 | const struct ofp_vendor_header *ovh; | |
153 | ||
154 | if (length < sizeof *ovh) { | |
155 | return OFPERR_OFPBRC_BAD_LEN; | |
156 | } | |
157 | ||
158 | ovh = (const struct ofp_vendor_header *) oh; | |
159 | hdrs->vendor = ntohl(ovh->vendor); | |
160 | if (hdrs->vendor == NX_VENDOR_ID) { | |
161 | /* Get Nicira message subtype (NXT_*). */ | |
162 | const struct nicira_header *nh; | |
163 | ||
164 | if (length < sizeof *nh) { | |
165 | return OFPERR_OFPBRC_BAD_LEN; | |
166 | } | |
167 | nh = (const struct nicira_header *) oh; | |
168 | hdrs->subtype = ntohl(nh->subtype); | |
169 | } else { | |
170 | log_bad_vendor(hdrs->vendor); | |
171 | return OFPERR_OFPBRC_BAD_VENDOR; | |
172 | } | |
173 | } else if (hdrs->version == OFP10_VERSION | |
174 | && (hdrs->type == OFPT10_STATS_REQUEST || | |
175 | hdrs->type == OFPT10_STATS_REPLY)) { | |
e2b9ac44 | 176 | const struct ofp10_stats_msg *osm; |
982697a4 BP |
177 | |
178 | /* Get statistic type (OFPST_*). */ | |
179 | if (length < sizeof *osm) { | |
180 | return OFPERR_OFPBRC_BAD_LEN; | |
181 | } | |
e2b9ac44 | 182 | osm = (const struct ofp10_stats_msg *) oh; |
982697a4 BP |
183 | hdrs->stat = ntohs(osm->type); |
184 | ||
185 | if (hdrs->stat == OFPST_VENDOR) { | |
186 | /* Get vendor. */ | |
187 | const struct ofp10_vendor_stats_msg *ovsm; | |
188 | ||
189 | if (length < sizeof *ovsm) { | |
190 | return OFPERR_OFPBRC_BAD_LEN; | |
191 | } | |
192 | ||
193 | ovsm = (const struct ofp10_vendor_stats_msg *) oh; | |
194 | hdrs->vendor = ntohl(ovsm->vendor); | |
195 | if (hdrs->vendor == NX_VENDOR_ID) { | |
196 | /* Get Nicira statistic type (NXST_*). */ | |
197 | const struct nicira10_stats_msg *nsm; | |
198 | ||
199 | if (length < sizeof *nsm) { | |
200 | return OFPERR_OFPBRC_BAD_LEN; | |
201 | } | |
202 | nsm = (const struct nicira10_stats_msg *) oh; | |
203 | hdrs->subtype = ntohl(nsm->subtype); | |
204 | } else { | |
205 | log_bad_vendor(hdrs->vendor); | |
206 | return OFPERR_OFPBRC_BAD_VENDOR; | |
207 | } | |
208 | } | |
209 | } else if (hdrs->version != OFP10_VERSION | |
210 | && (hdrs->type == OFPT11_STATS_REQUEST || | |
211 | hdrs->type == OFPT11_STATS_REPLY)) { | |
212 | const struct ofp11_stats_msg *osm; | |
213 | ||
214 | /* Get statistic type (OFPST_*). */ | |
215 | if (length < sizeof *osm) { | |
216 | return OFPERR_OFPBRC_BAD_LEN; | |
217 | } | |
218 | osm = (const struct ofp11_stats_msg *) oh; | |
219 | hdrs->stat = ntohs(osm->type); | |
220 | ||
221 | if (hdrs->stat == OFPST_VENDOR) { | |
222 | /* Get vendor. */ | |
223 | const struct ofp11_vendor_stats_msg *ovsm; | |
224 | ||
225 | if (length < sizeof *ovsm) { | |
226 | return OFPERR_OFPBRC_BAD_LEN; | |
227 | } | |
228 | ||
229 | ovsm = (const struct ofp11_vendor_stats_msg *) oh; | |
230 | hdrs->vendor = ntohl(ovsm->vendor); | |
231 | if (hdrs->vendor == NX_VENDOR_ID) { | |
232 | /* Get Nicira statistic type (NXST_*). */ | |
233 | const struct nicira11_stats_msg *nsm; | |
234 | ||
235 | if (length < sizeof *nsm) { | |
236 | return OFPERR_OFPBRC_BAD_LEN; | |
237 | } | |
238 | nsm = (const struct nicira11_stats_msg *) oh; | |
239 | hdrs->subtype = ntohl(nsm->subtype); | |
240 | } else { | |
241 | log_bad_vendor(hdrs->vendor); | |
242 | return OFPERR_OFPBRC_BAD_VENDOR; | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
247 | return 0; | |
248 | } | |
249 | ||
250 | static void | |
251 | ofphdrs_decode_assert(struct ofphdrs *hdrs, | |
252 | const struct ofp_header *oh, size_t length) | |
253 | { | |
254 | enum ofperr error = ofphdrs_decode(hdrs, oh, length); | |
cb22974d | 255 | ovs_assert(!error); |
982697a4 BP |
256 | } |
257 | ||
258 | static bool | |
259 | ofphdrs_is_stat(const struct ofphdrs *hdrs) | |
260 | { | |
2e3fa633 SH |
261 | switch ((enum ofp_version) hdrs->version) { |
262 | case OFP10_VERSION: | |
263 | return (hdrs->type == OFPT10_STATS_REQUEST || | |
264 | hdrs->type == OFPT10_STATS_REPLY); | |
265 | case OFP11_VERSION: | |
266 | case OFP12_VERSION: | |
2e1ae200 | 267 | case OFP13_VERSION: |
2e3fa633 SH |
268 | return (hdrs->type == OFPT11_STATS_REQUEST || |
269 | hdrs->type == OFPT11_STATS_REPLY); | |
270 | } | |
271 | ||
272 | return false; | |
982697a4 BP |
273 | } |
274 | ||
275 | size_t | |
276 | ofphdrs_len(const struct ofphdrs *hdrs) | |
277 | { | |
278 | if (hdrs->type == OFPT_VENDOR) { | |
279 | return sizeof(struct nicira_header); | |
280 | } | |
281 | ||
2e3fa633 SH |
282 | switch ((enum ofp_version) hdrs->version) { |
283 | case OFP10_VERSION: | |
982697a4 BP |
284 | if (hdrs->type == OFPT10_STATS_REQUEST || |
285 | hdrs->type == OFPT10_STATS_REPLY) { | |
286 | return (hdrs->stat == OFPST_VENDOR | |
287 | ? sizeof(struct nicira10_stats_msg) | |
e2b9ac44 | 288 | : sizeof(struct ofp10_stats_msg)); |
982697a4 | 289 | } |
2e3fa633 SH |
290 | break; |
291 | ||
292 | case OFP11_VERSION: | |
293 | case OFP12_VERSION: | |
2e1ae200 | 294 | case OFP13_VERSION: |
982697a4 BP |
295 | if (hdrs->type == OFPT11_STATS_REQUEST || |
296 | hdrs->type == OFPT11_STATS_REPLY) { | |
297 | return (hdrs->stat == OFPST_VENDOR | |
298 | ? sizeof(struct nicira11_stats_msg) | |
299 | : sizeof(struct ofp11_stats_msg)); | |
300 | } | |
2e3fa633 | 301 | break; |
982697a4 BP |
302 | } |
303 | ||
304 | return sizeof(struct ofp_header); | |
305 | } | |
306 | \f | |
307 | /* Determines the OFPRAW_* type of the OpenFlow message at 'oh', which has | |
308 | * length 'oh->length'. (The caller must ensure that 'oh->length' bytes of | |
309 | * data are readable at 'oh'.) On success, returns 0 and stores the type into | |
310 | * '*raw'. On failure, returns an OFPERR_* error code and zeros '*raw'. | |
311 | * | |
312 | * This function checks that 'oh' is a valid length for its particular type of | |
313 | * message, and returns an error if not. */ | |
314 | enum ofperr | |
315 | ofpraw_decode(enum ofpraw *raw, const struct ofp_header *oh) | |
316 | { | |
317 | struct ofpbuf msg; | |
318 | ||
319 | ofpbuf_use_const(&msg, oh, ntohs(oh->length)); | |
320 | return ofpraw_pull(raw, &msg); | |
321 | } | |
322 | ||
323 | /* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts | |
324 | * at 'msg->data' and has length 'msg->size' bytes. On success, returns 0 and | |
325 | * stores the type into '*rawp'. On failure, returns an OFPERR_* error code | |
326 | * and zeros '*rawp'. | |
327 | * | |
328 | * This function checks that the message has a valid length for its particular | |
329 | * type of message, and returns an error if not. | |
330 | * | |
331 | * In addition to setting '*rawp', this function pulls off the OpenFlow header | |
332 | * (including the stats headers, vendor header, and any subtype header) with | |
333 | * ofpbuf_pull(). It also sets 'msg->l2' to the start of the OpenFlow header | |
334 | * and 'msg->l3' just beyond the headers (that is, to the final value of | |
335 | * msg->data). */ | |
336 | enum ofperr | |
337 | ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg) | |
338 | { | |
339 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
340 | ||
341 | const struct raw_instance *instance; | |
342 | const struct raw_info *info; | |
343 | struct ofphdrs hdrs; | |
344 | ||
345 | unsigned int min_len; | |
346 | unsigned int len; | |
347 | ||
348 | enum ofperr error; | |
349 | enum ofpraw raw; | |
350 | ||
351 | /* Set default outputs. */ | |
352 | msg->l2 = msg->l3 = msg->data; | |
353 | *rawp = 0; | |
354 | ||
355 | len = msg->size; | |
356 | error = ofphdrs_decode(&hdrs, msg->data, len); | |
357 | if (error) { | |
358 | return error; | |
359 | } | |
360 | ||
361 | error = ofpraw_from_ofphdrs(&raw, &hdrs); | |
362 | if (error) { | |
363 | return error; | |
364 | } | |
365 | ||
366 | info = raw_info_get(raw); | |
367 | instance = raw_instance_get(info, hdrs.version); | |
368 | msg->l2 = ofpbuf_pull(msg, instance->hdrs_len); | |
369 | msg->l3 = msg->data; | |
370 | ||
371 | min_len = instance->hdrs_len + info->min_body; | |
372 | switch (info->extra_multiple) { | |
373 | case 0: | |
374 | if (len != min_len) { | |
375 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected " | |
376 | "length %u)", info->name, len, min_len); | |
377 | return OFPERR_OFPBRC_BAD_LEN; | |
378 | } | |
379 | break; | |
380 | ||
381 | case 1: | |
382 | if (len < min_len) { | |
383 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected " | |
384 | "length at least %u bytes)", | |
385 | info->name, len, min_len); | |
386 | return OFPERR_OFPBRC_BAD_LEN; | |
387 | } | |
388 | break; | |
389 | ||
390 | default: | |
391 | if (len < min_len || (len - min_len) % info->extra_multiple) { | |
392 | VLOG_WARN_RL(&rl, "received %s with incorrect length %u (must be " | |
393 | "exactly %u bytes or longer by an integer multiple " | |
394 | "of %u bytes)", | |
395 | info->name, len, min_len, info->extra_multiple); | |
396 | return OFPERR_OFPBRC_BAD_LEN; | |
397 | } | |
398 | break; | |
399 | } | |
400 | ||
401 | *rawp = raw; | |
402 | return 0; | |
403 | } | |
404 | ||
405 | /* Does the same job as ofpraw_pull(), except that it assert-fails if | |
406 | * ofpbuf_pull() would have reported an error. Thus, it's able to use the | |
407 | * return value for the OFPRAW_* message type instead of an error code. | |
408 | * | |
409 | * (It only makes sense to use this function if you previously called | |
410 | * ofpbuf_decode() on the message and thus know that it's OK.) */ | |
411 | enum ofpraw | |
412 | ofpraw_pull_assert(struct ofpbuf *msg) | |
413 | { | |
414 | enum ofperr error; | |
415 | enum ofpraw raw; | |
416 | ||
417 | error = ofpraw_pull(&raw, msg); | |
cb22974d | 418 | ovs_assert(!error); |
982697a4 BP |
419 | return raw; |
420 | } | |
421 | ||
422 | /* Determines the OFPRAW_* type of the OpenFlow message that starts at 'oh' and | |
423 | * has length 'length' bytes. On success, returns 0 and stores the type into | |
424 | * '*rawp'. On failure, returns an OFPERR_* error code and zeros '*rawp'. | |
425 | * | |
426 | * Unlike other functions for decoding message types, this one is not picky | |
427 | * about message length. For example, it will successfully decode a message | |
428 | * whose body is shorter than the minimum length for a message of its type. | |
429 | * Thus, this is the correct function to use for decoding the type of a message | |
430 | * that might have been truncated, such as the payload of an OpenFlow error | |
431 | * message (which is allowed to be truncated to 64 bytes). */ | |
432 | enum ofperr | |
433 | ofpraw_decode_partial(enum ofpraw *raw, | |
434 | const struct ofp_header *oh, size_t length) | |
435 | { | |
436 | struct ofphdrs hdrs; | |
437 | enum ofperr error; | |
438 | ||
439 | error = ofphdrs_decode(&hdrs, oh, length); | |
440 | if (!error) { | |
441 | error = ofpraw_from_ofphdrs(raw, &hdrs); | |
442 | } | |
443 | ||
444 | if (error) { | |
445 | *raw = 0; | |
446 | } | |
447 | return error; | |
448 | } | |
449 | \f | |
450 | /* Encoding messages using OFPRAW_* values. */ | |
451 | ||
452 | static void ofpraw_put__(enum ofpraw, uint8_t version, ovs_be32 xid, | |
453 | size_t extra_tailroom, struct ofpbuf *); | |
454 | ||
455 | /* Allocates and returns a new ofpbuf that contains an OpenFlow header for | |
456 | * 'raw' with OpenFlow version 'version' and a fresh OpenFlow transaction ID. | |
457 | * The ofpbuf has enough tailroom for the minimum body length of 'raw', plus | |
458 | * 'extra_tailroom' additional bytes. | |
459 | * | |
460 | * Each 'raw' value is valid only for certain OpenFlow versions. The caller | |
461 | * must specify a valid (raw, version) pair. | |
462 | * | |
463 | * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header | |
464 | * and 'l3' points just after it, to where the message's body will start. The | |
465 | * caller must actually allocate the body into the space reserved for it, | |
466 | * e.g. with ofpbuf_put_uninit(). | |
467 | * | |
468 | * The caller owns the returned ofpbuf and must free it when it is no longer | |
469 | * needed, e.g. with ofpbuf_delete(). */ | |
470 | struct ofpbuf * | |
471 | ofpraw_alloc(enum ofpraw raw, uint8_t version, size_t extra_tailroom) | |
472 | { | |
473 | return ofpraw_alloc_xid(raw, version, alloc_xid(), extra_tailroom); | |
474 | } | |
475 | ||
476 | /* Same as ofpraw_alloc() but the caller provides the transaction ID. */ | |
477 | struct ofpbuf * | |
478 | ofpraw_alloc_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid, | |
479 | size_t extra_tailroom) | |
480 | { | |
481 | struct ofpbuf *buf = ofpbuf_new(0); | |
482 | ofpraw_put__(raw, version, xid, extra_tailroom, buf); | |
483 | return buf; | |
484 | } | |
485 | ||
486 | /* Same as ofpraw_alloc(), but obtains the OpenFlow version and transaction ID | |
487 | * from 'request->version' and 'request->xid', respectively. | |
488 | * | |
489 | * Even though the version comes from 'request->version', the caller must still | |
490 | * know what it is doing, by specifying a valid pairing of 'raw' and | |
491 | * 'request->version', just like ofpraw_alloc(). */ | |
492 | struct ofpbuf * | |
493 | ofpraw_alloc_reply(enum ofpraw raw, const struct ofp_header *request, | |
494 | size_t extra_tailroom) | |
495 | { | |
496 | return ofpraw_alloc_xid(raw, request->version, request->xid, | |
497 | extra_tailroom); | |
498 | } | |
499 | ||
500 | /* Allocates and returns a new ofpbuf that contains an OpenFlow header that is | |
501 | * a stats reply to the stats request in 'request', using the same OpenFlow | |
502 | * version and transaction ID as 'request'. The ofpbuf has enough tailroom for | |
503 | * the stats reply's minimum body length, plus 'extra_tailroom' additional | |
504 | * bytes. | |
505 | * | |
506 | * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST* | |
507 | * value. Every stats request has a corresponding reply, so the (raw, version) | |
508 | * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here. | |
509 | * | |
510 | * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header | |
511 | * and 'l3' points just after it, to where the message's body will start. The | |
512 | * caller must actually allocate the body into the space reserved for it, | |
513 | * e.g. with ofpbuf_put_uninit(). | |
514 | * | |
515 | * The caller owns the returned ofpbuf and must free it when it is no longer | |
516 | * needed, e.g. with ofpbuf_delete(). */ | |
517 | struct ofpbuf * | |
518 | ofpraw_alloc_stats_reply(const struct ofp_header *request, | |
519 | size_t extra_tailroom) | |
520 | { | |
521 | enum ofpraw request_raw; | |
522 | enum ofpraw reply_raw; | |
523 | enum ofperr error; | |
524 | ||
525 | error = ofpraw_decode_partial(&request_raw, request, | |
526 | ntohs(request->length)); | |
cb22974d | 527 | ovs_assert(!error); |
982697a4 BP |
528 | |
529 | reply_raw = ofpraw_stats_request_to_reply(request_raw, request->version); | |
cb22974d | 530 | ovs_assert(reply_raw); |
982697a4 BP |
531 | |
532 | return ofpraw_alloc_reply(reply_raw, request, extra_tailroom); | |
533 | } | |
534 | ||
535 | /* Appends to 'buf' an OpenFlow header for 'raw' with OpenFlow version | |
536 | * 'version' and a fresh OpenFlow transaction ID. Preallocates enough tailroom | |
537 | * in 'buf' for the minimum body length of 'raw', plus 'extra_tailroom' | |
538 | * additional bytes. | |
539 | * | |
540 | * Each 'raw' value is valid only for certain OpenFlow versions. The caller | |
541 | * must specify a valid (raw, version) pair. | |
542 | * | |
543 | * Upon return, 'buf->l2' points to the beginning of the OpenFlow header and | |
544 | * 'buf->l3' points just after it, to where the message's body will start. The | |
545 | * caller must actually allocating the body into the space reserved for it, | |
546 | * e.g. with ofpbuf_put_uninit(). */ | |
547 | void | |
548 | ofpraw_put(enum ofpraw raw, uint8_t version, struct ofpbuf *buf) | |
549 | { | |
550 | ofpraw_put__(raw, version, alloc_xid(), 0, buf); | |
551 | } | |
552 | ||
553 | /* Same as ofpraw_put() but the caller provides the transaction ID. */ | |
554 | void | |
555 | ofpraw_put_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid, | |
556 | struct ofpbuf *buf) | |
557 | { | |
558 | ofpraw_put__(raw, version, xid, 0, buf); | |
559 | } | |
560 | ||
561 | /* Same as ofpraw_put(), but obtains the OpenFlow version and transaction ID | |
562 | * from 'request->version' and 'request->xid', respectively. | |
563 | * | |
564 | * Even though the version comes from 'request->version', the caller must still | |
565 | * know what it is doing, by specifying a valid pairing of 'raw' and | |
566 | * 'request->version', just like ofpraw_put(). */ | |
567 | void | |
568 | ofpraw_put_reply(enum ofpraw raw, const struct ofp_header *request, | |
569 | struct ofpbuf *buf) | |
570 | { | |
571 | ofpraw_put__(raw, request->version, request->xid, 0, buf); | |
572 | } | |
573 | ||
574 | /* Appends to 'buf' an OpenFlow header that is a stats reply to the stats | |
575 | * request in 'request', using the same OpenFlow version and transaction ID as | |
576 | * 'request'. Preallocate enough tailroom in 'buf for the stats reply's | |
577 | * minimum body length, plus 'extra_tailroom' additional bytes. | |
578 | * | |
579 | * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST* | |
580 | * value. Every stats request has a corresponding reply, so the (raw, version) | |
581 | * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here. | |
582 | * | |
583 | * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header | |
584 | * and 'l3' points just after it, to where the message's body will start. The | |
585 | * caller must actually allocate the body into the space reserved for it, | |
586 | * e.g. with ofpbuf_put_uninit(). | |
587 | * | |
588 | * The caller owns the returned ofpbuf and must free it when it is no longer | |
589 | * needed, e.g. with ofpbuf_delete(). */ | |
590 | void | |
591 | ofpraw_put_stats_reply(const struct ofp_header *request, struct ofpbuf *buf) | |
592 | { | |
593 | enum ofperr error; | |
594 | enum ofpraw raw; | |
595 | ||
596 | error = ofpraw_decode_partial(&raw, request, ntohs(request->length)); | |
cb22974d | 597 | ovs_assert(!error); |
982697a4 BP |
598 | |
599 | raw = ofpraw_stats_request_to_reply(raw, request->version); | |
cb22974d | 600 | ovs_assert(raw); |
982697a4 BP |
601 | |
602 | ofpraw_put__(raw, request->version, request->xid, 0, buf); | |
603 | } | |
604 | ||
605 | static void | |
606 | ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid, | |
607 | size_t extra_tailroom, struct ofpbuf *buf) | |
608 | { | |
609 | const struct raw_info *info = raw_info_get(raw); | |
610 | const struct raw_instance *instance = raw_instance_get(info, version); | |
611 | const struct ofphdrs *hdrs = &instance->hdrs; | |
612 | struct ofp_header *oh; | |
613 | ||
614 | ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body | |
615 | + extra_tailroom)); | |
616 | buf->l2 = ofpbuf_put_uninit(buf, instance->hdrs_len); | |
617 | buf->l3 = ofpbuf_tail(buf); | |
618 | ||
619 | oh = buf->l2; | |
620 | oh->version = version; | |
621 | oh->type = hdrs->type; | |
622 | oh->length = htons(buf->size); | |
623 | oh->xid = xid; | |
624 | ||
625 | if (hdrs->type == OFPT_VENDOR) { | |
626 | struct nicira_header *nh = buf->l2; | |
627 | ||
cb22974d | 628 | ovs_assert(hdrs->vendor == NX_VENDOR_ID); |
982697a4 BP |
629 | nh->vendor = htonl(hdrs->vendor); |
630 | nh->subtype = htonl(hdrs->subtype); | |
631 | } else if (version == OFP10_VERSION | |
632 | && (hdrs->type == OFPT10_STATS_REQUEST || | |
633 | hdrs->type == OFPT10_STATS_REPLY)) { | |
e2b9ac44 | 634 | struct ofp10_stats_msg *osm = buf->l2; |
982697a4 BP |
635 | |
636 | osm->type = htons(hdrs->stat); | |
637 | osm->flags = htons(0); | |
638 | ||
639 | if (hdrs->stat == OFPST_VENDOR) { | |
640 | struct ofp10_vendor_stats_msg *ovsm = buf->l2; | |
641 | ||
642 | ovsm->vendor = htonl(hdrs->vendor); | |
643 | if (hdrs->vendor == NX_VENDOR_ID) { | |
644 | struct nicira10_stats_msg *nsm = buf->l2; | |
645 | ||
646 | nsm->subtype = htonl(hdrs->subtype); | |
647 | memset(nsm->pad, 0, sizeof nsm->pad); | |
648 | } else { | |
649 | NOT_REACHED(); | |
650 | } | |
651 | } | |
652 | } else if (version != OFP10_VERSION | |
653 | && (hdrs->type == OFPT11_STATS_REQUEST || | |
654 | hdrs->type == OFPT11_STATS_REPLY)) { | |
655 | struct ofp11_stats_msg *osm = buf->l2; | |
656 | ||
657 | osm->type = htons(hdrs->stat); | |
658 | osm->flags = htons(0); | |
659 | memset(osm->pad, 0, sizeof osm->pad); | |
660 | ||
661 | if (hdrs->stat == OFPST_VENDOR) { | |
662 | struct ofp11_vendor_stats_msg *ovsm = buf->l2; | |
663 | ||
664 | ovsm->vendor = htonl(hdrs->vendor); | |
665 | if (hdrs->vendor == NX_VENDOR_ID) { | |
666 | struct nicira11_stats_msg *nsm = buf->l2; | |
667 | ||
668 | nsm->subtype = htonl(hdrs->subtype); | |
669 | } else { | |
670 | NOT_REACHED(); | |
671 | } | |
672 | } | |
673 | } | |
674 | } | |
675 | \f | |
676 | /* Returns 'raw''s name. | |
677 | * | |
678 | * The name is the name used for 'raw' in the OpenFlow specification. For | |
679 | * example, ofpraw_get_name(OFPRAW_OFPT10_FEATURES_REPLY) is | |
680 | * "OFPT_FEATURES_REPLY". | |
681 | * | |
682 | * The caller must not modify or free the returned string. */ | |
683 | const char * | |
684 | ofpraw_get_name(enum ofpraw raw) | |
685 | { | |
686 | return raw_info_get(raw)->name; | |
687 | } | |
688 | ||
689 | /* Returns the stats reply that corresponds to 'raw' in the given OpenFlow | |
690 | * 'version'. */ | |
691 | enum ofpraw | |
692 | ofpraw_stats_request_to_reply(enum ofpraw raw, uint8_t version) | |
693 | { | |
694 | const struct raw_info *info = raw_info_get(raw); | |
695 | const struct raw_instance *instance = raw_instance_get(info, version); | |
696 | enum ofpraw reply_raw; | |
697 | struct ofphdrs hdrs; | |
698 | enum ofperr error; | |
699 | ||
700 | hdrs = instance->hdrs; | |
2e3fa633 SH |
701 | switch ((enum ofp_version)hdrs.version) { |
702 | case OFP10_VERSION: | |
cb22974d | 703 | ovs_assert(hdrs.type == OFPT10_STATS_REQUEST); |
982697a4 | 704 | hdrs.type = OFPT10_STATS_REPLY; |
2e3fa633 SH |
705 | break; |
706 | case OFP11_VERSION: | |
707 | case OFP12_VERSION: | |
2e1ae200 | 708 | case OFP13_VERSION: |
cb22974d | 709 | ovs_assert(hdrs.type == OFPT11_STATS_REQUEST); |
982697a4 | 710 | hdrs.type = OFPT11_STATS_REPLY; |
2e3fa633 SH |
711 | break; |
712 | default: | |
713 | NOT_REACHED(); | |
982697a4 BP |
714 | } |
715 | ||
716 | error = ofpraw_from_ofphdrs(&reply_raw, &hdrs); | |
cb22974d | 717 | ovs_assert(!error); |
982697a4 BP |
718 | |
719 | return reply_raw; | |
720 | } | |
721 | \f | |
722 | /* Determines the OFPTYPE_* type of the OpenFlow message at 'oh', which has | |
723 | * length 'oh->length'. (The caller must ensure that 'oh->length' bytes of | |
724 | * data are readable at 'oh'.) On success, returns 0 and stores the type into | |
725 | * '*typep'. On failure, returns an OFPERR_* error code and zeros '*typep'. | |
726 | * | |
727 | * This function checks that 'oh' is a valid length for its particular type of | |
728 | * message, and returns an error if not. */ | |
729 | enum ofperr | |
730 | ofptype_decode(enum ofptype *typep, const struct ofp_header *oh) | |
731 | { | |
732 | enum ofperr error; | |
733 | enum ofpraw raw; | |
734 | ||
735 | error = ofpraw_decode(&raw, oh); | |
736 | *typep = error ? 0 : ofptype_from_ofpraw(raw); | |
737 | return error; | |
738 | } | |
739 | ||
740 | /* Determines the OFPTYPE_* type of the OpenFlow message in 'msg', which starts | |
741 | * at 'msg->data' and has length 'msg->size' bytes. On success, returns 0 and | |
742 | * stores the type into '*typep'. On failure, returns an OFPERR_* error code | |
743 | * and zeros '*typep'. | |
744 | * | |
745 | * This function checks that the message has a valid length for its particular | |
746 | * type of message, and returns an error if not. | |
747 | * | |
748 | * In addition to setting '*typep', this function pulls off the OpenFlow header | |
749 | * (including the stats headers, vendor header, and any subtype header) with | |
750 | * ofpbuf_pull(). It also sets 'msg->l2' to the start of the OpenFlow header | |
751 | * and 'msg->l3' just beyond the headers (that is, to the final value of | |
752 | * msg->data). */ | |
753 | enum ofperr | |
754 | ofptype_pull(enum ofptype *typep, struct ofpbuf *buf) | |
755 | { | |
756 | enum ofperr error; | |
757 | enum ofpraw raw; | |
758 | ||
759 | error = ofpraw_pull(&raw, buf); | |
760 | *typep = error ? 0 : ofptype_from_ofpraw(raw); | |
761 | return error; | |
762 | } | |
763 | ||
764 | /* Returns the OFPTYPE_* type that corresponds to 'raw'. | |
765 | * | |
766 | * (This is a one-way trip, because the mapping from ofpraw to ofptype is | |
767 | * many-to-one.) */ | |
768 | enum ofptype | |
769 | ofptype_from_ofpraw(enum ofpraw raw) | |
770 | { | |
771 | return raw_info_get(raw)->type; | |
772 | } | |
773 | \f | |
774 | /* Updates the 'length' field of the OpenFlow message in 'buf' to | |
775 | * 'buf->size'. */ | |
776 | void | |
777 | ofpmsg_update_length(struct ofpbuf *buf) | |
778 | { | |
779 | struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof *oh); | |
780 | oh->length = htons(buf->size); | |
781 | } | |
782 | ||
783 | /* Returns just past the Openflow header (including the stats headers, vendor | |
784 | * header, and any subtype header) in 'oh'. */ | |
785 | const void * | |
786 | ofpmsg_body(const struct ofp_header *oh) | |
787 | { | |
788 | struct ofphdrs hdrs; | |
789 | ||
790 | ofphdrs_decode_assert(&hdrs, oh, ntohs(oh->length)); | |
791 | return (const uint8_t *) oh + ofphdrs_len(&hdrs); | |
792 | } | |
793 | \f | |
79b8c36c BP |
794 | static ovs_be16 *ofpmp_flags__(const struct ofp_header *); |
795 | ||
982697a4 BP |
796 | /* Initializes 'replies' as a new list of stats messages that reply to |
797 | * 'request', which must be a stats request message. Initially the list will | |
798 | * consist of only a single reply part without any body. The caller should | |
799 | * use calls to the other ofpmp_*() functions to add to the body and split the | |
800 | * message into multiple parts, if necessary. */ | |
801 | void | |
802 | ofpmp_init(struct list *replies, const struct ofp_header *request) | |
803 | { | |
804 | struct ofpbuf *msg; | |
805 | ||
806 | list_init(replies); | |
807 | ||
808 | msg = ofpraw_alloc_stats_reply(request, 1000); | |
809 | list_push_back(replies, &msg->list_node); | |
810 | } | |
811 | ||
812 | /* Prepares to append up to 'len' bytes to the series of statistics replies in | |
813 | * 'replies', which should have been initialized with ofpmp_init(), if | |
814 | * necessary adding a new reply to the list. | |
815 | * | |
816 | * Returns an ofpbuf with at least 'len' bytes of tailroom. The 'len' bytes | |
817 | * have not actually been allocated, so the caller must do so with | |
818 | * e.g. ofpbuf_put_uninit(). */ | |
819 | struct ofpbuf * | |
820 | ofpmp_reserve(struct list *replies, size_t len) | |
821 | { | |
822 | struct ofpbuf *msg = ofpbuf_from_list(list_back(replies)); | |
823 | ||
824 | if (msg->size + len <= UINT16_MAX) { | |
825 | ofpbuf_prealloc_tailroom(msg, len); | |
826 | return msg; | |
827 | } else { | |
828 | unsigned int hdrs_len; | |
829 | struct ofpbuf *next; | |
830 | struct ofphdrs hdrs; | |
831 | ||
832 | ofphdrs_decode_assert(&hdrs, msg->data, msg->size); | |
833 | hdrs_len = ofphdrs_len(&hdrs); | |
834 | ||
835 | next = ofpbuf_new(MAX(1024, hdrs_len + len)); | |
836 | ofpbuf_put(next, msg->data, hdrs_len); | |
837 | list_push_back(replies, &next->list_node); | |
838 | ||
79b8c36c BP |
839 | *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE); |
840 | ||
982697a4 BP |
841 | return next; |
842 | } | |
843 | } | |
844 | ||
845 | /* Appends 'len' bytes to the series of statistics replies in 'replies', and | |
846 | * returns the first byte. */ | |
847 | void * | |
848 | ofpmp_append(struct list *replies, size_t len) | |
849 | { | |
850 | return ofpbuf_put_uninit(ofpmp_reserve(replies, len), len); | |
851 | } | |
852 | ||
853 | /* Sometimes, when composing stats replies, it's difficult to predict how long | |
854 | * an individual reply chunk will be before actually encoding it into the reply | |
855 | * buffer. This function allows easy handling of this case: just encode the | |
856 | * reply, then use this function to break the message into two pieces if it | |
857 | * exceeds the OpenFlow message limit. | |
858 | * | |
859 | * In detail, if the final stats message in 'replies' is too long for OpenFlow, | |
860 | * this function breaks it into two separate stats replies, the first one with | |
861 | * the first 'start_ofs' bytes, the second one containing the bytes from that | |
862 | * offset onward. */ | |
863 | void | |
864 | ofpmp_postappend(struct list *replies, size_t start_ofs) | |
865 | { | |
866 | struct ofpbuf *msg = ofpbuf_from_list(list_back(replies)); | |
867 | ||
cb22974d | 868 | ovs_assert(start_ofs <= UINT16_MAX); |
982697a4 BP |
869 | if (msg->size > UINT16_MAX) { |
870 | size_t len = msg->size - start_ofs; | |
871 | memcpy(ofpmp_append(replies, len), | |
872 | (const uint8_t *) msg->data + start_ofs, len); | |
873 | msg->size = start_ofs; | |
874 | } | |
875 | } | |
876 | ||
877 | static ovs_be16 * | |
878 | ofpmp_flags__(const struct ofp_header *oh) | |
879 | { | |
2e3fa633 SH |
880 | switch ((enum ofp_version)oh->version) { |
881 | case OFP10_VERSION: | |
882 | return &((struct ofp10_stats_msg *) oh)->flags; | |
883 | case OFP11_VERSION: | |
884 | case OFP12_VERSION: | |
2e1ae200 | 885 | case OFP13_VERSION: |
2e3fa633 SH |
886 | return &((struct ofp11_stats_msg *) oh)->flags; |
887 | default: | |
888 | NOT_REACHED(); | |
889 | } | |
982697a4 BP |
890 | } |
891 | ||
892 | /* Returns the OFPSF_* flags found in the OpenFlow stats header of 'oh', which | |
893 | * must be an OpenFlow stats request or reply. | |
894 | * | |
895 | * (OFPSF_REPLY_MORE is the only defined flag.) */ | |
896 | uint16_t | |
897 | ofpmp_flags(const struct ofp_header *oh) | |
898 | { | |
899 | return ntohs(*ofpmp_flags__(oh)); | |
900 | } | |
901 | ||
902 | /* Returns true if the OFPSF_REPLY_MORE flag is set in the OpenFlow stats | |
903 | * header of 'oh', which must be an OpenFlow stats request or reply, false if | |
904 | * it is not set. */ | |
905 | bool | |
906 | ofpmp_more(const struct ofp_header *oh) | |
907 | { | |
908 | return (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; | |
909 | } | |
910 | \f | |
911 | static void ofpmsgs_init(void); | |
912 | ||
913 | static const struct raw_info * | |
914 | raw_info_get(enum ofpraw raw) | |
915 | { | |
916 | ofpmsgs_init(); | |
917 | ||
cb22974d | 918 | ovs_assert(raw < ARRAY_SIZE(raw_infos)); |
982697a4 BP |
919 | return &raw_infos[raw]; |
920 | } | |
921 | ||
922 | static struct raw_instance * | |
923 | raw_instance_get(const struct raw_info *info, uint8_t version) | |
924 | { | |
cb22974d | 925 | ovs_assert(version >= info->min_version && version <= info->max_version); |
982697a4 BP |
926 | return &info->instances[version - info->min_version]; |
927 | } | |
928 | ||
929 | static enum ofperr | |
930 | ofpraw_from_ofphdrs(enum ofpraw *raw, const struct ofphdrs *hdrs) | |
931 | { | |
932 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); | |
933 | ||
934 | struct raw_instance *raw_hdrs; | |
935 | uint32_t hash; | |
936 | ||
937 | ofpmsgs_init(); | |
938 | ||
939 | hash = ofphdrs_hash(hdrs); | |
940 | HMAP_FOR_EACH_WITH_HASH (raw_hdrs, hmap_node, hash, &raw_instance_map) { | |
941 | if (ofphdrs_equal(hdrs, &raw_hdrs->hdrs)) { | |
942 | *raw = raw_hdrs->raw; | |
943 | return 0; | |
944 | } | |
945 | } | |
946 | ||
947 | if (!VLOG_DROP_WARN(&rl)) { | |
948 | struct ds s; | |
949 | ||
950 | ds_init(&s); | |
951 | ds_put_format(&s, "version %"PRIu8", type %"PRIu8, | |
952 | hdrs->version, hdrs->type); | |
953 | if (ofphdrs_is_stat(hdrs)) { | |
954 | ds_put_format(&s, ", stat %"PRIu16, hdrs->stat); | |
955 | } | |
956 | if (hdrs->vendor) { | |
957 | ds_put_format(&s, ", vendor 0x%"PRIx32", subtype %"PRIu32, | |
958 | hdrs->vendor, hdrs->subtype); | |
959 | } | |
960 | VLOG_WARN("unknown OpenFlow message (%s)", ds_cstr(&s)); | |
961 | ds_destroy(&s); | |
962 | } | |
963 | ||
964 | return (hdrs->vendor ? OFPERR_OFPBRC_BAD_SUBTYPE | |
965 | : ofphdrs_is_stat(hdrs) ? OFPERR_OFPBRC_BAD_STAT | |
966 | : OFPERR_OFPBRC_BAD_TYPE); | |
967 | } | |
968 | ||
969 | static void | |
970 | ofpmsgs_init(void) | |
971 | { | |
972 | const struct raw_info *info; | |
973 | ||
974 | if (raw_instance_map.buckets) { | |
975 | return; | |
976 | } | |
977 | ||
978 | hmap_init(&raw_instance_map); | |
979 | for (info = raw_infos; info < &raw_infos[ARRAY_SIZE(raw_infos)]; info++) | |
980 | { | |
981 | int n_instances = info->max_version - info->min_version + 1; | |
982 | struct raw_instance *inst; | |
983 | ||
984 | for (inst = info->instances; | |
985 | inst < &info->instances[n_instances]; | |
986 | inst++) { | |
987 | inst->hdrs_len = ofphdrs_len(&inst->hdrs); | |
988 | hmap_insert(&raw_instance_map, &inst->hmap_node, | |
989 | ofphdrs_hash(&inst->hdrs)); | |
990 | } | |
991 | } | |
992 | } |