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