/src/openvswitch/lib/ofp-protocol.c
Line | Count | Source (jump to first uncovered line) |
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" |
22 | | #include "openvswitch/ofp-msgs.h" |
23 | | #include "openvswitch/ofpbuf.h" |
24 | | #include "openvswitch/vlog.h" |
25 | | #include "util.h" |
26 | | |
27 | | VLOG_DEFINE_THIS_MODULE(ofp_protocol); |
28 | | |
29 | | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); |
30 | | |
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 | 0 | #define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs) |
47 | | |
48 | | enum ofputil_protocol ofputil_flow_dump_protocols[] = { |
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 | 0 | { |
66 | 0 | switch (version) { |
67 | 0 | case OFP10_VERSION: |
68 | 0 | return OFPUTIL_P_OF10_STD_ANY | OFPUTIL_P_OF10_NXM_ANY; |
69 | 0 | case OFP11_VERSION: |
70 | 0 | return OFPUTIL_P_OF11_STD; |
71 | 0 | case OFP12_VERSION: |
72 | 0 | return OFPUTIL_P_OF12_OXM; |
73 | 0 | case OFP13_VERSION: |
74 | 0 | return OFPUTIL_P_OF13_OXM; |
75 | 0 | case OFP14_VERSION: |
76 | 0 | return OFPUTIL_P_OF14_OXM; |
77 | 0 | case OFP15_VERSION: |
78 | 0 | return OFPUTIL_P_OF15_OXM; |
79 | 0 | default: |
80 | 0 | return 0; |
81 | 0 | } |
82 | 0 | } |
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 | 0 | { |
92 | 0 | return rightmost_1bit(ofputil_protocols_from_ofp_version(version)); |
93 | 0 | } |
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 | 0 | { |
100 | 0 | switch (protocol) { |
101 | 0 | case OFPUTIL_P_OF10_STD: |
102 | 0 | case OFPUTIL_P_OF10_STD_TID: |
103 | 0 | case OFPUTIL_P_OF10_NXM: |
104 | 0 | case OFPUTIL_P_OF10_NXM_TID: |
105 | 0 | return OFP10_VERSION; |
106 | 0 | case OFPUTIL_P_OF11_STD: |
107 | 0 | return OFP11_VERSION; |
108 | 0 | case OFPUTIL_P_OF12_OXM: |
109 | 0 | return OFP12_VERSION; |
110 | 0 | case OFPUTIL_P_OF13_OXM: |
111 | 0 | return OFP13_VERSION; |
112 | 0 | case OFPUTIL_P_OF14_OXM: |
113 | 0 | return OFP14_VERSION; |
114 | 0 | case OFPUTIL_P_OF15_OXM: |
115 | 0 | return OFP15_VERSION; |
116 | 0 | } |
117 | | |
118 | 0 | OVS_NOT_REACHED(); |
119 | 0 | } |
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 | 0 | { |
126 | 0 | uint32_t bitmap = 0; |
127 | |
|
128 | 0 | for (; protocols; protocols = zero_rightmost_1bit(protocols)) { |
129 | 0 | enum ofputil_protocol protocol = rightmost_1bit(protocols); |
130 | |
|
131 | 0 | bitmap |= 1u << ofputil_protocol_to_ofp_version(protocol); |
132 | 0 | } |
133 | |
|
134 | 0 | return bitmap; |
135 | 0 | } |
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 | 0 | { |
142 | 0 | enum ofputil_protocol protocols = 0; |
143 | |
|
144 | 0 | for (; bitmap; bitmap = zero_rightmost_1bit(bitmap)) { |
145 | 0 | enum ofp_version version = rightmost_1bit_idx(bitmap); |
146 | |
|
147 | 0 | protocols |= ofputil_protocols_from_ofp_version(version); |
148 | 0 | } |
149 | |
|
150 | 0 | return protocols; |
151 | 0 | } |
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 | 0 | { |
158 | 0 | return protocol & OFPUTIL_P_ANY && is_pow2(protocol); |
159 | 0 | } |
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 | 0 | { |
174 | 0 | switch (protocol) { |
175 | 0 | case OFPUTIL_P_OF10_STD: |
176 | 0 | case OFPUTIL_P_OF10_STD_TID: |
177 | 0 | return enable ? OFPUTIL_P_OF10_STD_TID : OFPUTIL_P_OF10_STD; |
178 | | |
179 | 0 | case OFPUTIL_P_OF10_NXM: |
180 | 0 | case OFPUTIL_P_OF10_NXM_TID: |
181 | 0 | return enable ? OFPUTIL_P_OF10_NXM_TID : OFPUTIL_P_OF10_NXM; |
182 | | |
183 | 0 | case OFPUTIL_P_OF11_STD: |
184 | 0 | return OFPUTIL_P_OF11_STD; |
185 | | |
186 | 0 | case OFPUTIL_P_OF12_OXM: |
187 | 0 | return OFPUTIL_P_OF12_OXM; |
188 | | |
189 | 0 | case OFPUTIL_P_OF13_OXM: |
190 | 0 | return OFPUTIL_P_OF13_OXM; |
191 | | |
192 | 0 | case OFPUTIL_P_OF14_OXM: |
193 | 0 | return OFPUTIL_P_OF14_OXM; |
194 | | |
195 | 0 | case OFPUTIL_P_OF15_OXM: |
196 | 0 | return OFPUTIL_P_OF15_OXM; |
197 | | |
198 | 0 | default: |
199 | 0 | OVS_NOT_REACHED(); |
200 | 0 | } |
201 | 0 | } |
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 | 0 | { |
210 | 0 | return ofputil_protocol_set_tid(protocol, false); |
211 | 0 | } |
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 | 0 | { |
218 | 0 | bool tid = (cur & OFPUTIL_P_TID) != 0; |
219 | |
|
220 | 0 | switch (new_base) { |
221 | 0 | case OFPUTIL_P_OF10_STD: |
222 | 0 | case OFPUTIL_P_OF10_STD_TID: |
223 | 0 | return ofputil_protocol_set_tid(OFPUTIL_P_OF10_STD, tid); |
224 | | |
225 | 0 | case OFPUTIL_P_OF10_NXM: |
226 | 0 | case OFPUTIL_P_OF10_NXM_TID: |
227 | 0 | return ofputil_protocol_set_tid(OFPUTIL_P_OF10_NXM, tid); |
228 | | |
229 | 0 | case OFPUTIL_P_OF11_STD: |
230 | 0 | return ofputil_protocol_set_tid(OFPUTIL_P_OF11_STD, tid); |
231 | | |
232 | 0 | case OFPUTIL_P_OF12_OXM: |
233 | 0 | return ofputil_protocol_set_tid(OFPUTIL_P_OF12_OXM, tid); |
234 | | |
235 | 0 | case OFPUTIL_P_OF13_OXM: |
236 | 0 | return ofputil_protocol_set_tid(OFPUTIL_P_OF13_OXM, tid); |
237 | | |
238 | 0 | case OFPUTIL_P_OF14_OXM: |
239 | 0 | return ofputil_protocol_set_tid(OFPUTIL_P_OF14_OXM, tid); |
240 | | |
241 | 0 | case OFPUTIL_P_OF15_OXM: |
242 | 0 | return ofputil_protocol_set_tid(OFPUTIL_P_OF15_OXM, tid); |
243 | | |
244 | 0 | default: |
245 | 0 | OVS_NOT_REACHED(); |
246 | 0 | } |
247 | 0 | } |
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 | 0 | { |
255 | 0 | 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 | 0 | switch (protocol) { |
260 | 0 | case OFPUTIL_P_OF10_NXM: |
261 | 0 | return "NXM-table_id"; |
262 | | |
263 | 0 | case OFPUTIL_P_OF10_NXM_TID: |
264 | 0 | return "NXM+table_id"; |
265 | | |
266 | 0 | case OFPUTIL_P_OF10_STD: |
267 | 0 | return "OpenFlow10-table_id"; |
268 | | |
269 | 0 | case OFPUTIL_P_OF10_STD_TID: |
270 | 0 | return "OpenFlow10+table_id"; |
271 | | |
272 | 0 | case OFPUTIL_P_OF11_STD: |
273 | 0 | return "OpenFlow11"; |
274 | | |
275 | 0 | case OFPUTIL_P_OF12_OXM: |
276 | 0 | return "OXM-OpenFlow12"; |
277 | | |
278 | 0 | case OFPUTIL_P_OF13_OXM: |
279 | 0 | return "OXM-OpenFlow13"; |
280 | | |
281 | 0 | case OFPUTIL_P_OF14_OXM: |
282 | 0 | return "OXM-OpenFlow14"; |
283 | | |
284 | 0 | case OFPUTIL_P_OF15_OXM: |
285 | 0 | return "OXM-OpenFlow15"; |
286 | 0 | } |
287 | | |
288 | | /* Check abbreviations. */ |
289 | 0 | for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) { |
290 | 0 | if (protocol == p->protocol) { |
291 | 0 | return p->name; |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | 0 | return NULL; |
296 | 0 | } |
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 | 0 | { |
306 | 0 | struct ds s; |
307 | |
|
308 | 0 | ovs_assert(!(protocols & ~OFPUTIL_P_ANY)); |
309 | 0 | if (protocols == 0) { |
310 | 0 | return xstrdup("none"); |
311 | 0 | } |
312 | | |
313 | 0 | ds_init(&s); |
314 | 0 | while (protocols) { |
315 | 0 | const struct proto_abbrev *p; |
316 | 0 | int i; |
317 | |
|
318 | 0 | if (s.length) { |
319 | 0 | ds_put_char(&s, ','); |
320 | 0 | } |
321 | |
|
322 | 0 | for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) { |
323 | 0 | if ((protocols & p->protocol) == p->protocol) { |
324 | 0 | ds_put_cstr(&s, p->name); |
325 | 0 | protocols &= ~p->protocol; |
326 | 0 | goto match; |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | 0 | for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) { |
331 | 0 | enum ofputil_protocol bit = 1u << i; |
332 | |
|
333 | 0 | if (protocols & bit) { |
334 | 0 | ds_put_cstr(&s, ofputil_protocol_to_string(bit)); |
335 | 0 | protocols &= ~bit; |
336 | 0 | goto match; |
337 | 0 | } |
338 | 0 | } |
339 | 0 | OVS_NOT_REACHED(); |
340 | | |
341 | 0 | match: ; |
342 | 0 | } |
343 | 0 | return ds_steal_cstr(&s); |
344 | 0 | } |
345 | | |
346 | | static enum ofputil_protocol |
347 | | ofputil_protocol_from_string__(const char *s, size_t n) |
348 | 0 | { |
349 | 0 | const struct proto_abbrev *p; |
350 | 0 | int i; |
351 | |
|
352 | 0 | for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) { |
353 | 0 | enum ofputil_protocol bit = 1u << i; |
354 | 0 | const char *name = ofputil_protocol_to_string(bit); |
355 | |
|
356 | 0 | if (name && n == strlen(name) && !strncasecmp(s, name, n)) { |
357 | 0 | return bit; |
358 | 0 | } |
359 | 0 | } |
360 | | |
361 | 0 | for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) { |
362 | 0 | if (n == strlen(p->name) && !strncasecmp(s, p->name, n)) { |
363 | 0 | return p->protocol; |
364 | 0 | } |
365 | 0 | } |
366 | | |
367 | 0 | return 0; |
368 | 0 | } |
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 | 0 | { |
377 | 0 | const char *orig_s = s; |
378 | 0 | enum ofputil_protocol protocols; |
379 | |
|
380 | 0 | protocols = 0; |
381 | 0 | while (*s) { |
382 | 0 | enum ofputil_protocol p; |
383 | 0 | size_t n; |
384 | |
|
385 | 0 | n = strcspn(s, ","); |
386 | 0 | if (n == 0) { |
387 | 0 | s++; |
388 | 0 | continue; |
389 | 0 | } |
390 | | |
391 | 0 | p = ofputil_protocol_from_string__(s, n); |
392 | 0 | if (!p) { |
393 | 0 | ovs_fatal(0, "%.*s: unknown flow protocol", (int) n, s); |
394 | 0 | } |
395 | 0 | protocols |= p; |
396 | |
|
397 | 0 | s += n; |
398 | 0 | } |
399 | | |
400 | 0 | if (!protocols) { |
401 | 0 | ovs_fatal(0, "%s: no flow protocol specified", orig_s); |
402 | 0 | } |
403 | 0 | return protocols; |
404 | 0 | } |
405 | | |
406 | | enum ofp_version |
407 | | ofputil_version_from_string(const char *s) |
408 | 0 | { |
409 | 0 | if (!strcasecmp(s, "OpenFlow10")) { |
410 | 0 | return OFP10_VERSION; |
411 | 0 | } |
412 | 0 | if (!strcasecmp(s, "OpenFlow11")) { |
413 | 0 | return OFP11_VERSION; |
414 | 0 | } |
415 | 0 | if (!strcasecmp(s, "OpenFlow12")) { |
416 | 0 | return OFP12_VERSION; |
417 | 0 | } |
418 | 0 | if (!strcasecmp(s, "OpenFlow13")) { |
419 | 0 | return OFP13_VERSION; |
420 | 0 | } |
421 | 0 | if (!strcasecmp(s, "OpenFlow14")) { |
422 | 0 | return OFP14_VERSION; |
423 | 0 | } |
424 | 0 | if (!strcasecmp(s, "OpenFlow15")) { |
425 | 0 | return OFP15_VERSION; |
426 | 0 | } |
427 | 0 | return 0; |
428 | 0 | } |
429 | | |
430 | | static bool |
431 | | is_delimiter(unsigned char c) |
432 | 0 | { |
433 | 0 | return isspace(c) || c == ','; |
434 | 0 | } |
435 | | |
436 | | uint32_t |
437 | | ofputil_versions_from_string(const char *s) |
438 | 0 | { |
439 | 0 | size_t i = 0; |
440 | 0 | uint32_t bitmap = 0; |
441 | |
|
442 | 0 | while (s[i]) { |
443 | 0 | size_t j; |
444 | 0 | int version; |
445 | 0 | char *key; |
446 | |
|
447 | 0 | if (is_delimiter(s[i])) { |
448 | 0 | i++; |
449 | 0 | continue; |
450 | 0 | } |
451 | 0 | j = 0; |
452 | 0 | while (s[i + j] && !is_delimiter(s[i + j])) { |
453 | 0 | j++; |
454 | 0 | } |
455 | 0 | key = xmemdup0(s + i, j); |
456 | 0 | version = ofputil_version_from_string(key); |
457 | 0 | if (!version) { |
458 | 0 | VLOG_FATAL("Unknown OpenFlow version: \"%s\"", key); |
459 | 0 | } |
460 | 0 | free(key); |
461 | 0 | bitmap |= 1u << version; |
462 | 0 | i += j; |
463 | 0 | } |
464 | | |
465 | 0 | return bitmap; |
466 | 0 | } |
467 | | |
468 | | uint32_t |
469 | | ofputil_versions_from_strings(char ** const s, size_t count) |
470 | 0 | { |
471 | 0 | uint32_t bitmap = 0; |
472 | |
|
473 | 0 | while (count--) { |
474 | 0 | int version = ofputil_version_from_string(s[count]); |
475 | 0 | if (!version) { |
476 | 0 | VLOG_WARN("Unknown OpenFlow version: \"%s\"", s[count]); |
477 | 0 | } else { |
478 | 0 | bitmap |= 1u << version; |
479 | 0 | } |
480 | 0 | } |
481 | |
|
482 | 0 | return bitmap; |
483 | 0 | } |
484 | | |
485 | | const char * |
486 | | ofputil_version_to_string(enum ofp_version ofp_version) |
487 | 0 | { |
488 | 0 | switch (ofp_version) { |
489 | 0 | case OFP10_VERSION: |
490 | 0 | return "OpenFlow10"; |
491 | 0 | case OFP11_VERSION: |
492 | 0 | return "OpenFlow11"; |
493 | 0 | case OFP12_VERSION: |
494 | 0 | return "OpenFlow12"; |
495 | 0 | case OFP13_VERSION: |
496 | 0 | return "OpenFlow13"; |
497 | 0 | case OFP14_VERSION: |
498 | 0 | return "OpenFlow14"; |
499 | 0 | case OFP15_VERSION: |
500 | 0 | return "OpenFlow15"; |
501 | 0 | default: |
502 | 0 | OVS_NOT_REACHED(); |
503 | 0 | } |
504 | 0 | } |
505 | | |
506 | | void |
507 | | ofputil_format_version(struct ds *msg, enum ofp_version version) |
508 | 0 | { |
509 | 0 | ds_put_format(msg, "0x%02x", version); |
510 | 0 | } |
511 | | |
512 | | void |
513 | | ofputil_format_version_name(struct ds *msg, enum ofp_version version) |
514 | 0 | { |
515 | 0 | ds_put_cstr(msg, ofputil_version_to_string(version)); |
516 | 0 | } |
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 | 0 | { |
523 | 0 | while (bitmap) { |
524 | 0 | format_version(msg, raw_ctz(bitmap)); |
525 | 0 | bitmap = zero_rightmost_1bit(bitmap); |
526 | 0 | if (bitmap) { |
527 | 0 | ds_put_cstr(msg, ", "); |
528 | 0 | } |
529 | 0 | } |
530 | 0 | } |
531 | | |
532 | | void |
533 | | ofputil_format_version_bitmap(struct ds *msg, uint32_t bitmap) |
534 | 0 | { |
535 | 0 | ofputil_format_version_bitmap__(msg, bitmap, ofputil_format_version); |
536 | 0 | } |
537 | | |
538 | | void |
539 | | ofputil_format_version_bitmap_names(struct ds *msg, uint32_t bitmap) |
540 | 0 | { |
541 | 0 | ofputil_format_version_bitmap__(msg, bitmap, ofputil_format_version_name); |
542 | 0 | } |
543 | | |
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 | 0 | { |
558 | 0 | enum ofp_version cur_version, want_version; |
559 | 0 | enum ofputil_protocol cur_base, want_base; |
560 | 0 | bool cur_tid, want_tid; |
561 | |
|
562 | 0 | cur_version = ofputil_protocol_to_ofp_version(current); |
563 | 0 | want_version = ofputil_protocol_to_ofp_version(want); |
564 | 0 | if (cur_version != want_version) { |
565 | 0 | *next = current; |
566 | 0 | return NULL; |
567 | 0 | } |
568 | | |
569 | 0 | cur_base = ofputil_protocol_to_base(current); |
570 | 0 | want_base = ofputil_protocol_to_base(want); |
571 | 0 | if (cur_base != want_base) { |
572 | 0 | *next = ofputil_protocol_set_base(current, want_base); |
573 | 0 | switch (want_base) { |
574 | 0 | case OFPUTIL_P_OF10_NXM: |
575 | 0 | case OFPUTIL_P_OF10_STD: |
576 | 0 | return ofputil_encode_nx_set_flow_format(want_base); |
577 | | |
578 | 0 | case OFPUTIL_P_OF11_STD: |
579 | 0 | case OFPUTIL_P_OF12_OXM: |
580 | 0 | case OFPUTIL_P_OF13_OXM: |
581 | 0 | case OFPUTIL_P_OF14_OXM: |
582 | 0 | case OFPUTIL_P_OF15_OXM: |
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 | 0 | OVS_NOT_REACHED(); |
586 | | |
587 | 0 | case OFPUTIL_P_OF10_STD_TID: |
588 | 0 | case OFPUTIL_P_OF10_NXM_TID: |
589 | 0 | OVS_NOT_REACHED(); |
590 | 0 | } |
591 | 0 | } |
592 | | |
593 | 0 | cur_tid = (current & OFPUTIL_P_TID) != 0; |
594 | 0 | want_tid = (want & OFPUTIL_P_TID) != 0; |
595 | 0 | if (cur_tid != want_tid) { |
596 | 0 | *next = ofputil_protocol_set_tid(current, want_tid); |
597 | 0 | return ofputil_encode_nx_flow_mod_table_id(want_tid); |
598 | 0 | } |
599 | | |
600 | 0 | ovs_assert(current == want); |
601 | |
|
602 | 0 | *next = current; |
603 | 0 | return NULL; |
604 | 0 | } |
605 | | |
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 | 0 | { |
616 | 0 | struct ofpbuf *msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, |
617 | 0 | OFP10_VERSION, 0); |
618 | 0 | ovs_be32 *nxff = ofpbuf_put_uninit(msg, sizeof *nxff); |
619 | 0 | if (protocol == OFPUTIL_P_OF10_STD) { |
620 | 0 | *nxff = htonl(NXFF_OPENFLOW10); |
621 | 0 | } else if (protocol == OFPUTIL_P_OF10_NXM) { |
622 | 0 | *nxff = htonl(NXFF_NXM); |
623 | 0 | } else { |
624 | 0 | OVS_NOT_REACHED(); |
625 | 0 | } |
626 | | |
627 | 0 | return msg; |
628 | 0 | } |
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 | 0 | { |
636 | 0 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
637 | 0 | ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_SET_FLOW_FORMAT); |
638 | |
|
639 | 0 | ovs_be32 *flow_formatp = ofpbuf_pull(&b, sizeof *flow_formatp); |
640 | 0 | uint32_t flow_format = ntohl(*flow_formatp); |
641 | 0 | switch (flow_format) { |
642 | 0 | case NXFF_OPENFLOW10: |
643 | 0 | return OFPUTIL_P_OF10_STD; |
644 | | |
645 | 0 | case NXFF_NXM: |
646 | 0 | return OFPUTIL_P_OF10_NXM; |
647 | | |
648 | 0 | default: |
649 | 0 | VLOG_WARN_RL(&rl, "NXT_SET_FLOW_FORMAT message specified invalid " |
650 | 0 | "flow format %"PRIu32, flow_format); |
651 | 0 | return 0; |
652 | 0 | } |
653 | 0 | } |
654 | | |
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 | 0 | { |
700 | 0 | struct ofpbuf *msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD_TABLE_ID, |
701 | 0 | OFP10_VERSION, 0); |
702 | 0 | uint8_t *p = ofpbuf_put_zeros(msg, 8); |
703 | 0 | *p = enable; |
704 | 0 | return msg; |
705 | 0 | } |
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 | 0 | { |
713 | 0 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
714 | 0 | ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_FLOW_MOD_TABLE_ID); |
715 | 0 | uint8_t *enable = ofpbuf_pull(&b, 8); |
716 | 0 | return *enable != 0; |
717 | 0 | } |