/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
ofp_print_version(oh, string);
}
-static void
-ofp_print_not_implemented(struct ds *string)
-{
- ds_put_cstr(string, "NOT IMPLEMENTED YET!\n");
-}
-
static void
ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
struct list *p_buckets)
ofp_print_group(s, gm.group_id, gm.type, &gm.buckets);
}
+static const char *
+ofp13_action_to_string(uint32_t bit)
+{
+ switch (bit) {
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ case 1u << ENUM: return NAME;
+#include "ofp-util.def"
+ }
+ return NULL;
+}
+
+static void
+print_table_action_features(struct ds *s,
+ const struct ofputil_table_action_features *taf)
+{
+ ds_put_cstr(s, " actions: ");
+ ofp_print_bit_names(s, taf->actions, ofp13_action_to_string, ',');
+ ds_put_char(s, '\n');
+
+ ds_put_cstr(s, " supported on Set-Field: ");
+ if (taf->set_fields) {
+ int i;
+
+ for (i = 0; i < MFF_N_IDS; i++) {
+ uint64_t bit = UINT64_C(1) << i;
+
+ if (taf->set_fields & bit) {
+ ds_put_format(s, "%s,", mf_from_id(i)->name);
+ }
+ }
+ ds_chomp(s, ',');
+ } else {
+ ds_put_cstr(s, "none");
+ }
+ ds_put_char(s, '\n');
+}
+
+static bool
+table_action_features_equal(const struct ofputil_table_action_features *a,
+ const struct ofputil_table_action_features *b)
+{
+ return a->actions == b->actions && a->set_fields == b->set_fields;
+}
+
+static void
+print_table_instruction_features(
+ struct ds *s, const struct ofputil_table_instruction_features *tif)
+{
+ int start, end;
+
+ ds_put_cstr(s, " next tables: ");
+ for (start = bitmap_scan(tif->next, 1, 0, 255); start < 255;
+ start = bitmap_scan(tif->next, 1, end, 255)) {
+ end = bitmap_scan(tif->next, 0, start + 1, 255);
+ if (end == start + 1) {
+ ds_put_format(s, "%d,", start);
+ } else {
+ ds_put_format(s, "%d-%d,", start, end - 1);
+ }
+ }
+ ds_chomp(s, ',');
+ if (ds_last(s) == ' ') {
+ ds_put_cstr(s, "none");
+ }
+ ds_put_char(s, '\n');
+
+ ds_put_cstr(s, " instructions: ");
+ if (tif->instructions) {
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if (tif->instructions & (1u << i)) {
+ ds_put_format(s, "%s,", ovs_instruction_name_from_type(i));
+ }
+ }
+ ds_chomp(s, ',');
+ } else {
+ ds_put_cstr(s, "none");
+ }
+ ds_put_char(s, '\n');
+
+ if (table_action_features_equal(&tif->write, &tif->apply)) {
+ ds_put_cstr(s, " Write-Actions and Apply-Actions features:\n");
+ print_table_action_features(s, &tif->write);
+ } else {
+ ds_put_cstr(s, " Write-Actions features:\n");
+ print_table_action_features(s, &tif->write);
+ ds_put_cstr(s, " Apply-Actions features:\n");
+ print_table_action_features(s, &tif->apply);
+ }
+}
+
+static bool
+table_instruction_features_equal(
+ const struct ofputil_table_instruction_features *a,
+ const struct ofputil_table_instruction_features *b)
+{
+ return (bitmap_equal(a->next, b->next, 255)
+ && a->instructions == b->instructions
+ && table_action_features_equal(&a->write, &b->write)
+ && table_action_features_equal(&a->apply, &b->apply));
+}
+
+static void
+ofp_print_table_features(struct ds *s, const struct ofp_header *oh)
+{
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+
+ for (;;) {
+ struct ofputil_table_features tf;
+ int retval;
+ int i;
+
+ retval = ofputil_decode_table_features(&b, &tf, true);
+ if (retval) {
+ if (retval != EOF) {
+ ofp_print_error(s, retval);
+ }
+ return;
+ }
+
+ ds_put_format(s, "\n table %"PRIu8":\n", tf.table_id);
+ ds_put_format(s, " name=\"%s\"\n", tf.name);
+ ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n",
+ tf.metadata_match, tf.metadata_write);
+
+ ds_put_cstr(s, " config=");
+ ofp_print_table_miss_config(s, tf.config);
+
+ ds_put_format(s, " max_entries=%"PRIu32"\n", tf.max_entries);
+
+ if (table_instruction_features_equal(&tf.nonmiss, &tf.miss)) {
+ ds_put_cstr(s, " instructions (table miss and others):\n");
+ print_table_instruction_features(s, &tf.nonmiss);
+ } else {
+ ds_put_cstr(s, " instructions (other than table miss):\n");
+ print_table_instruction_features(s, &tf.nonmiss);
+ ds_put_cstr(s, " instructions (table miss):\n");
+ print_table_instruction_features(s, &tf.miss);
+ }
+
+ ds_put_cstr(s, " matching:\n");
+ for (i = 0; i < MFF_N_IDS; i++) {
+ uint64_t bit = UINT64_C(1) << i;
+
+ if (tf.match & bit) {
+ const struct mf_field *f = mf_from_id(i);
+
+ ds_put_format(s, " %s: %s\n",
+ f->name,
+ (tf.mask ? "arbitrary mask"
+ : tf.wildcard ? "exact match or wildcard"
+ : "must exact match"));
+ }
+ }
+ }
+}
+
static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
- ofp_print_not_implemented(string);
+ ofp_print_table_features(string, oh);
break;
case OFPTYPE_HELLO:
#include "unaligned.h"
#include "type-props.h"
#include "vlog.h"
+#include "bitmap.h"
VLOG_DEFINE_THIS_MODULE(ofp_util);
return b;
}
+struct ofp_prop_header {
+ ovs_be16 type;
+ ovs_be16 len;
+};
+
+static enum ofperr
+ofputil_pull_property(struct ofpbuf *msg, struct ofpbuf *payload,
+ uint16_t *typep)
+{
+ struct ofp_prop_header *oph;
+ unsigned int len;
+
+ if (msg->size < sizeof *oph) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+
+ oph = msg->data;
+ len = ntohs(oph->len);
+ if (len < sizeof *oph || ROUND_UP(len, 8) > msg->size) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+
+ *typep = ntohs(oph->type);
+ if (payload) {
+ ofpbuf_use_const(payload, msg->data, len);
+ ofpbuf_pull(payload, sizeof *oph);
+ }
+ ofpbuf_pull(msg, ROUND_UP(len, 8));
+ return 0;
+}
+
+static void PRINTF_FORMAT(2, 3)
+log_property(bool loose, const char *message, ...)
+{
+ enum vlog_level level = loose ? VLL_DBG : VLL_WARN;
+ if (!vlog_should_drop(THIS_MODULE, level, &bad_ofmsg_rl)) {
+ va_list args;
+
+ va_start(args, message);
+ vlog_valist(THIS_MODULE, level, message, args);
+ va_end(args);
+ }
+}
+
+static enum ofperr
+parse_table_ids(struct ofpbuf *payload, uint32_t *ids)
+{
+ uint16_t type;
+
+ *ids = 0;
+ while (payload->size > 0) {
+ enum ofperr error = ofputil_pull_property(payload, NULL, &type);
+ if (error) {
+ return error;
+ }
+ if (type < CHAR_BIT * sizeof *ids) {
+ *ids |= 1u << type;
+ }
+ }
+ return 0;
+}
+
+static enum ofperr
+parse_instruction_ids(struct ofpbuf *payload, bool loose, uint32_t *insts)
+{
+ *insts = 0;
+ while (payload->size > 0) {
+ enum ovs_instruction_type inst;
+ enum ofperr error;
+ uint16_t ofpit;
+
+ error = ofputil_pull_property(payload, NULL, &ofpit);
+ if (error) {
+ return error;
+ }
+
+ error = ovs_instruction_type_from_inst_type(&inst, ofpit);
+ if (!error) {
+ *insts |= 1u << inst;
+ } else if (!loose) {
+ return error;
+ }
+ }
+ return 0;
+}
+
+static enum ofperr
+parse_table_features_next_table(struct ofpbuf *payload,
+ unsigned long int *next_tables)
+{
+ size_t i;
+
+ memset(next_tables, 0, bitmap_n_bytes(255));
+ for (i = 0; i < payload->size; i++) {
+ uint8_t id = ((const uint8_t *) payload->data)[i];
+ if (id >= 255) {
+ return OFPERR_OFPTFFC_BAD_ARGUMENT;
+ }
+ bitmap_set1(next_tables, id);
+ }
+ return 0;
+}
+
+static enum ofperr
+parse_oxm(struct ofpbuf *b, bool loose,
+ const struct mf_field **fieldp, bool *hasmask)
+{
+ ovs_be32 *oxmp;
+ uint32_t oxm;
+
+ oxmp = ofpbuf_try_pull(b, sizeof *oxmp);
+ if (!oxmp) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+ oxm = ntohl(*oxmp);
+
+ /* Determine '*hasmask'. If 'oxm' is masked, convert it to the equivalent
+ * unmasked version, because the table of OXM fields we support only has
+ * masked versions of fields that we support with masks, but we should be
+ * able to parse the masked versions of those here. */
+ *hasmask = NXM_HASMASK(oxm);
+ if (*hasmask) {
+ if (NXM_LENGTH(oxm) & 1) {
+ return OFPERR_OFPTFFC_BAD_ARGUMENT;
+ }
+ oxm = NXM_HEADER(NXM_VENDOR(oxm), NXM_FIELD(oxm), NXM_LENGTH(oxm) / 2);
+ }
+
+ *fieldp = mf_from_nxm_header(oxm);
+ if (!*fieldp) {
+ log_property(loose, "unknown OXM field %#"PRIx32, ntohl(*oxmp));
+ }
+ return *fieldp ? 0 : OFPERR_OFPBMC_BAD_FIELD;
+}
+
+static enum ofperr
+parse_oxms(struct ofpbuf *payload, bool loose,
+ uint64_t *exactp, uint64_t *maskedp)
+{
+ uint64_t exact, masked;
+
+ exact = masked = 0;
+ while (payload->size > 0) {
+ const struct mf_field *field;
+ enum ofperr error;
+ bool hasmask;
+
+ error = parse_oxm(payload, loose, &field, &hasmask);
+ if (!error) {
+ if (hasmask) {
+ masked |= UINT64_C(1) << field->id;
+ } else {
+ exact |= UINT64_C(1) << field->id;
+ }
+ } else if (error != OFPERR_OFPBMC_BAD_FIELD || !loose) {
+ return error;
+ }
+ }
+ if (exactp) {
+ *exactp = exact;
+ } else if (exact) {
+ return OFPERR_OFPBMC_BAD_MASK;
+ }
+ if (maskedp) {
+ *maskedp = masked;
+ } else if (masked) {
+ return OFPERR_OFPBMC_BAD_MASK;
+ }
+ return 0;
+}
+
+/* Converts an OFPMP_TABLE_FEATURES request or reply in 'msg' into an abstract
+ * ofputil_table_features in 'tf'.
+ *
+ * If 'loose' is true, this function ignores properties and values that it does
+ * not understand, as a controller would want to do when interpreting
+ * capabilities provided by a switch. If 'loose' is false, this function
+ * treats unknown properties and values as an error, as a switch would want to
+ * do when interpreting a configuration request made by a controller.
+ *
+ * A single OpenFlow message can specify features for multiple tables. Calling
+ * this function multiple times for a single 'msg' iterates through the tables
+ * in the message. The caller must initially leave 'msg''s layer pointers null
+ * and not modify them between calls.
+ *
+ * Returns 0 if successful, EOF if no tables were left in this 'msg', otherwise
+ * a positive "enum ofperr" value. */
+int
+ofputil_decode_table_features(struct ofpbuf *msg,
+ struct ofputil_table_features *tf, bool loose)
+{
+ struct ofp13_table_features *otf;
+ unsigned int len;
+
+ if (!msg->l2) {
+ msg->l2 = msg->data;
+ ofpraw_pull_assert(msg);
+ }
+
+ if (!msg->size) {
+ return EOF;
+ }
+
+ if (msg->size < sizeof *otf) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+
+ otf = msg->data;
+ len = ntohs(otf->length);
+ if (len < sizeof *otf || len % 8 || len > msg->size) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+ ofpbuf_pull(msg, sizeof *otf);
+
+ tf->table_id = otf->table_id;
+ if (tf->table_id == OFPTT_ALL) {
+ return OFPERR_OFPTFFC_BAD_TABLE;
+ }
+
+ ovs_strlcpy(tf->name, otf->name, OFP_MAX_TABLE_NAME_LEN);
+ tf->metadata_match = otf->metadata_match;
+ tf->metadata_write = otf->metadata_write;
+ tf->config = ntohl(otf->config);
+ tf->max_entries = ntohl(otf->max_entries);
+
+ while (msg->size > 0) {
+ struct ofpbuf payload;
+ enum ofperr error;
+ uint16_t type;
+
+ error = ofputil_pull_property(msg, &payload, &type);
+ if (error) {
+ return error;
+ }
+
+ switch ((enum ofp13_table_feature_prop_type) type) {
+ case OFPTFPT13_INSTRUCTIONS:
+ error = parse_instruction_ids(&payload, loose,
+ &tf->nonmiss.instructions);
+ break;
+ case OFPTFPT13_INSTRUCTIONS_MISS:
+ error = parse_instruction_ids(&payload, loose,
+ &tf->miss.instructions);
+ break;
+
+ case OFPTFPT13_NEXT_TABLES:
+ error = parse_table_features_next_table(&payload,
+ tf->nonmiss.next);
+ break;
+ case OFPTFPT13_NEXT_TABLES_MISS:
+ error = parse_table_features_next_table(&payload, tf->miss.next);
+ break;
+
+ case OFPTFPT13_WRITE_ACTIONS:
+ error = parse_table_ids(&payload, &tf->nonmiss.write.actions);
+ break;
+ case OFPTFPT13_WRITE_ACTIONS_MISS:
+ error = parse_table_ids(&payload, &tf->miss.write.actions);
+ break;
+
+ case OFPTFPT13_APPLY_ACTIONS:
+ error = parse_table_ids(&payload, &tf->nonmiss.apply.actions);
+ break;
+ case OFPTFPT13_APPLY_ACTIONS_MISS:
+ error = parse_table_ids(&payload, &tf->miss.apply.actions);
+ break;
+
+ case OFPTFPT13_MATCH:
+ error = parse_oxms(&payload, loose, &tf->match, &tf->mask);
+ break;
+ case OFPTFPT13_WILDCARDS:
+ error = parse_oxms(&payload, loose, &tf->wildcard, NULL);
+ break;
+
+ case OFPTFPT13_WRITE_SETFIELD:
+ error = parse_oxms(&payload, loose,
+ &tf->nonmiss.write.set_fields, NULL);
+ break;
+ case OFPTFPT13_WRITE_SETFIELD_MISS:
+ error = parse_oxms(&payload, loose,
+ &tf->miss.write.set_fields, NULL);
+ break;
+ case OFPTFPT13_APPLY_SETFIELD:
+ error = parse_oxms(&payload, loose,
+ &tf->nonmiss.apply.set_fields, NULL);
+ break;
+ case OFPTFPT13_APPLY_SETFIELD_MISS:
+ error = parse_oxms(&payload, loose,
+ &tf->miss.apply.set_fields, NULL);
+ break;
+
+ case OFPTFPT13_EXPERIMENTER:
+ case OFPTFPT13_EXPERIMENTER_MISS:
+ log_property(loose,
+ "unknown table features experimenter property");
+ error = loose ? 0 : OFPERR_OFPTFFC_BAD_TYPE;
+ break;
+ }
+ if (error) {
+ return error;
+ }
+ }
+
+ /* Fix inconsistencies:
+ *
+ * - Turn off 'mask' and 'wildcard' bits that are not in 'match',
+ * because a field must be matchable to be masked or wildcarded.
+ *
+ * - Turn on 'wildcard' bits that are set in 'mask', because a field
+ * that is arbitrarily maskable can be wildcarded entirely. */
+ tf->mask &= tf->match;
+ tf->wildcard &= tf->match;
+
+ tf->wildcard |= tf->mask;
+
+ return 0;
+}
+
+/* Encodes and returns a request to obtain the table features of a switch.
+ * The message is encoded for OpenFlow version 'ofp_version'. */
+struct ofpbuf *
+ofputil_encode_table_features_request(enum ofp_version ofp_version)
+{
+ struct ofpbuf *request = NULL;
+
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ ovs_fatal(0, "dump-table-features needs OpenFlow 1.3 or later "
+ "(\'-O OpenFlow13\')");
+ case OFP13_VERSION:
+ case OFP14_VERSION:
+ request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
+ ofp_version, 0);
+ break;
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ return request;
+}
+
/* ofputil_table_mod */
/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
: "Unknown action";
}
+enum ofputil_action_code
+ofputil_action_code_from_ofp13_action(enum ofp13_action_type type)
+{
+ switch (type) {
+
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ case ENUM: \
+ return OFPUTIL_##ENUM;
+#include "ofp-util.def"
+
+ default:
+ return OFPUTIL_ACTION_INVALID;
+ }
+}
+
/* Appends an action of the type specified by 'code' to 'buf' and returns the
* action. Initializes the parts of 'action' that identify it as having type
* <ENUM> and length 'sizeof *action' and zeros the rest. For actions that
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include "bitmap.h"
#include "compiler.h"
#include "flow.h"
#include "list.h"
struct ofpbuf *ofputil_encode_table_mod(const struct ofputil_table_mod *,
enum ofputil_protocol);
+/* Abstract ofp_table_features. */
+struct ofputil_table_features {
+ uint8_t table_id; /* Identifier of table. Lower numbered tables
+ are consulted first. */
+ char name[OFP_MAX_TABLE_NAME_LEN];
+ ovs_be64 metadata_match; /* Bits of metadata table can match. */
+ ovs_be64 metadata_write; /* Bits of metadata table can write. */
+ uint32_t config; /* Bitmap of OFPTC_* values */
+ uint32_t max_entries; /* Max number of entries supported. */
+
+ /* Table features related to instructions. There are two instances:
+ *
+ * - 'miss' reports features available in the table miss flow.
+ *
+ * - 'nonmiss' reports features available in other flows. */
+ struct ofputil_table_instruction_features {
+ /* Tables that "goto-table" may jump to. */
+ unsigned long int next[BITMAP_N_LONGS(255)];
+
+ /* Bitmap of OVSINST_* for supported instructions. */
+ uint32_t instructions;
+
+ /* Table features related to actions. There are two instances:
+ *
+ * - 'write' reports features available in a "write_actions"
+ * instruction.
+ *
+ * - 'apply' reports features available in an "apply_actions"
+ * instruction. */
+ struct ofputil_table_action_features {
+ uint32_t actions; /* Bitmap of supported OFPAT*. */
+ uint64_t set_fields; /* Bitmap of MFF_* "set-field" supports. */
+ } write, apply;
+ } nonmiss, miss;
+
+ /* MFF_* bitmaps.
+ *
+ * For any given field the following combinations are valid:
+ *
+ * - match=0, wildcard=0, mask=0: Flows in this table cannot match on
+ * this field.
+ *
+ * - match=1, wildcard=0, mask=0: Flows in this table must match on all
+ * the bits in this field.
+ *
+ * - match=1, wildcard=1, mask=0: Flows in this table must either match
+ * on all the bits in the field or wildcard the field entirely.
+ *
+ * - match=1, wildcard=1, mask=1: Flows in this table may arbitrarily
+ * mask this field (as special cases, they may match on all the bits
+ * or wildcard it entirely).
+ *
+ * Other combinations do not make sense.
+ */
+ uint64_t match; /* Fields that may be matched. */
+ uint64_t mask; /* Subset of 'match' that may have masks. */
+ uint64_t wildcard; /* Subset of 'match' that may be wildcarded. */
+};
+
+int ofputil_decode_table_features(struct ofpbuf *,
+ struct ofputil_table_features *, bool loose);
+struct ofpbuf *ofputil_encode_table_features_request(
+ enum ofp_version ofp_version);
+void ofputil_append_table_features_reply(
+ const struct ofputil_table_features *tf,
+ struct list *replies);
+
+uint16_t table_feature_prop_get_size(enum ofp13_table_feature_prop_type type);
+char *table_feature_prop_get_name(enum ofp13_table_feature_prop_type type);
+
/* Meter band configuration for all supported band types. */
struct ofputil_meter_band {
uint16_t type;
int ofputil_action_code_from_name(const char *);
const char * ofputil_action_name_from_code(enum ofputil_action_code code);
+enum ofputil_action_code ofputil_action_code_from_ofp13_action(
+ enum ofp13_action_type type);
void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
])
AT_CLEANUP
+AT_SETUP([OFPST_TABLE_FEATURES request - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 13 09 40 00 00 00 d5 00 0c 00 01 00 00 00 00 \
+09 30 00 00 00 00 00 00 74 61 62 6c 65 30 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff \
+ff ff ff ff ff ff ff ff 00 00 00 03 00 0f 42 40 \
+00 00 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \
+00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \
+00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \
+00 01 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \
+00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \
+00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \
+00 02 01 01 01 02 03 04 05 06 07 08 09 0a 0b 0c \
+0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c \
+1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c \
+2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c \
+3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c \
+4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c \
+5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c \
+6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c \
+7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c \
+8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c \
+9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac \
+ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc \
+bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc \
+cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc \
+dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec \
+ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc \
+fd 00 00 00 00 00 00 00 00 03 01 01 01 02 03 04 \
+05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 \
+15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 \
+25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 \
+35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 \
+45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 \
+55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 \
+65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 \
+75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 \
+85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 \
+95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 \
+a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 \
+b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 \
+c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 \
+d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 \
+e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 \
+f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \
+00 04 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \
+00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \
+00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \
+00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \
+00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \
+00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \
+00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \
+00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \
+00 00 00 00 00 00 00 00 00 05 00 84 00 00 00 08 \
+00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \
+00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \
+00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \
+00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \
+00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \
+00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \
+00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \
+00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \
+00 06 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \
+00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \
+00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \
+00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \
+00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \
+00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \
+00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \
+00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \
+00 00 00 00 00 00 00 00 00 07 00 84 00 00 00 08 \
+00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \
+00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \
+00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \
+00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \
+00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \
+00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \
+00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \
+00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \
+00 08 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \
+80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \
+80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \
+80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \
+80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \
+80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \
+00 0a 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \
+80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \
+80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \
+80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \
+80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \
+80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \
+00 0c 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \
+80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \
+80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \
+80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \
+80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \
+80 00 22 02 80 00 24 02 00 0d 00 a8 80 00 4c 08 \
+00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \
+80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \
+00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \
+00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \
+00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \
+80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \
+00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \
+80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+00 0e 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \
+80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \
+80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \
+80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \
+80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \
+80 00 22 02 80 00 24 02 00 0f 00 a8 80 00 4c 08 \
+00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \
+80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \
+00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \
+00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \
+00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \
+80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \
+00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \
+80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+"], [0], [OFPST_TABLE_FEATURES reply (OF1.3) (xid=0xd5):
+ table 0:
+ name="table0"
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ config=Unknown
+ max_entries=1000000
+ instructions (table miss and others):
+ next tables: 1-253
+ instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table
+ Write-Actions and Apply-Actions features:
+ actions: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb
+ supported on Set-Field: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst
+ matching:
+ tun_id: exact match or wildcard
+ tun_src: exact match or wildcard
+ tun_dst: exact match or wildcard
+ metadata: exact match or wildcard
+ in_port: exact match or wildcard
+ in_port_oxm: exact match or wildcard
+ pkt_mark: exact match or wildcard
+ reg0: exact match or wildcard
+ reg1: exact match or wildcard
+ reg2: exact match or wildcard
+ reg3: exact match or wildcard
+ reg4: exact match or wildcard
+ reg5: exact match or wildcard
+ reg6: exact match or wildcard
+ reg7: exact match or wildcard
+ eth_src: exact match or wildcard
+ eth_dst: exact match or wildcard
+ eth_type: exact match or wildcard
+ vlan_tci: exact match or wildcard
+ vlan_vid: exact match or wildcard
+ vlan_pcp: exact match or wildcard
+ mpls_label: exact match or wildcard
+ mpls_tc: exact match or wildcard
+ mpls_bos: exact match or wildcard
+ ip_src: exact match or wildcard
+ ip_dst: exact match or wildcard
+ ipv6_src: exact match or wildcard
+ ipv6_dst: exact match or wildcard
+ ipv6_label: exact match or wildcard
+ nw_proto: exact match or wildcard
+ nw_tos: exact match or wildcard
+ ip_dscp: exact match or wildcard
+ nw_ecn: exact match or wildcard
+ nw_ttl: exact match or wildcard
+ ip_frag: exact match or wildcard
+ arp_op: exact match or wildcard
+ arp_spa: exact match or wildcard
+ arp_tpa: exact match or wildcard
+ arp_sha: exact match or wildcard
+ arp_tha: exact match or wildcard
+ tcp_src: exact match or wildcard
+ tcp_dst: exact match or wildcard
+ tcp_flags: exact match or wildcard
+ udp_src: exact match or wildcard
+ udp_dst: exact match or wildcard
+ sctp_src: exact match or wildcard
+ sctp_dst: exact match or wildcard
+ icmp_type: exact match or wildcard
+ icmp_code: exact match or wildcard
+ icmpv6_type: exact match or wildcard
+ icmpv6_code: exact match or wildcard
+ nd_target: exact match or wildcard
+ nd_sll: exact match or wildcard
+ nd_tll: exact match or wildcard
+])
+AT_CLEANUP
+
AT_SETUP([OFPT_BARRIER_REQUEST - OF1.0])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print '01 12 00 08 00 00 00 01'], [0], [dnl
\fBdump\-tables \fIswitch\fR
Prints to the console statistics for each of the flow tables used by
\fIswitch\fR.
+.TP
+\fBdump\-table\-features \fIswitch\fR
+Prints to the console features for each of the flow tables used by
+\fIswitch\fR.
.
.TP
\fBdump\-ports \fIswitch\fR [\fInetdev\fR]
" show SWITCH show OpenFlow information\n"
" dump-desc SWITCH print switch description\n"
" dump-tables SWITCH print table stats\n"
+ " dump-table-features SWITCH print table features\n"
" mod-port SWITCH IFACE ACT modify port behavior\n"
" mod-table SWITCH MOD modify flow table behavior\n"
" get-frags SWITCH print fragment handling behavior\n"
dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_TABLE_REQUEST);
}
+static void
+ofctl_dump_table_features(int argc OVS_UNUSED, char *argv[])
+{
+ struct ofpbuf *request;
+ struct vconn *vconn;
+
+ open_vconn(argv[1], &vconn);
+ request = ofputil_encode_table_features_request(vconn_get_version(vconn));
+ if (request) {
+ dump_stats_transaction(vconn, request);
+ }
+
+ vconn_close(vconn);
+}
+
static bool
fetch_port_by_features(const char *vconn_name,
const char *port_name, ofp_port_t port_no,
{ "snoop", 1, 1, ofctl_snoop },
{ "dump-desc", 1, 1, ofctl_dump_desc },
{ "dump-tables", 1, 1, ofctl_dump_tables },
+ { "dump-table-features", 1, 1, ofctl_dump_table_features },
{ "dump-flows", 1, 2, ofctl_dump_flows },
{ "dump-aggregate", 1, 2, ofctl_dump_aggregate },
{ "queue-stats", 1, 3, ofctl_queue_stats },