2 * Copyright (c) 2008-2017 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "openvswitch/ofp-table.h"
21 #include "openvswitch/dynamic-string.h"
22 #include "openvswitch/json.h"
23 #include "openvswitch/ofp-actions.h"
24 #include "openvswitch/ofp-msgs.h"
25 #include "openvswitch/ofp-print.h"
26 #include "openvswitch/ofp-prop.h"
27 #include "openvswitch/ofpbuf.h"
28 #include "openvswitch/vlog.h"
31 VLOG_DEFINE_THIS_MODULE(ofp_table
);
33 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
35 static ovs_be32
ofputil_encode_table_config(enum ofputil_table_miss
,
36 enum ofputil_table_eviction
,
37 enum ofputil_table_vacancy
,
39 static enum ofputil_table_vacancy
ofputil_decode_table_vacancy(
40 ovs_be32 config
, enum ofp_version
);
41 static enum ofputil_table_eviction
ofputil_decode_table_eviction(
42 ovs_be32 config
, enum ofp_version
);
45 ofputil_table_miss_to_string(enum ofputil_table_miss miss
)
48 case OFPUTIL_TABLE_MISS_DEFAULT
: return "default";
49 case OFPUTIL_TABLE_MISS_CONTROLLER
: return "controller";
50 case OFPUTIL_TABLE_MISS_CONTINUE
: return "continue";
51 case OFPUTIL_TABLE_MISS_DROP
: return "drop";
52 default: return "***error***";
57 ofputil_table_eviction_to_string(enum ofputil_table_eviction eviction
)
60 case OFPUTIL_TABLE_EVICTION_DEFAULT
: return "default";
61 case OFPUTIL_TABLE_EVICTION_ON
: return "on";
62 case OFPUTIL_TABLE_EVICTION_OFF
: return "off";
63 default: return "***error***";
68 ofputil_table_vacancy_to_string(enum ofputil_table_vacancy vacancy
)
71 case OFPUTIL_TABLE_VACANCY_DEFAULT
: return "default";
72 case OFPUTIL_TABLE_VACANCY_ON
: return "on";
73 case OFPUTIL_TABLE_VACANCY_OFF
: return "off";
74 default: return "***error***";
79 ofp15_table_features_command_is_valid(enum ofp15_table_features_command cmd
)
82 case OFPTFC15_REPLACE
:
85 case OFPTFC15_DISABLE
:
94 ofp15_table_features_command_to_string(enum ofp15_table_features_command cmd
)
97 case OFPTFC15_REPLACE
: return "replace";
98 case OFPTFC15_MODIFY
: return "modify";
99 case OFPTFC15_ENABLE
: return "enable";
100 case OFPTFC15_DISABLE
: return "disable";
101 default: return "***bad command***";
105 /* ofputil_table_map. */
108 ofputil_table_map_init(struct ofputil_table_map
*map
)
110 namemap_init(&map
->map
);
114 ofputil_table_map_put(struct ofputil_table_map
*map
,
115 uint8_t table_id
, const char *name
)
117 namemap_put(&map
->map
, table_id
, name
);
121 ofputil_table_map_get_name(const struct ofputil_table_map
*map
,
124 struct namemap_node
*node
125 = map
? namemap_find_by_number(&map
->map
, table_id
) : NULL
;
126 return node
&& !node
->duplicate
? node
->name
: NULL
;
130 ofputil_table_map_get_number(const struct ofputil_table_map
*map
,
133 struct namemap_node
*node
134 = map
? namemap_find_by_name(&map
->map
, name
) : NULL
;
135 return node
&& !node
->duplicate
? node
->number
: UINT8_MAX
;
139 ofputil_table_map_destroy(struct ofputil_table_map
*map
)
141 namemap_destroy(&map
->map
);
146 /* Stores the table number represented by 's' into '*tablep'. 's' may be an
147 * integer or, if 'table_map' is nonnull, a name (quoted or unquoted).
149 * Returns true if successful, false if 's' is not a valid OpenFlow table
150 * number or name. The caller should issue an error message in this case,
151 * because this function usually does not. (This gives the caller an
152 * opportunity to look up the table name another way, e.g. by contacting the
153 * switch and listing the names of all its tables). */
155 ofputil_table_from_string(const char *s
,
156 const struct ofputil_table_map
*table_map
,
161 VLOG_WARN("Negative value %s is not a valid table number.", s
);
166 if (str_to_uint(s
, 10, &table
)) {
168 VLOG_WARN("table %u is outside the supported range 0 through 255",
176 table
= ofputil_table_map_get_number(table_map
, s
);
178 size_t length
= strlen(s
);
181 && s
[length
- 1] == '"'
182 && json_string_unescape(s
+ 1, length
- 2, &name
)) {
183 table
= ofputil_table_map_get_number(table_map
, name
);
187 if (table
!= UINT8_MAX
) {
196 /* Appends to 's' a string representation of the OpenFlow table number 'table',
197 * either the table number or a name drawn from 'table_map'. */
199 ofputil_format_table(uint8_t table
, const struct ofputil_table_map
*table_map
,
202 const char *table_name
= ofputil_table_map_get_name(table_map
, table
);
204 namemap_put_name(table_name
, s
);
206 ds_put_format(s
, "%"PRIu8
, table
);
210 /* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
211 * representation of OpenFlow table number 'table', either the table's number
212 * or a name drawn from 'table_map'. */
214 ofputil_table_to_string(uint8_t table
,
215 const struct ofputil_table_map
*table_map
,
216 char *namebuf
, size_t bufsize
)
218 const char *table_name
= ofputil_table_map_get_name(table_map
, table
);
220 struct ds s
= DS_EMPTY_INITIALIZER
;
221 namemap_put_name(table_name
, &s
);
222 ovs_strlcpy(namebuf
, ds_cstr(&s
), bufsize
);
227 snprintf(namebuf
, bufsize
, "%"PRIu8
, table
);
230 /* Table features. */
233 pull_table_feature_property(struct ofpbuf
*msg
, struct ofpbuf
*payload
,
238 error
= ofpprop_pull(msg
, payload
, typep
);
239 if (payload
&& !error
) {
240 ofpbuf_pull(payload
, (char *)payload
->msg
- (char *)payload
->header
);
246 parse_action_bitmap(struct ofpbuf
*payload
, enum ofp_version ofp_version
,
251 while (payload
->size
> 0) {
255 error
= ofpprop_pull__(payload
, NULL
, 1, 0x10000, &type
);
259 if (type
< CHAR_BIT
* sizeof types
) {
264 *ofpacts
= ofpact_bitmap_from_openflow(htonl(types
), ofp_version
);
269 parse_instruction_ids(struct ofpbuf
*payload
, bool loose
, uint32_t *insts
)
272 while (payload
->size
> 0) {
273 enum ovs_instruction_type inst
;
277 /* OF1.3 and OF1.4 aren't clear about padding in the instruction IDs.
278 * It seems clear that they aren't padded to 8 bytes, though, because
279 * both standards say that "non-experimenter instructions are 4 bytes"
280 * and do not mention any padding before the first instruction ID.
281 * (There wouldn't be any point in padding to 8 bytes if the IDs were
282 * aligned on an odd 4-byte boundary.)
284 * Anyway, we just assume they're all glommed together on byte
286 error
= ofpprop_pull__(payload
, NULL
, 1, 0x10000, &ofpit
);
291 error
= ovs_instruction_type_from_inst_type(&inst
, ofpit
);
293 *insts
|= 1u << inst
;
302 parse_table_features_next_table(struct ofpbuf
*payload
,
303 unsigned long int *next_tables
)
307 memset(next_tables
, 0, bitmap_n_bytes(255));
308 for (i
= 0; i
< payload
->size
; i
++) {
309 uint8_t id
= ((const uint8_t *) payload
->data
)[i
];
311 return OFPERR_OFPBPC_BAD_VALUE
;
313 bitmap_set1(next_tables
, id
);
319 parse_oxms(struct ofpbuf
*payload
, bool loose
,
320 struct mf_bitmap
*exactp
, struct mf_bitmap
*maskedp
)
322 struct mf_bitmap exact
= MF_BITMAP_INITIALIZER
;
323 struct mf_bitmap masked
= MF_BITMAP_INITIALIZER
;
325 while (payload
->size
> 0) {
326 const struct mf_field
*field
;
330 error
= nx_pull_header(payload
, NULL
, &field
, &hasmask
);
332 bitmap_set1(hasmask
? masked
.bm
: exact
.bm
, field
->id
);
333 } else if (error
!= OFPERR_OFPBMC_BAD_FIELD
|| !loose
) {
339 } else if (!bitmap_is_all_zeros(exact
.bm
, MFF_N_IDS
)) {
340 return OFPERR_OFPBMC_BAD_MASK
;
344 } else if (!bitmap_is_all_zeros(masked
.bm
, MFF_N_IDS
)) {
345 return OFPERR_OFPBMC_BAD_MASK
;
350 /* Converts an OFPMP_TABLE_FEATURES request or reply in 'msg' into an abstract
351 * ofputil_table_features in 'tf'.
353 * If 'raw_properties' is nonnull, this function ignores properties and values
354 * that it does not understand, as a controller would want to do when
355 * interpreting capabilities provided by a switch. In this mode, on success,
356 * it initializes 'raw_properties' to contain the properties that were parsed;
357 * this allows the caller to later re-serialize the same properties without
360 * If 'raw_properties' is null, this function treats unknown properties and
361 * values as an error, as a switch would want to do when interpreting a
362 * configuration request made by a controller.
364 * A single OpenFlow message can specify features for multiple tables. Calling
365 * this function multiple times for a single 'msg' iterates through the tables
366 * in the message. The caller must initially leave 'msg''s layer pointers null
367 * and not modify them between calls.
369 * Returns 0 if successful, EOF if no tables were left in this 'msg', otherwise
370 * a positive "enum ofperr" value. */
372 ofputil_decode_table_features(struct ofpbuf
*msg
,
373 struct ofputil_table_features
*tf
,
374 struct ofpbuf
*raw_properties
)
376 bool loose
= raw_properties
!= NULL
;
378 memset(tf
, 0, sizeof *tf
);
381 ofpraw_pull_assert(msg
);
388 const struct ofp_header
*oh
= msg
->header
;
389 struct ofp13_table_features
*otf
= msg
->data
;
390 if (msg
->size
< sizeof *otf
) {
391 return OFPERR_OFPBPC_BAD_LEN
;
394 unsigned int len
= ntohs(otf
->length
);
395 if (len
< sizeof *otf
|| len
% 8 || len
> msg
->size
) {
396 return OFPERR_OFPBPC_BAD_LEN
;
399 if (oh
->version
>= OFP15_VERSION
) {
400 if (!ofp15_table_features_command_is_valid(otf
->command
)) {
401 return OFPERR_OFPTFFC_BAD_COMMAND
;
403 tf
->command
= otf
->command
;
405 tf
->command
= OFPTFC15_REPLACE
;
408 tf
->table_id
= otf
->table_id
;
409 if (tf
->table_id
== OFPTT_ALL
) {
410 return OFPERR_OFPTFFC_BAD_TABLE
;
413 ovs_strlcpy_arrays(tf
->name
, otf
->name
);
414 tf
->metadata_match
= otf
->metadata_match
;
415 tf
->metadata_write
= otf
->metadata_write
;
416 tf
->miss_config
= OFPUTIL_TABLE_MISS_DEFAULT
;
417 if (oh
->version
>= OFP14_VERSION
) {
418 uint32_t caps
= ntohl(otf
->capabilities
);
419 tf
->supports_eviction
= (caps
& OFPTC14_EVICTION
) != 0;
420 tf
->supports_vacancy_events
= (caps
& OFPTC14_VACANCY_EVENTS
) != 0;
422 tf
->supports_eviction
= -1;
423 tf
->supports_vacancy_events
= -1;
425 tf
->max_entries
= ntohl(otf
->max_entries
);
427 struct ofpbuf properties
= ofpbuf_const_initializer(ofpbuf_pull(msg
, len
),
429 ofpbuf_pull(&properties
, sizeof *otf
);
430 tf
->any_properties
= properties
.size
> 0;
431 if (raw_properties
) {
432 *raw_properties
= properties
;
435 while (properties
.size
> 0) {
436 struct ofpbuf payload
;
440 error
= pull_table_feature_property(&properties
, &payload
, &type
);
446 uint32_t bit
= 1u << type
;
448 return OFPERR_OFPTFFC_BAD_FEATURES
;
453 switch ((enum ofp13_table_feature_prop_type
) type
) {
454 case OFPTFPT13_INSTRUCTIONS
:
455 error
= parse_instruction_ids(&payload
, loose
,
456 &tf
->nonmiss
.instructions
);
458 case OFPTFPT13_INSTRUCTIONS_MISS
:
459 error
= parse_instruction_ids(&payload
, loose
,
460 &tf
->miss
.instructions
);
463 case OFPTFPT13_NEXT_TABLES
:
464 error
= parse_table_features_next_table(&payload
,
467 case OFPTFPT13_NEXT_TABLES_MISS
:
468 error
= parse_table_features_next_table(&payload
, tf
->miss
.next
);
471 case OFPTFPT13_WRITE_ACTIONS
:
472 error
= parse_action_bitmap(&payload
, oh
->version
,
473 &tf
->nonmiss
.write
.ofpacts
);
475 case OFPTFPT13_WRITE_ACTIONS_MISS
:
476 error
= parse_action_bitmap(&payload
, oh
->version
,
477 &tf
->miss
.write
.ofpacts
);
480 case OFPTFPT13_APPLY_ACTIONS
:
481 error
= parse_action_bitmap(&payload
, oh
->version
,
482 &tf
->nonmiss
.apply
.ofpacts
);
484 case OFPTFPT13_APPLY_ACTIONS_MISS
:
485 error
= parse_action_bitmap(&payload
, oh
->version
,
486 &tf
->miss
.apply
.ofpacts
);
489 case OFPTFPT13_MATCH
:
490 error
= parse_oxms(&payload
, loose
, &tf
->match
, &tf
->mask
);
492 case OFPTFPT13_WILDCARDS
:
493 error
= parse_oxms(&payload
, loose
, &tf
->wildcard
, NULL
);
496 case OFPTFPT13_WRITE_SETFIELD
:
497 error
= parse_oxms(&payload
, loose
,
498 &tf
->nonmiss
.write
.set_fields
, NULL
);
500 case OFPTFPT13_WRITE_SETFIELD_MISS
:
501 error
= parse_oxms(&payload
, loose
,
502 &tf
->miss
.write
.set_fields
, NULL
);
504 case OFPTFPT13_APPLY_SETFIELD
:
505 error
= parse_oxms(&payload
, loose
,
506 &tf
->nonmiss
.apply
.set_fields
, NULL
);
508 case OFPTFPT13_APPLY_SETFIELD_MISS
:
509 error
= parse_oxms(&payload
, loose
,
510 &tf
->miss
.apply
.set_fields
, NULL
);
513 case OFPTFPT13_EXPERIMENTER
:
514 case OFPTFPT13_EXPERIMENTER_MISS
:
516 error
= OFPPROP_UNKNOWN(loose
, "table features", type
);
524 /* OpenFlow 1.3 and 1.4 always require all of the required properties.
525 * OpenFlow 1.5 requires all of them if any property is present. */
526 if ((seen
& OFPTFPT13_REQUIRED
) != OFPTFPT13_REQUIRED
527 && (tf
->any_properties
|| oh
->version
< OFP15_VERSION
)) {
528 VLOG_WARN_RL(&rl
, "table features message missing required property");
529 return OFPERR_OFPTFFC_BAD_FEATURES
;
532 /* Copy nonmiss to miss when appropriate. */
533 if (tf
->any_properties
) {
534 if (!(seen
& (1u << OFPTFPT13_INSTRUCTIONS_MISS
))) {
535 tf
->miss
.instructions
= tf
->nonmiss
.instructions
;
537 if (!(seen
& (1u << OFPTFPT13_NEXT_TABLES_MISS
))) {
538 memcpy(tf
->miss
.next
, tf
->nonmiss
.next
, sizeof tf
->miss
.next
);
540 if (!(seen
& (1u << OFPTFPT13_WRITE_ACTIONS_MISS
))) {
541 tf
->miss
.write
.ofpacts
= tf
->nonmiss
.write
.ofpacts
;
543 if (!(seen
& (1u << OFPTFPT13_APPLY_ACTIONS_MISS
))) {
544 tf
->miss
.apply
.ofpacts
= tf
->nonmiss
.apply
.ofpacts
;
546 if (!(seen
& (1u << OFPTFPT13_WRITE_SETFIELD_MISS
))) {
547 tf
->miss
.write
.set_fields
= tf
->nonmiss
.write
.set_fields
;
549 if (!(seen
& (1u << OFPTFPT13_APPLY_SETFIELD_MISS
))) {
550 tf
->miss
.apply
.set_fields
= tf
->nonmiss
.apply
.set_fields
;
554 /* Fix inconsistencies:
556 * - Turn on 'match' bits that are set in 'mask', because maskable
557 * fields are matchable.
559 * - Turn on 'wildcard' bits that are set in 'mask', because a field
560 * that is arbitrarily maskable can be wildcarded entirely.
562 * - Turn off 'wildcard' bits that are not in 'match', because a field
563 * must be matchable for it to be meaningfully wildcarded. */
564 bitmap_or(tf
->match
.bm
, tf
->mask
.bm
, MFF_N_IDS
);
565 bitmap_or(tf
->wildcard
.bm
, tf
->mask
.bm
, MFF_N_IDS
);
566 bitmap_and(tf
->wildcard
.bm
, tf
->match
.bm
, MFF_N_IDS
);
571 /* Encodes and returns a request to obtain the table features of a switch.
572 * The message is encoded for OpenFlow version 'ofp_version'. */
574 ofputil_encode_table_features_request(enum ofp_version ofp_version
)
576 struct ofpbuf
*request
= NULL
;
578 switch (ofp_version
) {
582 ovs_fatal(0, "dump-table-features needs OpenFlow 1.3 or later "
583 "(\'-O OpenFlow13\')");
587 request
= ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST
,
598 put_fields_property(struct ofpbuf
*reply
,
599 const struct mf_bitmap
*fields
,
600 const struct mf_bitmap
*masks
,
601 enum ofp13_table_feature_prop_type property
,
602 enum ofp_version version
)
607 start_ofs
= ofpprop_start(reply
, property
);
608 BITMAP_FOR_EACH_1 (field
, MFF_N_IDS
, fields
->bm
) {
609 nx_put_header(reply
, field
, version
,
610 masks
&& bitmap_is_set(masks
->bm
, field
));
612 ofpprop_end(reply
, start_ofs
);
616 put_table_action_features(struct ofpbuf
*reply
,
617 const struct ofputil_table_action_features
*taf
,
618 enum ofp13_table_feature_prop_type actions_type
,
619 enum ofp13_table_feature_prop_type set_fields_type
,
620 int miss_offset
, enum ofp_version version
)
622 ofpprop_put_bitmap(reply
, actions_type
+ miss_offset
,
623 ntohl(ofpact_bitmap_to_openflow(taf
->ofpacts
,
625 put_fields_property(reply
, &taf
->set_fields
, NULL
,
626 set_fields_type
+ miss_offset
, version
);
630 put_table_instruction_features(
631 struct ofpbuf
*reply
, const struct ofputil_table_instruction_features
*tif
,
632 int miss_offset
, enum ofp_version version
)
637 ofpprop_put_bitmap(reply
, OFPTFPT13_INSTRUCTIONS
+ miss_offset
,
638 ntohl(ovsinst_bitmap_to_openflow(tif
->instructions
,
641 start_ofs
= ofpprop_start(reply
, OFPTFPT13_NEXT_TABLES
+ miss_offset
);
642 BITMAP_FOR_EACH_1 (table_id
, 255, tif
->next
) {
643 ofpbuf_put(reply
, &table_id
, 1);
645 ofpprop_end(reply
, start_ofs
);
647 put_table_action_features(reply
, &tif
->write
,
648 OFPTFPT13_WRITE_ACTIONS
,
649 OFPTFPT13_WRITE_SETFIELD
, miss_offset
, version
);
650 put_table_action_features(reply
, &tif
->apply
,
651 OFPTFPT13_APPLY_ACTIONS
,
652 OFPTFPT13_APPLY_SETFIELD
, miss_offset
, version
);
655 /* Appends a table features record to 'msgs', which must be a
656 * OFPT_TABLE_FEATURES request or reply. If 'raw_properties' is nonnull, then
657 * it uses its contents verbatim as the table features properties, ignoring the
658 * corresponding members of 'tf'. */
660 ofputil_append_table_features(const struct ofputil_table_features
*tf
,
661 const struct ofpbuf
*raw_properties
,
662 struct ovs_list
*msgs
)
664 struct ofpbuf
*msg
= ofpbuf_from_list(ovs_list_back(msgs
));
665 enum ofp_version version
= ofpmp_version(msgs
);
666 size_t start_ofs
= msg
->size
;
667 struct ofp13_table_features
*otf
;
669 otf
= ofpbuf_put_zeros(msg
, sizeof *otf
);
670 otf
->table_id
= tf
->table_id
;
671 otf
->command
= version
>= OFP15_VERSION
? tf
->command
: 0;
672 ovs_strlcpy_arrays(otf
->name
, tf
->name
);
673 otf
->metadata_match
= tf
->metadata_match
;
674 otf
->metadata_write
= tf
->metadata_write
;
675 if (version
>= OFP14_VERSION
) {
676 if (tf
->supports_eviction
) {
677 otf
->capabilities
|= htonl(OFPTC14_EVICTION
);
679 if (tf
->supports_vacancy_events
) {
680 otf
->capabilities
|= htonl(OFPTC14_VACANCY_EVENTS
);
683 otf
->max_entries
= htonl(tf
->max_entries
);
685 if (raw_properties
) {
686 ofpbuf_put(msg
, raw_properties
->data
, raw_properties
->size
);
687 } else if (tf
->any_properties
) {
688 put_table_instruction_features(msg
, &tf
->nonmiss
, 0, version
);
689 put_table_instruction_features(msg
, &tf
->miss
, 1, version
);
691 put_fields_property(msg
, &tf
->match
, &tf
->mask
,
692 OFPTFPT13_MATCH
, version
);
693 put_fields_property(msg
, &tf
->wildcard
, NULL
,
694 OFPTFPT13_WILDCARDS
, version
);
697 otf
= ofpbuf_at_assert(msg
, start_ofs
, sizeof *otf
);
698 otf
->length
= htons(msg
->size
- start_ofs
);
699 ofpmp_postappend(msgs
, start_ofs
);
703 parse_table_desc_vacancy_property(struct ofpbuf
*property
,
704 struct ofputil_table_desc
*td
)
706 struct ofp14_table_mod_prop_vacancy
*otv
= property
->data
;
708 if (property
->size
!= sizeof *otv
) {
709 return OFPERR_OFPBPC_BAD_LEN
;
712 td
->table_vacancy
.vacancy_down
= otv
->vacancy_down
;
713 td
->table_vacancy
.vacancy_up
= otv
->vacancy_up
;
714 td
->table_vacancy
.vacancy
= otv
->vacancy
;
718 /* Decodes the next OpenFlow "table desc" message (of possibly several) from
719 * 'msg' into an abstract form in '*td'. Returns 0 if successful, EOF if the
720 * last "table desc" in 'msg' was already decoded, otherwise an OFPERR_*
723 ofputil_decode_table_desc(struct ofpbuf
*msg
,
724 struct ofputil_table_desc
*td
,
725 enum ofp_version version
)
727 memset(td
, 0, sizeof *td
);
730 ofpraw_pull_assert(msg
);
737 struct ofp14_table_desc
*otd
= ofpbuf_try_pull(msg
, sizeof *otd
);
739 VLOG_WARN_RL(&rl
, "OFP14_TABLE_DESC reply has %"PRIu32
" "
740 "leftover bytes at end", msg
->size
);
741 return OFPERR_OFPBRC_BAD_LEN
;
744 td
->table_id
= otd
->table_id
;
745 size_t length
= ntohs(otd
->length
);
746 if (length
< sizeof *otd
|| length
- sizeof *otd
> msg
->size
) {
747 VLOG_WARN_RL(&rl
, "OFP14_TABLE_DESC reply claims invalid "
748 "length %"PRIuSIZE
, length
);
749 return OFPERR_OFPBRC_BAD_LEN
;
751 length
-= sizeof *otd
;
753 td
->eviction
= ofputil_decode_table_eviction(otd
->config
, version
);
754 td
->vacancy
= ofputil_decode_table_vacancy(otd
->config
, version
);
755 td
->eviction_flags
= UINT32_MAX
;
757 struct ofpbuf properties
= ofpbuf_const_initializer(
758 ofpbuf_pull(msg
, length
), length
);
759 while (properties
.size
> 0) {
760 struct ofpbuf payload
;
764 error
= ofpprop_pull(&properties
, &payload
, &type
);
770 case OFPTMPT14_EVICTION
:
771 error
= ofpprop_parse_u32(&payload
, &td
->eviction_flags
);
774 case OFPTMPT14_VACANCY
:
775 error
= parse_table_desc_vacancy_property(&payload
, td
);
779 error
= OFPPROP_UNKNOWN(true, "table_desc", type
);
791 /* Encodes and returns a request to obtain description of tables of a switch.
792 * The message is encoded for OpenFlow version 'ofp_version'. */
794 ofputil_encode_table_desc_request(enum ofp_version ofp_version
)
796 struct ofpbuf
*request
= NULL
;
798 if (ofp_version
>= OFP14_VERSION
) {
799 request
= ofpraw_alloc(OFPRAW_OFPST14_TABLE_DESC_REQUEST
,
802 ovs_fatal(0, "dump-table-desc needs OpenFlow 1.4 or later "
803 "(\'-O OpenFlow14\')");
809 /* Function to append Table desc information in a reply list. */
811 ofputil_append_table_desc_reply(const struct ofputil_table_desc
*td
,
812 struct ovs_list
*replies
,
813 enum ofp_version version
)
815 struct ofpbuf
*reply
= ofpbuf_from_list(ovs_list_back(replies
));
817 struct ofp14_table_desc
*otd
;
819 start_otd
= reply
->size
;
820 ofpbuf_put_zeros(reply
, sizeof *otd
);
821 if (td
->eviction_flags
!= UINT32_MAX
) {
822 ofpprop_put_u32(reply
, OFPTMPT14_EVICTION
, td
->eviction_flags
);
824 if (td
->vacancy
== OFPUTIL_TABLE_VACANCY_ON
) {
825 struct ofp14_table_mod_prop_vacancy
*otv
;
827 otv
= ofpprop_put_zeros(reply
, OFPTMPT14_VACANCY
, sizeof *otv
);
828 otv
->vacancy_down
= td
->table_vacancy
.vacancy_down
;
829 otv
->vacancy_up
= td
->table_vacancy
.vacancy_up
;
830 otv
->vacancy
= td
->table_vacancy
.vacancy
;
833 otd
= ofpbuf_at_assert(reply
, start_otd
, sizeof *otd
);
834 otd
->length
= htons(reply
->size
- start_otd
);
835 otd
->table_id
= td
->table_id
;
836 otd
->config
= ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT
,
837 td
->eviction
, td
->vacancy
,
839 ofpmp_postappend(replies
, start_otd
);
843 ofputil_eviction_flag_to_string(uint32_t bit
)
845 enum ofp14_table_mod_prop_eviction_flag eviction_flag
= bit
;
847 switch (eviction_flag
) {
848 case OFPTMPEF14_OTHER
: return "OTHER";
849 case OFPTMPEF14_IMPORTANCE
: return "IMPORTANCE";
850 case OFPTMPEF14_LIFETIME
: return "LIFETIME";
856 /* Appends to 'string' a description of the bitmap of OFPTMPEF14_* values in
857 * 'eviction_flags'. */
859 ofputil_put_eviction_flags(struct ds
*string
, uint32_t eviction_flags
)
861 if (eviction_flags
!= UINT32_MAX
) {
862 ofp_print_bit_names(string
, eviction_flags
,
863 ofputil_eviction_flag_to_string
, '|');
865 ds_put_cstr(string
, "(default)");
870 ofputil_table_desc_format(struct ds
*s
, const struct ofputil_table_desc
*td
,
871 const struct ofputil_table_map
*table_map
)
873 ds_put_format(s
, "\n table ");
874 ofputil_format_table(td
->table_id
, table_map
, s
);
875 ds_put_cstr(s
, ":\n");
876 ds_put_format(s
, " eviction=%s eviction_flags=",
877 ofputil_table_eviction_to_string(td
->eviction
));
878 ofputil_put_eviction_flags(s
, td
->eviction_flags
);
879 ds_put_char(s
, '\n');
880 ds_put_format(s
, " vacancy=%s",
881 ofputil_table_vacancy_to_string(td
->vacancy
));
882 if (td
->vacancy
== OFPUTIL_TABLE_VACANCY_ON
) {
883 ds_put_format(s
, " vacancy_down=%"PRIu8
"%%",
884 td
->table_vacancy
.vacancy_down
);
885 ds_put_format(s
, " vacancy_up=%"PRIu8
"%%",
886 td
->table_vacancy
.vacancy_up
);
887 ds_put_format(s
, " vacancy=%"PRIu8
"%%",
888 td
->table_vacancy
.vacancy
);
890 ds_put_char(s
, '\n');
893 /* This function parses Vacancy property, and decodes the
894 * ofp14_table_mod_prop_vacancy in ofputil_table_mod.
895 * Returns OFPERR_OFPBPC_BAD_VALUE error code when vacancy_down is
896 * greater than vacancy_up and also when current vacancy has non-zero
897 * value. Returns 0 on success. */
899 parse_table_mod_vacancy_property(struct ofpbuf
*property
,
900 struct ofputil_table_mod
*tm
)
902 struct ofp14_table_mod_prop_vacancy
*otv
= property
->data
;
904 if (property
->size
!= sizeof *otv
) {
905 return OFPERR_OFPBPC_BAD_LEN
;
907 tm
->table_vacancy
.vacancy_down
= otv
->vacancy_down
;
908 tm
->table_vacancy
.vacancy_up
= otv
->vacancy_up
;
909 if (tm
->table_vacancy
.vacancy_down
> tm
->table_vacancy
.vacancy_up
) {
910 OFPPROP_LOG(&rl
, false,
911 "Value of vacancy_down is greater than vacancy_up");
912 return OFPERR_OFPBPC_BAD_VALUE
;
914 if (tm
->table_vacancy
.vacancy_down
> 100 ||
915 tm
->table_vacancy
.vacancy_up
> 100) {
916 OFPPROP_LOG(&rl
, false, "Vacancy threshold percentage "
917 "should not be greater than 100");
918 return OFPERR_OFPBPC_BAD_VALUE
;
920 tm
->table_vacancy
.vacancy
= otv
->vacancy
;
921 if (tm
->table_vacancy
.vacancy
) {
922 OFPPROP_LOG(&rl
, false,
923 "Vacancy value should be zero for table-mod messages");
924 return OFPERR_OFPBPC_BAD_VALUE
;
929 /* Given 'config', taken from an OpenFlow 'version' message that specifies
930 * table configuration (a table mod, table stats, or table features message),
931 * returns the table vacancy configuration that it specifies.
933 * Only OpenFlow 1.4 and later specify table vacancy configuration this way,
934 * so for other 'version' this function always returns
935 * OFPUTIL_TABLE_VACANCY_DEFAULT. */
936 static enum ofputil_table_vacancy
937 ofputil_decode_table_vacancy(ovs_be32 config
, enum ofp_version version
)
939 return (version
< OFP14_VERSION
? OFPUTIL_TABLE_VACANCY_DEFAULT
940 : config
& htonl(OFPTC14_VACANCY_EVENTS
) ? OFPUTIL_TABLE_VACANCY_ON
941 : OFPUTIL_TABLE_VACANCY_OFF
);
944 /* Given 'config', taken from an OpenFlow 'version' message that specifies
945 * table configuration (a table mod, table stats, or table features message),
946 * returns the table eviction configuration that it specifies.
948 * Only OpenFlow 1.4 and later specify table eviction configuration this way,
949 * so for other 'version' values this function always returns
950 * OFPUTIL_TABLE_EVICTION_DEFAULT. */
951 static enum ofputil_table_eviction
952 ofputil_decode_table_eviction(ovs_be32 config
, enum ofp_version version
)
954 return (version
< OFP14_VERSION
? OFPUTIL_TABLE_EVICTION_DEFAULT
955 : config
& htonl(OFPTC14_EVICTION
) ? OFPUTIL_TABLE_EVICTION_ON
956 : OFPUTIL_TABLE_EVICTION_OFF
);
959 /* Returns a bitmap of OFPTC* values suitable for 'config' fields in various
960 * OpenFlow messages of the given 'version', based on the provided 'miss' and
961 * 'eviction' values. */
963 ofputil_encode_table_config(enum ofputil_table_miss miss
,
964 enum ofputil_table_eviction eviction
,
965 enum ofputil_table_vacancy vacancy
,
966 enum ofp_version version
)
969 /* Search for "OFPTC_* Table Configuration" in the documentation for more
970 * information on the crazy evolution of this field. */
973 /* OpenFlow 1.0 didn't have such a field, any value ought to do. */
978 /* OpenFlow 1.1 and 1.2 define only OFPTC11_TABLE_MISS_*. */
980 case OFPUTIL_TABLE_MISS_DEFAULT
:
981 /* Really this shouldn't be used for encoding (the caller should
982 * provide a specific value) but I can't imagine that defaulting to
983 * the fall-through case here will hurt. */
984 case OFPUTIL_TABLE_MISS_CONTROLLER
:
986 return htonl(OFPTC11_TABLE_MISS_CONTROLLER
);
987 case OFPUTIL_TABLE_MISS_CONTINUE
:
988 return htonl(OFPTC11_TABLE_MISS_CONTINUE
);
989 case OFPUTIL_TABLE_MISS_DROP
:
990 return htonl(OFPTC11_TABLE_MISS_DROP
);
995 /* OpenFlow 1.3 removed OFPTC11_TABLE_MISS_* and didn't define any new
996 * flags, so this is correct. */
1001 /* OpenFlow 1.4 introduced OFPTC14_EVICTION and
1002 * OFPTC14_VACANCY_EVENTS. */
1003 if (eviction
== OFPUTIL_TABLE_EVICTION_ON
) {
1004 config
|= OFPTC14_EVICTION
;
1006 if (vacancy
== OFPUTIL_TABLE_VACANCY_ON
) {
1007 config
|= OFPTC14_VACANCY_EVENTS
;
1009 return htonl(config
);
1015 /* Given 'config', taken from an OpenFlow 'version' message that specifies
1016 * table configuration (a table mod, table stats, or table features message),
1017 * returns the table miss configuration that it specifies.
1019 * Only OpenFlow 1.1 and 1.2 specify table miss configurations this way, so for
1020 * other 'version' values this function always returns
1021 * OFPUTIL_TABLE_MISS_DEFAULT. */
1022 static enum ofputil_table_miss
1023 ofputil_decode_table_miss(ovs_be32 config_
, enum ofp_version version
)
1025 uint32_t config
= ntohl(config_
);
1027 if (version
== OFP11_VERSION
|| version
== OFP12_VERSION
) {
1028 switch (config
& OFPTC11_TABLE_MISS_MASK
) {
1029 case OFPTC11_TABLE_MISS_CONTROLLER
:
1030 return OFPUTIL_TABLE_MISS_CONTROLLER
;
1032 case OFPTC11_TABLE_MISS_CONTINUE
:
1033 return OFPUTIL_TABLE_MISS_CONTINUE
;
1035 case OFPTC11_TABLE_MISS_DROP
:
1036 return OFPUTIL_TABLE_MISS_DROP
;
1039 VLOG_WARN_RL(&rl
, "bad table miss config %d", config
);
1040 return OFPUTIL_TABLE_MISS_CONTROLLER
;
1043 return OFPUTIL_TABLE_MISS_DEFAULT
;
1047 /* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
1048 * '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */
1050 ofputil_decode_table_mod(const struct ofp_header
*oh
,
1051 struct ofputil_table_mod
*pm
)
1053 memset(pm
, 0, sizeof *pm
);
1054 pm
->miss
= OFPUTIL_TABLE_MISS_DEFAULT
;
1055 pm
->eviction
= OFPUTIL_TABLE_EVICTION_DEFAULT
;
1056 pm
->eviction_flags
= UINT32_MAX
;
1057 pm
->vacancy
= OFPUTIL_TABLE_VACANCY_DEFAULT
;
1059 struct ofpbuf b
= ofpbuf_const_initializer(oh
, ntohs(oh
->length
));
1060 enum ofpraw raw
= ofpraw_pull_assert(&b
);
1061 if (raw
== OFPRAW_OFPT11_TABLE_MOD
) {
1062 const struct ofp11_table_mod
*otm
= b
.data
;
1064 pm
->table_id
= otm
->table_id
;
1065 pm
->miss
= ofputil_decode_table_miss(otm
->config
, oh
->version
);
1066 } else if (raw
== OFPRAW_OFPT14_TABLE_MOD
) {
1067 const struct ofp14_table_mod
*otm
= ofpbuf_pull(&b
, sizeof *otm
);
1069 pm
->table_id
= otm
->table_id
;
1070 pm
->miss
= ofputil_decode_table_miss(otm
->config
, oh
->version
);
1071 pm
->eviction
= ofputil_decode_table_eviction(otm
->config
, oh
->version
);
1072 pm
->vacancy
= ofputil_decode_table_vacancy(otm
->config
, oh
->version
);
1073 while (b
.size
> 0) {
1074 struct ofpbuf property
;
1078 error
= ofpprop_pull(&b
, &property
, &type
);
1084 case OFPTMPT14_EVICTION
:
1085 error
= ofpprop_parse_u32(&property
, &pm
->eviction
);
1088 case OFPTMPT14_VACANCY
:
1089 error
= parse_table_mod_vacancy_property(&property
, pm
);
1093 error
= OFPERR_OFPBRC_BAD_TYPE
;
1102 return OFPERR_OFPBRC_BAD_TYPE
;
1108 /* Converts the abstract form of a "table mod" message in '*tm' into an
1109 * OpenFlow message suitable for 'protocol', and returns that encoded form in a
1110 * buffer owned by the caller. */
1112 ofputil_encode_table_mod(const struct ofputil_table_mod
*tm
,
1113 enum ofputil_protocol protocol
)
1115 enum ofp_version ofp_version
= ofputil_protocol_to_ofp_version(protocol
);
1118 switch (ofp_version
) {
1119 case OFP10_VERSION
: {
1120 ovs_fatal(0, "table mod needs OpenFlow 1.1 or later "
1121 "(\'-O OpenFlow11\')");
1126 case OFP13_VERSION
: {
1127 struct ofp11_table_mod
*otm
;
1129 b
= ofpraw_alloc(OFPRAW_OFPT11_TABLE_MOD
, ofp_version
, 0);
1130 otm
= ofpbuf_put_zeros(b
, sizeof *otm
);
1131 otm
->table_id
= tm
->table_id
;
1132 otm
->config
= ofputil_encode_table_config(tm
->miss
, tm
->eviction
,
1133 tm
->vacancy
, ofp_version
);
1137 case OFP15_VERSION
: {
1138 struct ofp14_table_mod
*otm
;
1140 b
= ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD
, ofp_version
, 0);
1141 otm
= ofpbuf_put_zeros(b
, sizeof *otm
);
1142 otm
->table_id
= tm
->table_id
;
1143 otm
->config
= ofputil_encode_table_config(tm
->miss
, tm
->eviction
,
1144 tm
->vacancy
, ofp_version
);
1146 if (tm
->eviction_flags
!= UINT32_MAX
) {
1147 ofpprop_put_u32(b
, OFPTMPT14_EVICTION
, tm
->eviction_flags
);
1149 if (tm
->vacancy
== OFPUTIL_TABLE_VACANCY_ON
) {
1150 struct ofp14_table_mod_prop_vacancy
*otv
;
1152 otv
= ofpprop_put_zeros(b
, OFPTMPT14_VACANCY
, sizeof *otv
);
1153 otv
->vacancy_down
= tm
->table_vacancy
.vacancy_down
;
1154 otv
->vacancy_up
= tm
->table_vacancy
.vacancy_up
;
1166 ofputil_table_mod_format(struct ds
*s
, const struct ofputil_table_mod
*tm
,
1167 const struct ofputil_table_map
*table_map
)
1169 if (tm
->table_id
== 0xff) {
1170 ds_put_cstr(s
, " table_id: ALL_TABLES");
1172 ds_put_format(s
, " table_id=");
1173 ofputil_format_table(tm
->table_id
, table_map
, s
);
1176 if (tm
->miss
!= OFPUTIL_TABLE_MISS_DEFAULT
) {
1177 ds_put_format(s
, ", flow_miss_config=%s",
1178 ofputil_table_miss_to_string(tm
->miss
));
1180 if (tm
->eviction
!= OFPUTIL_TABLE_EVICTION_DEFAULT
) {
1181 ds_put_format(s
, ", eviction=%s",
1182 ofputil_table_eviction_to_string(tm
->eviction
));
1184 if (tm
->eviction_flags
!= UINT32_MAX
) {
1185 ds_put_cstr(s
, "eviction_flags=");
1186 ofputil_put_eviction_flags(s
, tm
->eviction_flags
);
1188 if (tm
->vacancy
!= OFPUTIL_TABLE_VACANCY_DEFAULT
) {
1189 ds_put_format(s
, ", vacancy=%s",
1190 ofputil_table_vacancy_to_string(tm
->vacancy
));
1191 if (tm
->vacancy
== OFPUTIL_TABLE_VACANCY_ON
) {
1192 ds_put_format(s
, " vacancy:%"PRIu8
""
1193 ",%"PRIu8
"", tm
->table_vacancy
.vacancy_down
,
1194 tm
->table_vacancy
.vacancy_up
);
1199 /* Convert 'setting' (as described for the "mod-table" command
1200 * in ovs-ofctl man page) into 'tm->table_vacancy->vacancy_up' and
1201 * 'tm->table_vacancy->vacancy_down' threshold values.
1202 * For the two threshold values, value of vacancy_up is always greater
1203 * than value of vacancy_down.
1205 * Returns NULL if successful, otherwise a malloc()'d string describing the
1206 * error. The caller is responsible for freeing the returned string. */
1207 static char * OVS_WARN_UNUSED_RESULT
1208 parse_ofp_table_vacancy(struct ofputil_table_mod
*tm
, const char *setting
)
1210 char *save_ptr
= NULL
;
1211 char *vac_up
, *vac_down
;
1212 char *value
= xstrdup(setting
);
1214 int vacancy_up
, vacancy_down
;
1216 strtok_r(value
, ":", &save_ptr
);
1217 vac_down
= strtok_r(NULL
, ",", &save_ptr
);
1219 ret_msg
= xasprintf("Vacancy down value missing");
1222 if (!str_to_int(vac_down
, 0, &vacancy_down
) ||
1223 vacancy_down
< 0 || vacancy_down
> 100) {
1224 ret_msg
= xasprintf("Invalid vacancy down value \"%s\"", vac_down
);
1227 vac_up
= strtok_r(NULL
, ",", &save_ptr
);
1229 ret_msg
= xasprintf("Vacancy up value missing");
1232 if (!str_to_int(vac_up
, 0, &vacancy_up
) ||
1233 vacancy_up
< 0 || vacancy_up
> 100) {
1234 ret_msg
= xasprintf("Invalid vacancy up value \"%s\"", vac_up
);
1237 if (vacancy_down
> vacancy_up
) {
1238 ret_msg
= xasprintf("Invalid vacancy range, vacancy up should be "
1239 "greater than vacancy down (%s)",
1240 ofperr_to_string(OFPERR_OFPBPC_BAD_VALUE
));
1245 tm
->table_vacancy
.vacancy_down
= vacancy_down
;
1246 tm
->table_vacancy
.vacancy_up
= vacancy_up
;
1254 /* Convert 'table_id' and 'setting' (as described for the "mod-table" command
1255 * in the ovs-ofctl man page) into 'tm' for sending a table_mod command to a
1256 * switch. If 'setting' sets the name of the table, puts the new name in
1257 * '*namep' (a suffix of 'setting'), otherwise stores NULL.
1259 * Stores a bitmap of the OpenFlow versions that are usable for 'tm' into
1260 * '*usable_versions'.
1262 * Returns NULL if successful, otherwise a malloc()'d string describing the
1263 * error. The caller is responsible for freeing the returned string. */
1264 char * OVS_WARN_UNUSED_RESULT
1265 parse_ofp_table_mod(struct ofputil_table_mod
*tm
, const char **namep
,
1266 const char *table_id
, const char *setting
,
1267 const struct ofputil_table_map
*table_map
,
1268 uint32_t *usable_versions
)
1270 *usable_versions
= 0;
1272 if (!strcasecmp(table_id
, "all")) {
1273 tm
->table_id
= OFPTT_ALL
;
1274 } else if (!ofputil_table_from_string(table_id
, table_map
,
1276 return xasprintf("unknown table \"%s\"", table_id
);
1279 tm
->miss
= OFPUTIL_TABLE_MISS_DEFAULT
;
1280 tm
->eviction
= OFPUTIL_TABLE_EVICTION_DEFAULT
;
1281 tm
->eviction_flags
= UINT32_MAX
;
1282 tm
->vacancy
= OFPUTIL_TABLE_VACANCY_DEFAULT
;
1283 tm
->table_vacancy
.vacancy_down
= 0;
1284 tm
->table_vacancy
.vacancy_up
= 0;
1285 tm
->table_vacancy
.vacancy
= 0;
1286 /* Only OpenFlow 1.1 and 1.2 can configure table-miss via table_mod.
1287 * Only OpenFlow 1.4+ can configure eviction and vacancy events
1290 if (!strcmp(setting
, "controller")) {
1291 tm
->miss
= OFPUTIL_TABLE_MISS_CONTROLLER
;
1292 *usable_versions
= (1u << OFP11_VERSION
) | (1u << OFP12_VERSION
);
1293 } else if (!strcmp(setting
, "continue")) {
1294 tm
->miss
= OFPUTIL_TABLE_MISS_CONTINUE
;
1295 *usable_versions
= (1u << OFP11_VERSION
) | (1u << OFP12_VERSION
);
1296 } else if (!strcmp(setting
, "drop")) {
1297 tm
->miss
= OFPUTIL_TABLE_MISS_DROP
;
1298 *usable_versions
= (1u << OFP11_VERSION
) | (1u << OFP12_VERSION
);
1299 } else if (!strcmp(setting
, "evict")) {
1300 tm
->eviction
= OFPUTIL_TABLE_EVICTION_ON
;
1301 *usable_versions
= (1 << OFP14_VERSION
) | (1u << OFP15_VERSION
);
1302 } else if (!strcmp(setting
, "noevict")) {
1303 tm
->eviction
= OFPUTIL_TABLE_EVICTION_OFF
;
1304 *usable_versions
= (1 << OFP14_VERSION
) | (1u << OFP15_VERSION
);
1305 } else if (!strncmp(setting
, "vacancy", strcspn(setting
, ":"))) {
1306 tm
->vacancy
= OFPUTIL_TABLE_VACANCY_ON
;
1307 *usable_versions
= (1 << OFP14_VERSION
) | (1u << OFP15_VERSION
);
1308 char *error
= parse_ofp_table_vacancy(tm
, setting
);
1312 } else if (!strcmp(setting
, "novacancy")) {
1313 tm
->vacancy
= OFPUTIL_TABLE_VACANCY_OFF
;
1314 *usable_versions
= (1 << OFP14_VERSION
) | (1u << OFP15_VERSION
);
1315 } else if (tm
->table_id
!= OFPTT_ALL
&& !strncmp(setting
, "name:", 5)) {
1316 *namep
= setting
+ 5;
1317 *usable_versions
= ((1 << OFP13_VERSION
) | (1u << OFP14_VERSION
)
1318 | (1u << OFP15_VERSION
));
1320 return xasprintf("invalid table_mod setting %s", setting
);
1323 if (tm
->table_id
== 0xfe
1324 && tm
->miss
== OFPUTIL_TABLE_MISS_CONTINUE
) {
1325 return xstrdup("last table's flow miss handling can not be continue");
1331 /* Returns true if 's' consists of only ASCII digits (and at least one). */
1333 is_all_digits(const char *s
)
1335 return s
[0] && s
[strspn(s
, "0123456789")] == '\0';
1338 /* Returns true if 'a' and 'b' are the same except 'b' ends in a number one
1339 * larger than 'a', for example, "reg0" and "reg1" */
1341 are_names_sequential(const char *a
, const char *b
)
1343 /* Skip common prefix. */
1344 for (; *a
== *b
; a
++, b
++) {
1346 /* 'a' and 'b' are the same. Weird, but not sequential. */
1351 return (is_all_digits(a
)
1355 && atoi(a
) + 1 == atoi(b
));
1358 /* Returns the number of sequential names at the start of the 'n' strings in
1359 * 'ids'. Returns at least 1 (if 'n' > 0). */
1361 count_sequential_suffix_run(const char *ids
[], size_t n
)
1363 for (size_t i
= 1; ; i
++) {
1364 if (i
>= n
|| !are_names_sequential(ids
[i
- 1], ids
[i
])) {
1365 /* "x0...x1" is worse than "x0 x1", so suppress it. */
1366 return i
== 2 ? 1 : i
;
1371 /* Counts the length of the longest common prefix (that ends in "_") between
1372 * strings 'a' and 'b'. Returns 0 if they have no common prefix. */
1374 count_common_prefix(const char *a
, const char *b
)
1377 for (size_t i
= 0; ; i
++) {
1378 if (a
[i
] != b
[i
] || !a
[i
]) {
1380 } else if (a
[i
] == '_') {
1386 /* Returns the number of strings in the longest run of strings with a common
1387 * prefix (that ends in "_") at the beginning of the 'n' strings in 'ids'.
1388 * This is at least 1, if 'n' > 0. All the strings are already known to have a
1389 * common prefix of length 'prefix_len', so that's not of interest; only an
1390 * additional common prefix is interesting.
1392 * If this returns 'n' > 1, then '*extra_prefix_lenp' receives the length of
1393 * the additional common prefix. Otherwise '*extra_prefix_lenp' receives 0. */
1395 count_common_prefix_run(const char *ids
[], size_t n
,
1396 size_t prefix_len
, size_t *extra_prefix_lenp
)
1398 *extra_prefix_lenp
= 0;
1403 size_t extra_prefix_len
= count_common_prefix(ids
[0] + prefix_len
,
1404 ids
[1] + prefix_len
);
1405 if (!extra_prefix_len
) {
1411 size_t next
= count_common_prefix(ids
[0] + prefix_len
,
1412 ids
[i
] + prefix_len
);
1415 } else if (next
< extra_prefix_len
) {
1416 next
= extra_prefix_len
;
1420 *extra_prefix_lenp
= extra_prefix_len
;
1424 /* Appends the 'n' names in 'ids' to 's', omitting the first 'prefix_len' bytes
1425 * of each name (which should all be the same), separating them from each other
1428 * Two kinds of abbreviation are implemented:
1430 * - Common prefixes: "eth_src eth_dst eth_type" => "eth_{src,dst,type}".
1432 * - Sequential suffixes: "reg0 reg1 reg2 reg3" => "reg0...reg3".
1435 print_names(struct ds
*s
, const char *ids
[], size_t n
, size_t prefix_len
)
1440 ds_put_char(s
, prefix_len
? ',' : ' ');
1443 /* Count the prefix and suffix runs at the beginning of 'ids'. As of
1444 * this writing we don't have any sequentially numbered fields whose
1445 * names contain "_", so we should only have one or the other at a
1446 * time. However, if we end up with something like "a_0 a_1 a_2"
1447 * someday, we want to render it as a_0...a_2, not as a_{0...2}, so
1448 * given equal suffix and prefix runs, prefer the suffix. */
1449 size_t extra_prefix_len
;
1450 size_t prefix_run
= count_common_prefix_run(ids
, n
, prefix_len
,
1452 size_t suffix_run
= count_sequential_suffix_run(ids
, n
);
1453 size_t run
= MAX(prefix_run
, suffix_run
);
1454 if (suffix_run
>= prefix_run
) {
1455 ds_put_format(s
, "%s", ids
[0] + prefix_len
);
1457 ds_put_format(s
, "...%s", ids
[run
- 1] + prefix_len
);
1460 ds_put_format(s
, "%.*s{", (int) extra_prefix_len
,
1461 ids
[0] + prefix_len
);
1462 print_names(s
, ids
, run
, prefix_len
+ extra_prefix_len
);
1463 ds_put_char(s
, '}');
1472 print_mf_bitmap(struct ds
*s
, const struct mf_bitmap
*mfb
)
1474 const char *ids
[MFF_N_IDS
];
1478 BITMAP_FOR_EACH_1 (i
, MFF_N_IDS
, mfb
->bm
) {
1479 ids
[n
++] = mf_from_id(i
)->name
;
1483 ds_put_char(s
, ' ');
1484 print_names(s
, ids
, n
, 0);
1489 print_table_action_features(struct ds
*s
,
1490 const struct ofputil_table_action_features
*taf
)
1493 ds_put_cstr(s
, " actions: ");
1494 ofpact_bitmap_format(taf
->ofpacts
, s
);
1495 ds_put_char(s
, '\n');
1498 if (!bitmap_is_all_zeros(taf
->set_fields
.bm
, MFF_N_IDS
)) {
1499 ds_put_cstr(s
, " supported on Set-Field:");
1500 print_mf_bitmap(s
, &taf
->set_fields
);
1501 ds_put_char(s
, '\n');
1506 table_action_features_equal(const struct ofputil_table_action_features
*a
,
1507 const struct ofputil_table_action_features
*b
)
1509 return (a
->ofpacts
== b
->ofpacts
1510 && bitmap_equal(a
->set_fields
.bm
, b
->set_fields
.bm
, MFF_N_IDS
));
1514 table_action_features_empty(const struct ofputil_table_action_features
*taf
)
1516 return !taf
->ofpacts
&& bitmap_is_all_zeros(taf
->set_fields
.bm
, MFF_N_IDS
);
1520 print_table_instruction_features(
1522 const struct ofputil_table_instruction_features
*tif
,
1523 const struct ofputil_table_instruction_features
*prev_tif
)
1527 if (!bitmap_is_all_zeros(tif
->next
, 255)) {
1528 ds_put_cstr(s
, " next tables: ");
1529 for (start
= bitmap_scan(tif
->next
, 1, 0, 255); start
< 255;
1530 start
= bitmap_scan(tif
->next
, 1, end
, 255)) {
1531 end
= bitmap_scan(tif
->next
, 0, start
+ 1, 255);
1532 if (end
== start
+ 1) {
1533 ds_put_format(s
, "%d,", start
);
1535 ds_put_format(s
, "%d-%d,", start
, end
- 1);
1539 if (ds_last(s
) == ' ') {
1540 ds_put_cstr(s
, "none");
1542 ds_put_char(s
, '\n');
1545 if (tif
->instructions
) {
1546 if (prev_tif
&& tif
->instructions
== prev_tif
->instructions
) {
1547 ds_put_cstr(s
, " (same instructions)\n");
1549 ds_put_cstr(s
, " instructions: ");
1552 for (i
= 0; i
< 32; i
++) {
1553 if (tif
->instructions
& (1u << i
)) {
1554 const char *name
= ovs_instruction_name_from_type(i
);
1556 ds_put_cstr(s
, name
);
1558 ds_put_format(s
, "%d", i
);
1560 ds_put_char(s
, ' ');
1564 ds_put_char(s
, '\n');
1569 && table_action_features_equal(&tif
->write
, &prev_tif
->write
)
1570 && table_action_features_equal(&tif
->apply
, &prev_tif
->apply
)
1571 && !bitmap_is_all_zeros(tif
->write
.set_fields
.bm
, MFF_N_IDS
)) {
1572 ds_put_cstr(s
, " (same actions)\n");
1573 } else if (!table_action_features_equal(&tif
->write
, &tif
->apply
)) {
1574 ds_put_cstr(s
, " Write-Actions features:\n");
1575 print_table_action_features(s
, &tif
->write
);
1576 ds_put_cstr(s
, " Apply-Actions features:\n");
1577 print_table_action_features(s
, &tif
->apply
);
1578 } else if (tif
->write
.ofpacts
1579 || !bitmap_is_all_zeros(tif
->write
.set_fields
.bm
, MFF_N_IDS
)) {
1580 ds_put_cstr(s
, " Write-Actions and Apply-Actions features:\n");
1581 print_table_action_features(s
, &tif
->write
);
1586 print_matches(struct ds
*s
, const struct ofputil_table_features
*f
,
1587 bool mask
, bool wc
, const char *title
)
1589 const struct mf_bitmap m
= mask
? f
->mask
: mf_bitmap_not(f
->mask
);
1590 const struct mf_bitmap w
= wc
? f
->wildcard
: mf_bitmap_not(f
->wildcard
);
1591 const struct mf_bitmap bm
= mf_bitmap_and(f
->match
, mf_bitmap_and(m
, w
));
1593 if (!bitmap_is_all_zeros(bm
.bm
, MFF_N_IDS
)) {
1594 ds_put_format(s
, " %s:", title
);
1595 print_mf_bitmap(s
, &bm
);
1596 ds_put_char(s
, '\n');
1600 /* Compares bitmaps of next tables 'a' and 'b', for tables 'a_table_id' and
1601 * 'b_table_id', respectively. Returns true if the bitmaps are equal.
1603 * The bitmaps are considered equal if b_table_id == a_table_id + 1 and the bit
1604 * for 'b_table_id' is set in 'a' but not in 'b'. This is because OpenFlow
1605 * requires that a table not be able to do a goto_table back to its own table
1606 * or an earlier one. Without considering these equivalent, every table will
1607 * be different from every one in some way, which just isn't useful in printing
1608 * table features. */
1610 table_instruction_features_next_equal(const unsigned long *a
, int a_table_id
,
1611 const unsigned long *b
, int b_table_id
)
1613 if (b_table_id
== a_table_id
+ 1
1614 && bitmap_is_set(a
, b_table_id
)
1615 && !bitmap_is_set(b
, b_table_id
)) {
1616 for (size_t i
= 0; i
< BITMAP_N_LONGS(255); i
++) {
1617 unsigned long diff
= a
[i
] ^ b
[i
];
1618 if (i
== b_table_id
/ BITMAP_ULONG_BITS
) {
1619 diff
&= ~bitmap_bit__(b_table_id
);
1626 } else if (a_table_id
== b_table_id
+ 1) {
1627 return table_instruction_features_next_equal(b
, b_table_id
,
1630 return bitmap_equal(a
, b
, 255);
1635 table_instruction_features_equal(
1636 const struct ofputil_table_instruction_features
*a
, int a_table_id
,
1637 const struct ofputil_table_instruction_features
*b
, int b_table_id
)
1639 return (table_instruction_features_next_equal(a
->next
, a_table_id
,
1640 b
->next
, b_table_id
)
1641 && a
->instructions
== b
->instructions
1642 && table_action_features_equal(&a
->write
, &b
->write
)
1643 && table_action_features_equal(&a
->apply
, &b
->apply
));
1647 table_instruction_features_empty(
1648 const struct ofputil_table_instruction_features
*tif
)
1650 return (bitmap_is_all_zeros(tif
->next
, 255)
1651 && !tif
->instructions
1652 && table_action_features_empty(&tif
->write
)
1653 && table_action_features_empty(&tif
->apply
));
1657 table_features_equal(const struct ofputil_table_features
*a
,
1658 const struct ofputil_table_features
*b
)
1660 return (a
->metadata_match
== b
->metadata_match
1661 && a
->metadata_write
== b
->metadata_write
1662 && a
->miss_config
== b
->miss_config
1663 && a
->supports_eviction
== b
->supports_eviction
1664 && a
->supports_vacancy_events
== b
->supports_vacancy_events
1665 && a
->max_entries
== b
->max_entries
1666 && table_instruction_features_equal(&a
->nonmiss
, a
->table_id
,
1667 &b
->nonmiss
, b
->table_id
)
1668 && table_instruction_features_equal(&a
->miss
, a
->table_id
,
1669 &b
->miss
, b
->table_id
)
1670 && bitmap_equal(a
->match
.bm
, b
->match
.bm
, MFF_N_IDS
));
1674 table_features_empty(const struct ofputil_table_features
*tf
)
1676 return (!tf
->metadata_match
1677 && !tf
->metadata_write
1678 && tf
->miss_config
== OFPUTIL_TABLE_MISS_DEFAULT
1679 && tf
->supports_eviction
< 0
1680 && tf
->supports_vacancy_events
< 0
1682 && table_instruction_features_empty(&tf
->nonmiss
)
1683 && table_instruction_features_empty(&tf
->miss
)
1684 && bitmap_is_all_zeros(tf
->match
.bm
, MFF_N_IDS
));
1688 table_stats_equal(const struct ofputil_table_stats
*a
,
1689 const struct ofputil_table_stats
*b
)
1691 return (a
->active_count
== b
->active_count
1692 && a
->lookup_count
== b
->lookup_count
1693 && a
->matched_count
== b
->matched_count
);
1697 ofputil_table_features_format(
1699 const struct ofputil_table_features
*features
,
1700 const struct ofputil_table_features
*prev_features
,
1701 const struct ofputil_table_stats
*stats
,
1702 const struct ofputil_table_stats
*prev_stats
,
1703 int *first_ditto
, int *last_ditto
)
1705 if (!prev_features
&& features
->command
!= OFPTFC15_REPLACE
) {
1706 ds_put_format(s
, "\n command: %s",
1707 ofp15_table_features_command_to_string(
1708 features
->command
));
1711 int table
= features
->table_id
;
1712 int prev_table
= prev_features
? prev_features
->table_id
: 0;
1714 bool same_stats
= !stats
|| (prev_stats
1715 && table_stats_equal(stats
, prev_stats
));
1716 bool same_features
= prev_features
&& table_features_equal(features
,
1718 if (same_stats
&& same_features
&& !features
->name
[0]) {
1719 if (*first_ditto
< 0) {
1720 *first_ditto
= table
;
1722 *last_ditto
= table
;
1725 ofputil_table_features_format_finish(s
, *first_ditto
, *last_ditto
);
1728 ds_put_format(s
, "\n table %d", table
);
1729 if (features
->name
[0]) {
1730 ds_put_format(s
, " (\"%s\")", features
->name
);
1732 ds_put_char(s
, ':');
1734 if (same_stats
&& same_features
) {
1735 ds_put_cstr(s
, " ditto");
1738 ds_put_char(s
, '\n');
1740 ds_put_format(s
, " active=%"PRIu32
", ", stats
->active_count
);
1741 ds_put_format(s
, "lookup=%"PRIu64
", ", stats
->lookup_count
);
1742 ds_put_format(s
, "matched=%"PRIu64
"\n", stats
->matched_count
);
1744 if (same_features
) {
1745 if (!table_features_empty(features
)) {
1746 ds_put_cstr(s
, " (same features)\n");
1750 if (features
->metadata_match
|| features
->metadata_write
) {
1751 ds_put_format(s
, " metadata: match=%#"PRIx64
" write=%#"PRIx64
"\n",
1752 ntohll(features
->metadata_match
),
1753 ntohll(features
->metadata_write
));
1756 if (features
->miss_config
!= OFPUTIL_TABLE_MISS_DEFAULT
) {
1757 ds_put_format(s
, " config=%s\n",
1758 ofputil_table_miss_to_string(features
->miss_config
));
1761 if (features
->supports_eviction
>= 0) {
1762 ds_put_format(s
, " eviction: %ssupported\n",
1763 features
->supports_eviction
? "" : "not ");
1766 if (features
->supports_vacancy_events
>= 0) {
1767 ds_put_format(s
, " vacancy events: %ssupported\n",
1768 features
->supports_vacancy_events
? "" : "not ");
1772 if (features
->max_entries
) {
1773 ds_put_format(s
, " max_entries=%"PRIu32
"\n", features
->max_entries
);
1776 const struct ofputil_table_instruction_features
*prev_nonmiss
1777 = prev_features
? &prev_features
->nonmiss
: NULL
;
1778 const struct ofputil_table_instruction_features
*prev_miss
1779 = prev_features
? &prev_features
->miss
: NULL
;
1781 && table_instruction_features_equal(&features
->nonmiss
, table
,
1782 prev_nonmiss
, prev_table
)
1783 && table_instruction_features_equal(&features
->miss
, table
,
1784 prev_miss
, prev_table
)) {
1785 if (!table_instruction_features_empty(&features
->nonmiss
)) {
1786 ds_put_cstr(s
, " (same instructions)\n");
1788 } else if (!table_instruction_features_equal(&features
->nonmiss
, table
,
1789 &features
->miss
, table
)) {
1790 ds_put_cstr(s
, " instructions (other than table miss):\n");
1791 print_table_instruction_features(s
, &features
->nonmiss
, prev_nonmiss
);
1792 ds_put_cstr(s
, " instructions (table miss):\n");
1793 print_table_instruction_features(s
, &features
->miss
, prev_miss
);
1794 } else if (!table_instruction_features_empty(&features
->nonmiss
)) {
1795 ds_put_cstr(s
, " instructions (table miss and others):\n");
1796 print_table_instruction_features(s
, &features
->nonmiss
, prev_nonmiss
);
1799 if (!bitmap_is_all_zeros(features
->match
.bm
, MFF_N_IDS
)) {
1801 && bitmap_equal(features
->match
.bm
, prev_features
->match
.bm
,
1803 ds_put_cstr(s
, " (same matching)\n");
1805 ds_put_cstr(s
, " matching:\n");
1807 print_matches(s
, features
, true, true, "arbitrary mask");
1808 print_matches(s
, features
, false, true, "exact match or wildcard");
1809 print_matches(s
, features
, false, false, "must exact match");
1815 ofputil_table_features_format_finish(struct ds
*s
,
1816 int first_ditto
, int last_ditto
)
1818 if (first_ditto
< 0) {
1822 ds_put_char(s
, '\n');
1823 if (first_ditto
== last_ditto
) {
1824 ds_put_format(s
, " table %d: ditto\n", first_ditto
);
1826 ds_put_format(s
, " tables %d...%d: ditto\n", first_ditto
, last_ditto
);
1830 /* Returns true if 'super' is a superset of 'sub', false otherwise. */
1832 ofputil_table_action_features_is_superset(
1833 const struct ofputil_table_action_features
*super
,
1834 const struct ofputil_table_action_features
*sub
)
1836 return (uint_is_superset(super
->ofpacts
, sub
->ofpacts
)
1837 && mf_bitmap_is_superset(&super
->set_fields
, &sub
->set_fields
));
1840 /* Returns true if 'super' is a superset of 'sub', false otherwise. */
1842 ofputil_table_instruction_features_is_superset(
1843 const struct ofputil_table_instruction_features
*super
,
1844 const struct ofputil_table_instruction_features
*sub
)
1846 return (bitmap_is_superset(super
->next
, sub
->next
, 255)
1847 && uint_is_superset(super
->instructions
, sub
->instructions
)
1848 && ofputil_table_action_features_is_superset(&super
->write
,
1850 && ofputil_table_action_features_is_superset(&super
->apply
,
1854 /* Returns true if 'super' is a superset of 'sub', false otherwise. */
1856 ofputil_table_features_are_superset(
1857 const struct ofputil_table_features
*super
,
1858 const struct ofputil_table_features
*sub
)
1860 return (be64_is_superset(super
->metadata_match
, sub
->metadata_match
)
1861 && be64_is_superset(super
->metadata_write
, sub
->metadata_write
)
1862 && super
->max_entries
>= sub
->max_entries
1863 && super
->supports_eviction
>= sub
->supports_eviction
1864 && super
->supports_vacancy_events
>= sub
->supports_vacancy_events
1865 && ofputil_table_instruction_features_is_superset(&super
->nonmiss
,
1867 && ofputil_table_instruction_features_is_superset(&super
->miss
,
1869 && mf_bitmap_is_superset(&super
->match
, &sub
->match
)
1870 && mf_bitmap_is_superset(&super
->mask
, &sub
->mask
)
1871 && mf_bitmap_is_superset(&super
->wildcard
, &sub
->wildcard
));
1876 /* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be
1877 * matched and a field that must be wildcarded. This function returns a bitmap
1878 * that contains both kinds of fields. */
1879 static struct mf_bitmap
1880 wild_or_nonmatchable_fields(const struct ofputil_table_features
*features
)
1882 struct mf_bitmap wc
= features
->match
;
1883 bitmap_not(wc
.bm
, MFF_N_IDS
);
1884 bitmap_or(wc
.bm
, features
->wildcard
.bm
, MFF_N_IDS
);
1888 struct ofp10_wc_map
{
1889 enum ofp10_flow_wildcards wc10
;
1890 enum mf_field_id mf
;
1893 static const struct ofp10_wc_map ofp10_wc_map
[] = {
1894 { OFPFW10_IN_PORT
, MFF_IN_PORT
},
1895 { OFPFW10_DL_VLAN
, MFF_VLAN_VID
},
1896 { OFPFW10_DL_SRC
, MFF_ETH_SRC
},
1897 { OFPFW10_DL_DST
, MFF_ETH_DST
},
1898 { OFPFW10_DL_TYPE
, MFF_ETH_TYPE
},
1899 { OFPFW10_NW_PROTO
, MFF_IP_PROTO
},
1900 { OFPFW10_TP_SRC
, MFF_TCP_SRC
},
1901 { OFPFW10_TP_DST
, MFF_TCP_DST
},
1902 { OFPFW10_NW_SRC_MASK
, MFF_IPV4_SRC
},
1903 { OFPFW10_NW_DST_MASK
, MFF_IPV4_DST
},
1904 { OFPFW10_DL_VLAN_PCP
, MFF_VLAN_PCP
},
1905 { OFPFW10_NW_TOS
, MFF_IP_DSCP
},
1909 mf_bitmap_to_of10(const struct mf_bitmap
*fields
)
1911 const struct ofp10_wc_map
*p
;
1914 for (p
= ofp10_wc_map
; p
< &ofp10_wc_map
[ARRAY_SIZE(ofp10_wc_map
)]; p
++) {
1915 if (bitmap_is_set(fields
->bm
, p
->mf
)) {
1922 static struct mf_bitmap
1923 mf_bitmap_from_of10(ovs_be32 wc10_
)
1925 struct mf_bitmap fields
= MF_BITMAP_INITIALIZER
;
1926 const struct ofp10_wc_map
*p
;
1927 uint32_t wc10
= ntohl(wc10_
);
1929 for (p
= ofp10_wc_map
; p
< &ofp10_wc_map
[ARRAY_SIZE(ofp10_wc_map
)]; p
++) {
1930 if (wc10
& p
->wc10
) {
1931 bitmap_set1(fields
.bm
, p
->mf
);
1938 ofputil_put_ofp10_table_stats(const struct ofputil_table_stats
*stats
,
1939 const struct ofputil_table_features
*features
,
1942 struct mf_bitmap wc
= wild_or_nonmatchable_fields(features
);
1943 struct ofp10_table_stats
*out
;
1945 out
= ofpbuf_put_zeros(buf
, sizeof *out
);
1946 out
->table_id
= features
->table_id
;
1947 ovs_strlcpy_arrays(out
->name
, features
->name
);
1948 out
->wildcards
= mf_bitmap_to_of10(&wc
);
1949 out
->max_entries
= htonl(features
->max_entries
);
1950 out
->active_count
= htonl(stats
->active_count
);
1951 put_32aligned_be64(&out
->lookup_count
, htonll(stats
->lookup_count
));
1952 put_32aligned_be64(&out
->matched_count
, htonll(stats
->matched_count
));
1955 struct ofp11_wc_map
{
1956 enum ofp11_flow_match_fields wc11
;
1957 enum mf_field_id mf
;
1960 static const struct ofp11_wc_map ofp11_wc_map
[] = {
1961 { OFPFMF11_IN_PORT
, MFF_IN_PORT
},
1962 { OFPFMF11_DL_VLAN
, MFF_VLAN_VID
},
1963 { OFPFMF11_DL_VLAN_PCP
, MFF_VLAN_PCP
},
1964 { OFPFMF11_DL_TYPE
, MFF_ETH_TYPE
},
1965 { OFPFMF11_NW_TOS
, MFF_IP_DSCP
},
1966 { OFPFMF11_NW_PROTO
, MFF_IP_PROTO
},
1967 { OFPFMF11_TP_SRC
, MFF_TCP_SRC
},
1968 { OFPFMF11_TP_DST
, MFF_TCP_DST
},
1969 { OFPFMF11_MPLS_LABEL
, MFF_MPLS_LABEL
},
1970 { OFPFMF11_MPLS_TC
, MFF_MPLS_TC
},
1971 /* I don't know what OFPFMF11_TYPE means. */
1972 { OFPFMF11_DL_SRC
, MFF_ETH_SRC
},
1973 { OFPFMF11_DL_DST
, MFF_ETH_DST
},
1974 { OFPFMF11_NW_SRC
, MFF_IPV4_SRC
},
1975 { OFPFMF11_NW_DST
, MFF_IPV4_DST
},
1976 { OFPFMF11_METADATA
, MFF_METADATA
},
1980 mf_bitmap_to_of11(const struct mf_bitmap
*fields
)
1982 const struct ofp11_wc_map
*p
;
1985 for (p
= ofp11_wc_map
; p
< &ofp11_wc_map
[ARRAY_SIZE(ofp11_wc_map
)]; p
++) {
1986 if (bitmap_is_set(fields
->bm
, p
->mf
)) {
1993 static struct mf_bitmap
1994 mf_bitmap_from_of11(ovs_be32 wc11_
)
1996 struct mf_bitmap fields
= MF_BITMAP_INITIALIZER
;
1997 const struct ofp11_wc_map
*p
;
1998 uint32_t wc11
= ntohl(wc11_
);
2000 for (p
= ofp11_wc_map
; p
< &ofp11_wc_map
[ARRAY_SIZE(ofp11_wc_map
)]; p
++) {
2001 if (wc11
& p
->wc11
) {
2002 bitmap_set1(fields
.bm
, p
->mf
);
2009 ofputil_put_ofp11_table_stats(const struct ofputil_table_stats
*stats
,
2010 const struct ofputil_table_features
*features
,
2013 struct mf_bitmap wc
= wild_or_nonmatchable_fields(features
);
2014 struct ofp11_table_stats
*out
;
2016 out
= ofpbuf_put_zeros(buf
, sizeof *out
);
2017 out
->table_id
= features
->table_id
;
2018 ovs_strlcpy_arrays(out
->name
, features
->name
);
2019 out
->wildcards
= mf_bitmap_to_of11(&wc
);
2020 out
->match
= mf_bitmap_to_of11(&features
->match
);
2021 out
->instructions
= ovsinst_bitmap_to_openflow(
2022 features
->nonmiss
.instructions
, OFP11_VERSION
);
2023 out
->write_actions
= ofpact_bitmap_to_openflow(
2024 features
->nonmiss
.write
.ofpacts
, OFP11_VERSION
);
2025 out
->apply_actions
= ofpact_bitmap_to_openflow(
2026 features
->nonmiss
.apply
.ofpacts
, OFP11_VERSION
);
2027 out
->config
= htonl(features
->miss_config
);
2028 out
->max_entries
= htonl(features
->max_entries
);
2029 out
->active_count
= htonl(stats
->active_count
);
2030 out
->lookup_count
= htonll(stats
->lookup_count
);
2031 out
->matched_count
= htonll(stats
->matched_count
);
2035 ofputil_put_ofp12_table_stats(const struct ofputil_table_stats
*stats
,
2036 const struct ofputil_table_features
*features
,
2039 struct ofp12_table_stats
*out
;
2041 out
= ofpbuf_put_zeros(buf
, sizeof *out
);
2042 out
->table_id
= features
->table_id
;
2043 ovs_strlcpy_arrays(out
->name
, features
->name
);
2044 out
->match
= oxm_bitmap_from_mf_bitmap(&features
->match
, OFP12_VERSION
);
2045 out
->wildcards
= oxm_bitmap_from_mf_bitmap(&features
->wildcard
,
2047 out
->write_actions
= ofpact_bitmap_to_openflow(
2048 features
->nonmiss
.write
.ofpacts
, OFP12_VERSION
);
2049 out
->apply_actions
= ofpact_bitmap_to_openflow(
2050 features
->nonmiss
.apply
.ofpacts
, OFP12_VERSION
);
2051 out
->write_setfields
= oxm_bitmap_from_mf_bitmap(
2052 &features
->nonmiss
.write
.set_fields
, OFP12_VERSION
);
2053 out
->apply_setfields
= oxm_bitmap_from_mf_bitmap(
2054 &features
->nonmiss
.apply
.set_fields
, OFP12_VERSION
);
2055 out
->metadata_match
= features
->metadata_match
;
2056 out
->metadata_write
= features
->metadata_write
;
2057 out
->instructions
= ovsinst_bitmap_to_openflow(
2058 features
->nonmiss
.instructions
, OFP12_VERSION
);
2059 out
->config
= ofputil_encode_table_config(features
->miss_config
,
2060 OFPUTIL_TABLE_EVICTION_DEFAULT
,
2061 OFPUTIL_TABLE_VACANCY_DEFAULT
,
2063 out
->max_entries
= htonl(features
->max_entries
);
2064 out
->active_count
= htonl(stats
->active_count
);
2065 out
->lookup_count
= htonll(stats
->lookup_count
);
2066 out
->matched_count
= htonll(stats
->matched_count
);
2070 ofputil_put_ofp13_table_stats(const struct ofputil_table_stats
*stats
,
2073 struct ofp13_table_stats
*out
;
2075 out
= ofpbuf_put_zeros(buf
, sizeof *out
);
2076 out
->table_id
= stats
->table_id
;
2077 out
->active_count
= htonl(stats
->active_count
);
2078 out
->lookup_count
= htonll(stats
->lookup_count
);
2079 out
->matched_count
= htonll(stats
->matched_count
);
2083 ofputil_encode_table_stats_reply(const struct ofp_header
*request
)
2085 return ofpraw_alloc_stats_reply(request
, 0);
2089 ofputil_append_table_stats_reply(struct ofpbuf
*reply
,
2090 const struct ofputil_table_stats
*stats
,
2091 const struct ofputil_table_features
*features
)
2093 struct ofp_header
*oh
= reply
->header
;
2095 ovs_assert(stats
->table_id
== features
->table_id
);
2097 switch ((enum ofp_version
) oh
->version
) {
2099 ofputil_put_ofp10_table_stats(stats
, features
, reply
);
2103 ofputil_put_ofp11_table_stats(stats
, features
, reply
);
2107 ofputil_put_ofp12_table_stats(stats
, features
, reply
);
2113 ofputil_put_ofp13_table_stats(stats
, reply
);
2122 ofputil_decode_ofp10_table_stats(struct ofpbuf
*msg
,
2123 struct ofputil_table_stats
*stats
,
2124 struct ofputil_table_features
*features
)
2126 struct ofp10_table_stats
*ots
;
2128 ots
= ofpbuf_try_pull(msg
, sizeof *ots
);
2130 return OFPERR_OFPBRC_BAD_LEN
;
2133 features
->table_id
= ots
->table_id
;
2134 ovs_strlcpy_arrays(features
->name
, ots
->name
);
2135 features
->max_entries
= ntohl(ots
->max_entries
);
2136 features
->match
= features
->wildcard
= mf_bitmap_from_of10(ots
->wildcards
);
2138 stats
->table_id
= ots
->table_id
;
2139 stats
->active_count
= ntohl(ots
->active_count
);
2140 stats
->lookup_count
= ntohll(get_32aligned_be64(&ots
->lookup_count
));
2141 stats
->matched_count
= ntohll(get_32aligned_be64(&ots
->matched_count
));
2147 ofputil_decode_ofp11_table_stats(struct ofpbuf
*msg
,
2148 struct ofputil_table_stats
*stats
,
2149 struct ofputil_table_features
*features
)
2151 struct ofp11_table_stats
*ots
;
2153 ots
= ofpbuf_try_pull(msg
, sizeof *ots
);
2155 return OFPERR_OFPBRC_BAD_LEN
;
2158 features
->table_id
= ots
->table_id
;
2159 ovs_strlcpy_arrays(features
->name
, ots
->name
);
2160 features
->max_entries
= ntohl(ots
->max_entries
);
2161 features
->nonmiss
.instructions
= ovsinst_bitmap_from_openflow(
2162 ots
->instructions
, OFP11_VERSION
);
2163 features
->nonmiss
.write
.ofpacts
= ofpact_bitmap_from_openflow(
2164 ots
->write_actions
, OFP11_VERSION
);
2165 features
->nonmiss
.apply
.ofpacts
= ofpact_bitmap_from_openflow(
2166 ots
->write_actions
, OFP11_VERSION
);
2167 features
->miss
= features
->nonmiss
;
2168 features
->miss_config
= ofputil_decode_table_miss(ots
->config
,
2170 features
->match
= mf_bitmap_from_of11(ots
->match
);
2171 features
->wildcard
= mf_bitmap_from_of11(ots
->wildcards
);
2172 bitmap_or(features
->match
.bm
, features
->wildcard
.bm
, MFF_N_IDS
);
2174 stats
->table_id
= ots
->table_id
;
2175 stats
->active_count
= ntohl(ots
->active_count
);
2176 stats
->lookup_count
= ntohll(ots
->lookup_count
);
2177 stats
->matched_count
= ntohll(ots
->matched_count
);
2183 ofputil_decode_ofp12_table_stats(struct ofpbuf
*msg
,
2184 struct ofputil_table_stats
*stats
,
2185 struct ofputil_table_features
*features
)
2187 struct ofp12_table_stats
*ots
;
2189 ots
= ofpbuf_try_pull(msg
, sizeof *ots
);
2191 return OFPERR_OFPBRC_BAD_LEN
;
2194 features
->table_id
= ots
->table_id
;
2195 ovs_strlcpy_arrays(features
->name
, ots
->name
);
2196 features
->metadata_match
= ots
->metadata_match
;
2197 features
->metadata_write
= ots
->metadata_write
;
2198 features
->miss_config
= ofputil_decode_table_miss(ots
->config
,
2200 features
->max_entries
= ntohl(ots
->max_entries
);
2202 features
->nonmiss
.instructions
= ovsinst_bitmap_from_openflow(
2203 ots
->instructions
, OFP12_VERSION
);
2204 features
->nonmiss
.write
.ofpacts
= ofpact_bitmap_from_openflow(
2205 ots
->write_actions
, OFP12_VERSION
);
2206 features
->nonmiss
.apply
.ofpacts
= ofpact_bitmap_from_openflow(
2207 ots
->apply_actions
, OFP12_VERSION
);
2208 features
->nonmiss
.write
.set_fields
= oxm_bitmap_to_mf_bitmap(
2209 ots
->write_setfields
, OFP12_VERSION
);
2210 features
->nonmiss
.apply
.set_fields
= oxm_bitmap_to_mf_bitmap(
2211 ots
->apply_setfields
, OFP12_VERSION
);
2212 features
->miss
= features
->nonmiss
;
2214 features
->match
= oxm_bitmap_to_mf_bitmap(ots
->match
, OFP12_VERSION
);
2215 features
->wildcard
= oxm_bitmap_to_mf_bitmap(ots
->wildcards
,
2217 bitmap_or(features
->match
.bm
, features
->wildcard
.bm
, MFF_N_IDS
);
2219 stats
->table_id
= ots
->table_id
;
2220 stats
->active_count
= ntohl(ots
->active_count
);
2221 stats
->lookup_count
= ntohll(ots
->lookup_count
);
2222 stats
->matched_count
= ntohll(ots
->matched_count
);
2228 ofputil_decode_ofp13_table_stats(struct ofpbuf
*msg
,
2229 struct ofputil_table_stats
*stats
,
2230 struct ofputil_table_features
*features
)
2232 struct ofp13_table_stats
*ots
;
2234 ots
= ofpbuf_try_pull(msg
, sizeof *ots
);
2236 return OFPERR_OFPBRC_BAD_LEN
;
2239 features
->table_id
= ots
->table_id
;
2241 stats
->table_id
= ots
->table_id
;
2242 stats
->active_count
= ntohl(ots
->active_count
);
2243 stats
->lookup_count
= ntohll(ots
->lookup_count
);
2244 stats
->matched_count
= ntohll(ots
->matched_count
);
2250 ofputil_decode_table_stats_reply(struct ofpbuf
*msg
,
2251 struct ofputil_table_stats
*stats
,
2252 struct ofputil_table_features
*features
)
2254 const struct ofp_header
*oh
;
2257 ofpraw_pull_assert(msg
);
2265 memset(stats
, 0, sizeof *stats
);
2266 memset(features
, 0, sizeof *features
);
2267 features
->supports_eviction
= -1;
2268 features
->supports_vacancy_events
= -1;
2270 switch ((enum ofp_version
) oh
->version
) {
2272 return ofputil_decode_ofp10_table_stats(msg
, stats
, features
);
2275 return ofputil_decode_ofp11_table_stats(msg
, stats
, features
);
2278 return ofputil_decode_ofp12_table_stats(msg
, stats
, features
);
2283 return ofputil_decode_ofp13_table_stats(msg
, stats
, features
);
2290 /* Returns a string form of 'reason'. The return value is either a statically
2291 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
2292 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
2294 ofp_table_reason_to_string(enum ofp14_table_reason reason
,
2295 char *reasonbuf
, size_t bufsize
)
2298 case OFPTR_VACANCY_DOWN
:
2299 return "vacancy_down";
2301 case OFPTR_VACANCY_UP
:
2302 return "vacancy_up";
2305 snprintf(reasonbuf
, bufsize
, "%d", (int) reason
);
2311 ofputil_put_ofp14_table_desc(const struct ofputil_table_desc
*td
,
2312 struct ofpbuf
*b
, enum ofp_version version
)
2314 struct ofp14_table_desc
*otd
;
2315 struct ofp14_table_mod_prop_vacancy
*otv
;
2318 start_otd
= b
->size
;
2319 ofpbuf_put_zeros(b
, sizeof *otd
);
2321 ofpprop_put_u32(b
, OFPTMPT14_EVICTION
, td
->eviction_flags
);
2323 otv
= ofpbuf_put_zeros(b
, sizeof *otv
);
2324 otv
->type
= htons(OFPTMPT14_VACANCY
);
2325 otv
->length
= htons(sizeof *otv
);
2326 otv
->vacancy_down
= td
->table_vacancy
.vacancy_down
;
2327 otv
->vacancy_up
= td
->table_vacancy
.vacancy_up
;
2328 otv
->vacancy
= td
->table_vacancy
.vacancy
;
2330 otd
= ofpbuf_at_assert(b
, start_otd
, sizeof *otd
);
2331 otd
->length
= htons(b
->size
- start_otd
);
2332 otd
->table_id
= td
->table_id
;
2333 otd
->config
= ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT
,
2334 td
->eviction
, td
->vacancy
,
2338 /* Converts the abstract form of a "table status" message in '*ts' into an
2339 * OpenFlow message suitable for 'protocol', and returns that encoded form in
2340 * a buffer owned by the caller. */
2342 ofputil_encode_table_status(const struct ofputil_table_status
*ts
,
2343 enum ofputil_protocol protocol
)
2345 enum ofp_version version
;
2348 version
= ofputil_protocol_to_ofp_version(protocol
);
2349 if (version
>= OFP14_VERSION
) {
2351 struct ofp14_table_status
*ots
;
2353 raw
= OFPRAW_OFPT14_TABLE_STATUS
;
2354 b
= ofpraw_alloc_xid(raw
, version
, htonl(0), 0);
2355 ots
= ofpbuf_put_zeros(b
, sizeof *ots
);
2356 ots
->reason
= ts
->reason
;
2357 ofputil_put_ofp14_table_desc(&ts
->desc
, b
, version
);
2358 ofpmsg_update_length(b
);
2365 /* Decodes the OpenFlow "table status" message in '*ots' into an abstract form
2366 * in '*ts'. Returns 0 if successful, otherwise an OFPERR_* value. */
2368 ofputil_decode_table_status(const struct ofp_header
*oh
,
2369 struct ofputil_table_status
*ts
)
2371 const struct ofp14_table_status
*ots
;
2376 ofpbuf_use_const(&b
, oh
, ntohs(oh
->length
));
2377 raw
= ofpraw_pull_assert(&b
);
2378 ots
= ofpbuf_pull(&b
, sizeof *ots
);
2380 if (raw
== OFPRAW_OFPT14_TABLE_STATUS
) {
2381 if (ots
->reason
!= OFPTR_VACANCY_DOWN
2382 && ots
->reason
!= OFPTR_VACANCY_UP
) {
2383 return OFPERR_OFPBPC_BAD_VALUE
;
2385 ts
->reason
= ots
->reason
;
2387 error
= ofputil_decode_table_desc(&b
, &ts
->desc
, oh
->version
);
2390 return OFPERR_OFPBRC_BAD_VERSION
;
2397 ofputil_format_table_status(struct ds
*string
,
2398 const struct ofputil_table_status
*ts
,
2399 const struct ofputil_table_map
*table_map
)
2401 if (ts
->reason
== OFPTR_VACANCY_DOWN
) {
2402 ds_put_format(string
, " reason=VACANCY_DOWN");
2403 } else if (ts
->reason
== OFPTR_VACANCY_UP
) {
2404 ds_put_format(string
, " reason=VACANCY_UP");
2407 ds_put_format(string
, "\ntable_desc:-");
2408 ofputil_table_desc_format(string
, &ts
->desc
, table_map
);