]>
Commit | Line | Data |
---|---|---|
0d71302e BP |
1 | /* |
2 | * Copyright (c) 2008-2017 Nicira, Inc. | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #include "openvswitch/ofp-protocol.h" | |
19 | #include <ctype.h> | |
20 | #include "openvswitch/dynamic-string.h" | |
21 | #include "openvswitch/ofp-flow.h" | |
225c33ba BP |
22 | #include "openvswitch/ofp-msgs.h" |
23 | #include "openvswitch/ofpbuf.h" | |
0d71302e BP |
24 | #include "openvswitch/vlog.h" |
25 | #include "util.h" | |
26 | ||
27 | VLOG_DEFINE_THIS_MODULE(ofp_protocol); | |
28 | ||
225c33ba BP |
29 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); |
30 | ||
0d71302e BP |
31 | /* Protocols. */ |
32 | ||
33 | struct proto_abbrev { | |
34 | enum ofputil_protocol protocol; | |
35 | const char *name; | |
36 | }; | |
37 | ||
38 | /* Most users really don't care about some of the differences between | |
39 | * protocols. These abbreviations help with that. */ | |
40 | static const struct proto_abbrev proto_abbrevs[] = { | |
41 | { OFPUTIL_P_ANY, "any" }, | |
42 | { OFPUTIL_P_OF10_STD_ANY, "OpenFlow10" }, | |
43 | { OFPUTIL_P_OF10_NXM_ANY, "NXM" }, | |
44 | { OFPUTIL_P_ANY_OXM, "OXM" }, | |
45 | }; | |
46 | #define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs) | |
47 | ||
48 | enum ofputil_protocol ofputil_flow_dump_protocols[] = { | |
0d71302e BP |
49 | OFPUTIL_P_OF15_OXM, |
50 | OFPUTIL_P_OF14_OXM, | |
51 | OFPUTIL_P_OF13_OXM, | |
52 | OFPUTIL_P_OF12_OXM, | |
53 | OFPUTIL_P_OF11_STD, | |
54 | OFPUTIL_P_OF10_NXM, | |
55 | OFPUTIL_P_OF10_STD, | |
56 | }; | |
57 | size_t ofputil_n_flow_dump_protocols = ARRAY_SIZE(ofputil_flow_dump_protocols); | |
58 | ||
59 | /* Returns the set of ofputil_protocols that are supported with the given | |
60 | * OpenFlow 'version'. 'version' should normally be an 8-bit OpenFlow version | |
61 | * identifier (e.g. 0x01 for OpenFlow 1.0, 0x02 for OpenFlow 1.1). Returns 0 | |
62 | * if 'version' is not supported or outside the valid range. */ | |
63 | enum ofputil_protocol | |
64 | ofputil_protocols_from_ofp_version(enum ofp_version version) | |
65 | { | |
66 | switch (version) { | |
67 | case OFP10_VERSION: | |
68 | return OFPUTIL_P_OF10_STD_ANY | OFPUTIL_P_OF10_NXM_ANY; | |
69 | case OFP11_VERSION: | |
70 | return OFPUTIL_P_OF11_STD; | |
71 | case OFP12_VERSION: | |
72 | return OFPUTIL_P_OF12_OXM; | |
73 | case OFP13_VERSION: | |
74 | return OFPUTIL_P_OF13_OXM; | |
75 | case OFP14_VERSION: | |
76 | return OFPUTIL_P_OF14_OXM; | |
77 | case OFP15_VERSION: | |
78 | return OFPUTIL_P_OF15_OXM; | |
0d71302e BP |
79 | default: |
80 | return 0; | |
81 | } | |
82 | } | |
83 | ||
84 | /* Returns the ofputil_protocol that is initially in effect on an OpenFlow | |
85 | * connection that has negotiated the given 'version'. 'version' should | |
86 | * normally be an 8-bit OpenFlow version identifier (e.g. 0x01 for OpenFlow | |
87 | * 1.0, 0x02 for OpenFlow 1.1). Returns 0 if 'version' is not supported or | |
88 | * outside the valid range. */ | |
89 | enum ofputil_protocol | |
90 | ofputil_protocol_from_ofp_version(enum ofp_version version) | |
91 | { | |
92 | return rightmost_1bit(ofputil_protocols_from_ofp_version(version)); | |
93 | } | |
94 | ||
95 | /* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION, | |
96 | * etc.) that corresponds to 'protocol'. */ | |
97 | enum ofp_version | |
98 | ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol) | |
99 | { | |
100 | switch (protocol) { | |
101 | case OFPUTIL_P_OF10_STD: | |
102 | case OFPUTIL_P_OF10_STD_TID: | |
103 | case OFPUTIL_P_OF10_NXM: | |
104 | case OFPUTIL_P_OF10_NXM_TID: | |
105 | return OFP10_VERSION; | |
106 | case OFPUTIL_P_OF11_STD: | |
107 | return OFP11_VERSION; | |
108 | case OFPUTIL_P_OF12_OXM: | |
109 | return OFP12_VERSION; | |
110 | case OFPUTIL_P_OF13_OXM: | |
111 | return OFP13_VERSION; | |
112 | case OFPUTIL_P_OF14_OXM: | |
113 | return OFP14_VERSION; | |
114 | case OFPUTIL_P_OF15_OXM: | |
115 | return OFP15_VERSION; | |
0d71302e BP |
116 | } |
117 | ||
118 | OVS_NOT_REACHED(); | |
119 | } | |
120 | ||
121 | /* Returns a bitmap of OpenFlow versions that are supported by at | |
122 | * least one of the 'protocols'. */ | |
123 | uint32_t | |
124 | ofputil_protocols_to_version_bitmap(enum ofputil_protocol protocols) | |
125 | { | |
126 | uint32_t bitmap = 0; | |
127 | ||
128 | for (; protocols; protocols = zero_rightmost_1bit(protocols)) { | |
129 | enum ofputil_protocol protocol = rightmost_1bit(protocols); | |
130 | ||
131 | bitmap |= 1u << ofputil_protocol_to_ofp_version(protocol); | |
132 | } | |
133 | ||
134 | return bitmap; | |
135 | } | |
136 | ||
137 | /* Returns the set of protocols that are supported on top of the | |
138 | * OpenFlow versions included in 'bitmap'. */ | |
139 | enum ofputil_protocol | |
140 | ofputil_protocols_from_version_bitmap(uint32_t bitmap) | |
141 | { | |
142 | enum ofputil_protocol protocols = 0; | |
143 | ||
144 | for (; bitmap; bitmap = zero_rightmost_1bit(bitmap)) { | |
145 | enum ofp_version version = rightmost_1bit_idx(bitmap); | |
146 | ||
147 | protocols |= ofputil_protocols_from_ofp_version(version); | |
148 | } | |
149 | ||
150 | return protocols; | |
151 | } | |
152 | ||
153 | /* Returns true if 'protocol' is a single OFPUTIL_P_* value, false | |
154 | * otherwise. */ | |
155 | bool | |
156 | ofputil_protocol_is_valid(enum ofputil_protocol protocol) | |
157 | { | |
158 | return protocol & OFPUTIL_P_ANY && is_pow2(protocol); | |
159 | } | |
160 | ||
161 | /* Returns the equivalent of 'protocol' with the Nicira flow_mod_table_id | |
162 | * extension turned on or off if 'enable' is true or false, respectively. | |
163 | * | |
164 | * This extension is only useful for protocols whose "standard" version does | |
165 | * not allow specific tables to be modified. In particular, this is true of | |
166 | * OpenFlow 1.0. In later versions of OpenFlow, a flow_mod request always | |
167 | * specifies a table ID and so there is no need for such an extension. When | |
168 | * 'protocol' is such a protocol that doesn't need a flow_mod_table_id | |
169 | * extension, this function just returns its 'protocol' argument unchanged | |
170 | * regardless of the value of 'enable'. */ | |
171 | enum ofputil_protocol | |
172 | ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable) | |
173 | { | |
174 | switch (protocol) { | |
175 | case OFPUTIL_P_OF10_STD: | |
176 | case OFPUTIL_P_OF10_STD_TID: | |
177 | return enable ? OFPUTIL_P_OF10_STD_TID : OFPUTIL_P_OF10_STD; | |
178 | ||
179 | case OFPUTIL_P_OF10_NXM: | |
180 | case OFPUTIL_P_OF10_NXM_TID: | |
181 | return enable ? OFPUTIL_P_OF10_NXM_TID : OFPUTIL_P_OF10_NXM; | |
182 | ||
183 | case OFPUTIL_P_OF11_STD: | |
184 | return OFPUTIL_P_OF11_STD; | |
185 | ||
186 | case OFPUTIL_P_OF12_OXM: | |
187 | return OFPUTIL_P_OF12_OXM; | |
188 | ||
189 | case OFPUTIL_P_OF13_OXM: | |
190 | return OFPUTIL_P_OF13_OXM; | |
191 | ||
192 | case OFPUTIL_P_OF14_OXM: | |
193 | return OFPUTIL_P_OF14_OXM; | |
194 | ||
195 | case OFPUTIL_P_OF15_OXM: | |
196 | return OFPUTIL_P_OF15_OXM; | |
197 | ||
0d71302e BP |
198 | default: |
199 | OVS_NOT_REACHED(); | |
200 | } | |
201 | } | |
202 | ||
203 | /* Returns the "base" version of 'protocol'. That is, if 'protocol' includes | |
204 | * some extension to a standard protocol version, the return value is the | |
205 | * standard version of that protocol without any extension. If 'protocol' is a | |
206 | * standard protocol version, returns 'protocol' unchanged. */ | |
207 | enum ofputil_protocol | |
208 | ofputil_protocol_to_base(enum ofputil_protocol protocol) | |
209 | { | |
210 | return ofputil_protocol_set_tid(protocol, false); | |
211 | } | |
212 | ||
213 | /* Returns 'new_base' with any extensions taken from 'cur'. */ | |
214 | enum ofputil_protocol | |
215 | ofputil_protocol_set_base(enum ofputil_protocol cur, | |
216 | enum ofputil_protocol new_base) | |
217 | { | |
218 | bool tid = (cur & OFPUTIL_P_TID) != 0; | |
219 | ||
220 | switch (new_base) { | |
221 | case OFPUTIL_P_OF10_STD: | |
222 | case OFPUTIL_P_OF10_STD_TID: | |
223 | return ofputil_protocol_set_tid(OFPUTIL_P_OF10_STD, tid); | |
224 | ||
225 | case OFPUTIL_P_OF10_NXM: | |
226 | case OFPUTIL_P_OF10_NXM_TID: | |
227 | return ofputil_protocol_set_tid(OFPUTIL_P_OF10_NXM, tid); | |
228 | ||
229 | case OFPUTIL_P_OF11_STD: | |
230 | return ofputil_protocol_set_tid(OFPUTIL_P_OF11_STD, tid); | |
231 | ||
232 | case OFPUTIL_P_OF12_OXM: | |
233 | return ofputil_protocol_set_tid(OFPUTIL_P_OF12_OXM, tid); | |
234 | ||
235 | case OFPUTIL_P_OF13_OXM: | |
236 | return ofputil_protocol_set_tid(OFPUTIL_P_OF13_OXM, tid); | |
237 | ||
238 | case OFPUTIL_P_OF14_OXM: | |
239 | return ofputil_protocol_set_tid(OFPUTIL_P_OF14_OXM, tid); | |
240 | ||
241 | case OFPUTIL_P_OF15_OXM: | |
242 | return ofputil_protocol_set_tid(OFPUTIL_P_OF15_OXM, tid); | |
243 | ||
0d71302e BP |
244 | default: |
245 | OVS_NOT_REACHED(); | |
246 | } | |
247 | } | |
248 | ||
249 | /* Returns a string form of 'protocol', if a simple form exists (that is, if | |
250 | * 'protocol' is either a single protocol or it is a combination of protocols | |
251 | * that have a single abbreviation). Otherwise, returns NULL. */ | |
252 | const char * | |
253 | ofputil_protocol_to_string(enum ofputil_protocol protocol) | |
254 | { | |
255 | const struct proto_abbrev *p; | |
256 | ||
257 | /* Use a "switch" statement for single-bit names so that we get a compiler | |
258 | * warning if we forget any. */ | |
259 | switch (protocol) { | |
260 | case OFPUTIL_P_OF10_NXM: | |
261 | return "NXM-table_id"; | |
262 | ||
263 | case OFPUTIL_P_OF10_NXM_TID: | |
264 | return "NXM+table_id"; | |
265 | ||
266 | case OFPUTIL_P_OF10_STD: | |
267 | return "OpenFlow10-table_id"; | |
268 | ||
269 | case OFPUTIL_P_OF10_STD_TID: | |
270 | return "OpenFlow10+table_id"; | |
271 | ||
272 | case OFPUTIL_P_OF11_STD: | |
273 | return "OpenFlow11"; | |
274 | ||
275 | case OFPUTIL_P_OF12_OXM: | |
276 | return "OXM-OpenFlow12"; | |
277 | ||
278 | case OFPUTIL_P_OF13_OXM: | |
279 | return "OXM-OpenFlow13"; | |
280 | ||
281 | case OFPUTIL_P_OF14_OXM: | |
282 | return "OXM-OpenFlow14"; | |
283 | ||
284 | case OFPUTIL_P_OF15_OXM: | |
285 | return "OXM-OpenFlow15"; | |
0d71302e BP |
286 | } |
287 | ||
288 | /* Check abbreviations. */ | |
289 | for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) { | |
290 | if (protocol == p->protocol) { | |
291 | return p->name; | |
292 | } | |
293 | } | |
294 | ||
295 | return NULL; | |
296 | } | |
297 | ||
298 | /* Returns a string that represents 'protocols'. The return value might be a | |
299 | * comma-separated list if 'protocols' doesn't have a simple name. The return | |
300 | * value is "none" if 'protocols' is 0. | |
301 | * | |
302 | * The caller must free the returned string (with free()). */ | |
303 | char * | |
304 | ofputil_protocols_to_string(enum ofputil_protocol protocols) | |
305 | { | |
306 | struct ds s; | |
307 | ||
308 | ovs_assert(!(protocols & ~OFPUTIL_P_ANY)); | |
309 | if (protocols == 0) { | |
310 | return xstrdup("none"); | |
311 | } | |
312 | ||
313 | ds_init(&s); | |
314 | while (protocols) { | |
315 | const struct proto_abbrev *p; | |
316 | int i; | |
317 | ||
318 | if (s.length) { | |
319 | ds_put_char(&s, ','); | |
320 | } | |
321 | ||
322 | for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) { | |
323 | if ((protocols & p->protocol) == p->protocol) { | |
324 | ds_put_cstr(&s, p->name); | |
325 | protocols &= ~p->protocol; | |
326 | goto match; | |
327 | } | |
328 | } | |
329 | ||
330 | for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) { | |
331 | enum ofputil_protocol bit = 1u << i; | |
332 | ||
333 | if (protocols & bit) { | |
334 | ds_put_cstr(&s, ofputil_protocol_to_string(bit)); | |
335 | protocols &= ~bit; | |
336 | goto match; | |
337 | } | |
338 | } | |
339 | OVS_NOT_REACHED(); | |
340 | ||
341 | match: ; | |
342 | } | |
343 | return ds_steal_cstr(&s); | |
344 | } | |
345 | ||
346 | static enum ofputil_protocol | |
347 | ofputil_protocol_from_string__(const char *s, size_t n) | |
348 | { | |
349 | const struct proto_abbrev *p; | |
350 | int i; | |
351 | ||
352 | for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) { | |
353 | enum ofputil_protocol bit = 1u << i; | |
354 | const char *name = ofputil_protocol_to_string(bit); | |
355 | ||
356 | if (name && n == strlen(name) && !strncasecmp(s, name, n)) { | |
357 | return bit; | |
358 | } | |
359 | } | |
360 | ||
361 | for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) { | |
362 | if (n == strlen(p->name) && !strncasecmp(s, p->name, n)) { | |
363 | return p->protocol; | |
364 | } | |
365 | } | |
366 | ||
367 | return 0; | |
368 | } | |
369 | ||
370 | /* Returns the nonempty set of protocols represented by 's', which can be a | |
371 | * single protocol name or abbreviation or a comma-separated list of them. | |
372 | * | |
373 | * Aborts the program with an error message if 's' is invalid. */ | |
374 | enum ofputil_protocol | |
375 | ofputil_protocols_from_string(const char *s) | |
376 | { | |
377 | const char *orig_s = s; | |
378 | enum ofputil_protocol protocols; | |
379 | ||
380 | protocols = 0; | |
381 | while (*s) { | |
382 | enum ofputil_protocol p; | |
383 | size_t n; | |
384 | ||
385 | n = strcspn(s, ","); | |
386 | if (n == 0) { | |
387 | s++; | |
388 | continue; | |
389 | } | |
390 | ||
391 | p = ofputil_protocol_from_string__(s, n); | |
392 | if (!p) { | |
393 | ovs_fatal(0, "%.*s: unknown flow protocol", (int) n, s); | |
394 | } | |
395 | protocols |= p; | |
396 | ||
397 | s += n; | |
398 | } | |
399 | ||
400 | if (!protocols) { | |
401 | ovs_fatal(0, "%s: no flow protocol specified", orig_s); | |
402 | } | |
403 | return protocols; | |
404 | } | |
405 | ||
406 | enum ofp_version | |
407 | ofputil_version_from_string(const char *s) | |
408 | { | |
409 | if (!strcasecmp(s, "OpenFlow10")) { | |
410 | return OFP10_VERSION; | |
411 | } | |
412 | if (!strcasecmp(s, "OpenFlow11")) { | |
413 | return OFP11_VERSION; | |
414 | } | |
415 | if (!strcasecmp(s, "OpenFlow12")) { | |
416 | return OFP12_VERSION; | |
417 | } | |
418 | if (!strcasecmp(s, "OpenFlow13")) { | |
419 | return OFP13_VERSION; | |
420 | } | |
421 | if (!strcasecmp(s, "OpenFlow14")) { | |
422 | return OFP14_VERSION; | |
423 | } | |
424 | if (!strcasecmp(s, "OpenFlow15")) { | |
425 | return OFP15_VERSION; | |
426 | } | |
0d71302e BP |
427 | return 0; |
428 | } | |
429 | ||
430 | static bool | |
431 | is_delimiter(unsigned char c) | |
432 | { | |
433 | return isspace(c) || c == ','; | |
434 | } | |
435 | ||
436 | uint32_t | |
437 | ofputil_versions_from_string(const char *s) | |
438 | { | |
439 | size_t i = 0; | |
440 | uint32_t bitmap = 0; | |
441 | ||
442 | while (s[i]) { | |
443 | size_t j; | |
444 | int version; | |
445 | char *key; | |
446 | ||
447 | if (is_delimiter(s[i])) { | |
448 | i++; | |
449 | continue; | |
450 | } | |
451 | j = 0; | |
452 | while (s[i + j] && !is_delimiter(s[i + j])) { | |
453 | j++; | |
454 | } | |
455 | key = xmemdup0(s + i, j); | |
456 | version = ofputil_version_from_string(key); | |
457 | if (!version) { | |
458 | VLOG_FATAL("Unknown OpenFlow version: \"%s\"", key); | |
459 | } | |
460 | free(key); | |
461 | bitmap |= 1u << version; | |
462 | i += j; | |
463 | } | |
464 | ||
465 | return bitmap; | |
466 | } | |
467 | ||
468 | uint32_t | |
469 | ofputil_versions_from_strings(char ** const s, size_t count) | |
470 | { | |
471 | uint32_t bitmap = 0; | |
472 | ||
473 | while (count--) { | |
474 | int version = ofputil_version_from_string(s[count]); | |
475 | if (!version) { | |
476 | VLOG_WARN("Unknown OpenFlow version: \"%s\"", s[count]); | |
477 | } else { | |
478 | bitmap |= 1u << version; | |
479 | } | |
480 | } | |
481 | ||
482 | return bitmap; | |
483 | } | |
484 | ||
485 | const char * | |
486 | ofputil_version_to_string(enum ofp_version ofp_version) | |
487 | { | |
488 | switch (ofp_version) { | |
489 | case OFP10_VERSION: | |
490 | return "OpenFlow10"; | |
491 | case OFP11_VERSION: | |
492 | return "OpenFlow11"; | |
493 | case OFP12_VERSION: | |
494 | return "OpenFlow12"; | |
495 | case OFP13_VERSION: | |
496 | return "OpenFlow13"; | |
497 | case OFP14_VERSION: | |
498 | return "OpenFlow14"; | |
499 | case OFP15_VERSION: | |
500 | return "OpenFlow15"; | |
0d71302e BP |
501 | default: |
502 | OVS_NOT_REACHED(); | |
503 | } | |
504 | } | |
505 | ||
506 | void | |
507 | ofputil_format_version(struct ds *msg, enum ofp_version version) | |
508 | { | |
509 | ds_put_format(msg, "0x%02x", version); | |
510 | } | |
511 | ||
512 | void | |
513 | ofputil_format_version_name(struct ds *msg, enum ofp_version version) | |
514 | { | |
515 | ds_put_cstr(msg, ofputil_version_to_string(version)); | |
516 | } | |
517 | ||
518 | static void | |
519 | ofputil_format_version_bitmap__(struct ds *msg, uint32_t bitmap, | |
520 | void (*format_version)(struct ds *msg, | |
521 | enum ofp_version)) | |
522 | { | |
523 | while (bitmap) { | |
524 | format_version(msg, raw_ctz(bitmap)); | |
525 | bitmap = zero_rightmost_1bit(bitmap); | |
526 | if (bitmap) { | |
527 | ds_put_cstr(msg, ", "); | |
528 | } | |
529 | } | |
530 | } | |
531 | ||
532 | void | |
533 | ofputil_format_version_bitmap(struct ds *msg, uint32_t bitmap) | |
534 | { | |
535 | ofputil_format_version_bitmap__(msg, bitmap, ofputil_format_version); | |
536 | } | |
537 | ||
538 | void | |
539 | ofputil_format_version_bitmap_names(struct ds *msg, uint32_t bitmap) | |
540 | { | |
541 | ofputil_format_version_bitmap__(msg, bitmap, ofputil_format_version_name); | |
542 | } | |
225c33ba | 543 | \f |
0d71302e BP |
544 | /* Returns an OpenFlow message that, sent on an OpenFlow connection whose |
545 | * protocol is 'current', at least partly transitions the protocol to 'want'. | |
546 | * Stores in '*next' the protocol that will be in effect on the OpenFlow | |
547 | * connection if the switch processes the returned message correctly. (If | |
548 | * '*next != want' then the caller will have to iterate.) | |
549 | * | |
550 | * If 'current == want', or if it is not possible to transition from 'current' | |
551 | * to 'want' (because, for example, 'current' and 'want' use different OpenFlow | |
552 | * protocol versions), returns NULL and stores 'current' in '*next'. */ | |
553 | struct ofpbuf * | |
554 | ofputil_encode_set_protocol(enum ofputil_protocol current, | |
555 | enum ofputil_protocol want, | |
556 | enum ofputil_protocol *next) | |
557 | { | |
558 | enum ofp_version cur_version, want_version; | |
559 | enum ofputil_protocol cur_base, want_base; | |
560 | bool cur_tid, want_tid; | |
561 | ||
562 | cur_version = ofputil_protocol_to_ofp_version(current); | |
563 | want_version = ofputil_protocol_to_ofp_version(want); | |
564 | if (cur_version != want_version) { | |
565 | *next = current; | |
566 | return NULL; | |
567 | } | |
568 | ||
569 | cur_base = ofputil_protocol_to_base(current); | |
570 | want_base = ofputil_protocol_to_base(want); | |
571 | if (cur_base != want_base) { | |
572 | *next = ofputil_protocol_set_base(current, want_base); | |
0d71302e BP |
573 | switch (want_base) { |
574 | case OFPUTIL_P_OF10_NXM: | |
0d71302e | 575 | case OFPUTIL_P_OF10_STD: |
225c33ba | 576 | return ofputil_encode_nx_set_flow_format(want_base); |
0d71302e BP |
577 | |
578 | case OFPUTIL_P_OF11_STD: | |
579 | case OFPUTIL_P_OF12_OXM: | |
580 | case OFPUTIL_P_OF13_OXM: | |
581 | case OFPUTIL_P_OF14_OXM: | |
582 | case OFPUTIL_P_OF15_OXM: | |
0d71302e BP |
583 | /* There is only one variant of each OpenFlow 1.1+ protocol, and we |
584 | * verified above that we're not trying to change versions. */ | |
585 | OVS_NOT_REACHED(); | |
586 | ||
587 | case OFPUTIL_P_OF10_STD_TID: | |
588 | case OFPUTIL_P_OF10_NXM_TID: | |
589 | OVS_NOT_REACHED(); | |
590 | } | |
591 | } | |
592 | ||
593 | cur_tid = (current & OFPUTIL_P_TID) != 0; | |
594 | want_tid = (want & OFPUTIL_P_TID) != 0; | |
595 | if (cur_tid != want_tid) { | |
596 | *next = ofputil_protocol_set_tid(current, want_tid); | |
225c33ba | 597 | return ofputil_encode_nx_flow_mod_table_id(want_tid); |
0d71302e BP |
598 | } |
599 | ||
600 | ovs_assert(current == want); | |
601 | ||
602 | *next = current; | |
603 | return NULL; | |
604 | } | |
225c33ba BP |
605 | \f |
606 | enum nx_flow_format { | |
607 | NXFF_OPENFLOW10 = 0, /* Standard OpenFlow 1.0 compatible. */ | |
608 | NXFF_NXM = 2 /* Nicira extended match. */ | |
609 | }; | |
610 | ||
611 | /* Returns an NXT_SET_FLOW_FORMAT message that can be used to set the flow | |
612 | * format to 'protocol'. */ | |
613 | struct ofpbuf * | |
614 | ofputil_encode_nx_set_flow_format(enum ofputil_protocol protocol) | |
615 | { | |
616 | struct ofpbuf *msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, | |
617 | OFP10_VERSION, 0); | |
618 | ovs_be32 *nxff = ofpbuf_put_uninit(msg, sizeof *nxff); | |
619 | if (protocol == OFPUTIL_P_OF10_STD) { | |
620 | *nxff = htonl(NXFF_OPENFLOW10); | |
621 | } else if (protocol == OFPUTIL_P_OF10_NXM) { | |
622 | *nxff = htonl(NXFF_NXM); | |
623 | } else { | |
624 | OVS_NOT_REACHED(); | |
625 | } | |
626 | ||
627 | return msg; | |
628 | } | |
629 | ||
630 | /* Returns the protocol specified in the NXT_SET_FLOW_FORMAT message at 'oh' | |
631 | * (either OFPUTIL_P_OF10_STD or OFPUTIL_P_OF10_NXM) or 0 if the message is | |
632 | * invalid. */ | |
633 | enum ofputil_protocol | |
634 | ofputil_decode_nx_set_flow_format(const struct ofp_header *oh) | |
635 | { | |
636 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); | |
637 | ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_SET_FLOW_FORMAT); | |
638 | ||
639 | ovs_be32 *flow_formatp = ofpbuf_pull(&b, sizeof *flow_formatp); | |
640 | uint32_t flow_format = ntohl(*flow_formatp); | |
641 | switch (flow_format) { | |
642 | case NXFF_OPENFLOW10: | |
643 | return OFPUTIL_P_OF10_STD; | |
644 | ||
645 | case NXFF_NXM: | |
646 | return OFPUTIL_P_OF10_NXM; | |
647 | ||
648 | default: | |
649 | VLOG_WARN_RL(&rl, "NXT_SET_FLOW_FORMAT message specified invalid " | |
650 | "flow format %"PRIu32, flow_format); | |
651 | return 0; | |
652 | } | |
653 | } | |
654 | \f | |
655 | /* These functions work with the Open vSwitch extension feature called | |
656 | * "flow_mod_table_id", which allows a controller to specify the OpenFlow table | |
657 | * to which a flow should be added, instead of having the switch decide which | |
658 | * table is most appropriate as required by OpenFlow 1.0. Because NXM was | |
659 | * designed as an extension to OpenFlow 1.0, the extension applies equally to | |
660 | * ofp10_flow_mod and nx_flow_mod. By default, the extension is disabled. | |
661 | * | |
662 | * When this feature is enabled, Open vSwitch treats struct ofp10_flow_mod's | |
663 | * and struct nx_flow_mod's 16-bit 'command' member as two separate fields. | |
664 | * The upper 8 bits are used as the table ID, the lower 8 bits specify the | |
665 | * command as usual. A table ID of 0xff is treated like a wildcarded table ID. | |
666 | * | |
667 | * The specific treatment of the table ID depends on the type of flow mod: | |
668 | * | |
669 | * - OFPFC_ADD: Given a specific table ID, the flow is always placed in that | |
670 | * table. If an identical flow already exists in that table only, then it | |
671 | * is replaced. If the flow cannot be placed in the specified table, | |
672 | * either because the table is full or because the table cannot support | |
673 | * flows of the given type, the switch replies with an OFPFMFC_TABLE_FULL | |
674 | * error. (A controller can distinguish these cases by comparing the | |
675 | * current and maximum number of entries reported in ofp_table_stats.) | |
676 | * | |
677 | * If the table ID is wildcarded, the switch picks an appropriate table | |
678 | * itself. If an identical flow already exist in the selected flow table, | |
679 | * then it is replaced. The choice of table might depend on the flows | |
680 | * that are already in the switch; for example, if one table fills up then | |
681 | * the switch might fall back to another one. | |
682 | * | |
683 | * - OFPFC_MODIFY, OFPFC_DELETE: Given a specific table ID, only flows | |
684 | * within that table are matched and modified or deleted. If the table ID | |
685 | * is wildcarded, flows within any table may be matched and modified or | |
686 | * deleted. | |
687 | * | |
688 | * - OFPFC_MODIFY_STRICT, OFPFC_DELETE_STRICT: Given a specific table ID, | |
689 | * only a flow within that table may be matched and modified or deleted. | |
690 | * If the table ID is wildcarded and exactly one flow within any table | |
691 | * matches, then it is modified or deleted; if flows in more than one | |
692 | * table match, then none is modified or deleted. | |
693 | */ | |
694 | ||
695 | /* Returns an OpenFlow message that can be used to turn the flow_mod_table_id | |
696 | * extension on or off (according to 'enable'). */ | |
697 | struct ofpbuf * | |
698 | ofputil_encode_nx_flow_mod_table_id(bool enable) | |
699 | { | |
700 | struct ofpbuf *msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD_TABLE_ID, | |
701 | OFP10_VERSION, 0); | |
702 | uint8_t *p = ofpbuf_put_zeros(msg, 8); | |
703 | *p = enable; | |
704 | return msg; | |
705 | } | |
706 | ||
707 | /* Decodes the NXT_FLOW_MOD_TABLE_ID message at 'oh'. Returns the message's | |
708 | * argument, that is, whether the flow_mod_table_id feature should be | |
709 | * enabled. */ | |
710 | bool | |
711 | ofputil_decode_nx_flow_mod_table_id(const struct ofp_header *oh) | |
712 | { | |
713 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); | |
714 | ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_FLOW_MOD_TABLE_ID); | |
715 | uint8_t *enable = ofpbuf_pull(&b, 8); | |
716 | return *enable != 0; | |
717 | } |