summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2014-07-26 13:09:42 -0700
committerBen Pfaff <blp@nicira.com>2014-07-28 11:11:50 -0700
commit7e9d7cc5a6749a47994e82307ea717626bc9095e (patch)
tree7f76eab1708a06e73d3f8b22127c59c8af607e06
parent75c61f5e6e54ee628140c64a39267979407a8977 (diff)
downloadopenvswitch-7e9d7cc5a6749a47994e82307ea717626bc9095e.tar.gz
Better abstract table stats, using OpenFlow 1.3+ table features.
Until now, the OpenFlow "table stats" have not been well abstracted. They have mostly used the raw ofp12_table_stats structure and translated to and from that. That works OK for simple purposes, but it falls apart for the "table features" introduced in OpenFlow 1.3, which are a superset of the previous table stats but broken apart differently. This commit refactors the internals to split "table stats" and "table features" in the way done in OpenFlow 1.3 and use both of these structures in the cases where previous versions of the protocol had just table stats. The refactoring in this commit makes it much easier to implement the OpenFlow 1.3 "table features request", which thus far Open vSwitch has omitted. Signed-off-by: Ben Pfaff <blp@nicira.com>
-rw-r--r--lib/ofp-print.c387
-rw-r--r--lib/ofp-util.c514
-rw-r--r--lib/ofp-util.h35
-rw-r--r--ofproto/ofproto-dpif.c33
-rw-r--r--ofproto/ofproto-provider.h68
-rw-r--r--ofproto/ofproto.c168
-rw-r--r--tests/ofp-print.at100
-rw-r--r--tests/ofproto-dpif.at51
-rw-r--r--tests/ofproto.at108
9 files changed, 848 insertions, 616 deletions
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 2b0b20f2b..01d34b1cf 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -51,7 +51,9 @@
static void ofp_print_queue_name(struct ds *string, uint32_t port);
static void ofp_print_error(struct ds *, enum ofperr);
-
+static void ofp_print_table_features(struct ds *,
+ const struct ofputil_table_features *,
+ const struct ofputil_table_stats *);
/* Returns a string that represents the contents of the Ethernet frame in the
* 'len' bytes starting at 'data'. The caller must free the returned string.*/
@@ -1573,216 +1575,27 @@ ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
}
static void
-ofp_print_one_ofpst_table_reply(struct ds *string, enum ofp_version ofp_version,
- const char *name, struct ofp12_table_stats *ts)
-{
- char name_[OFP_MAX_TABLE_NAME_LEN + 1];
-
- /* ofp13_table_stats is different */
- if (ofp_version > OFP12_VERSION) {
- return;
- }
-
- ovs_strlcpy(name_, name, sizeof name_);
-
- ds_put_format(string, " %d: %-8s: ", ts->table_id, name_);
- ds_put_format(string, "wild=0x%05"PRIx64", ", ntohll(ts->wildcards));
- ds_put_format(string, "max=%6"PRIu32", ", ntohl(ts->max_entries));
- ds_put_format(string, "active=%"PRIu32"\n", ntohl(ts->active_count));
- ds_put_cstr(string, " ");
- ds_put_format(string, "lookup=%"PRIu64", ", ntohll(ts->lookup_count));
- ds_put_format(string, "matched=%"PRIu64"\n", ntohll(ts->matched_count));
-
- if (ofp_version < OFP11_VERSION) {
- return;
- }
-
- ds_put_cstr(string, " ");
- ds_put_format(string, "match=0x%08"PRIx64", ", ntohll(ts->match));
- ds_put_format(string, "instructions=0x%08"PRIx32", ",
- ntohl(ts->instructions));
- ds_put_format(string, "config=0x%08"PRIx32"\n", ntohl(ts->config));
- ds_put_cstr(string, " ");
- ds_put_format(string, "write_actions=0x%08"PRIx32", ",
- ntohl(ts->write_actions));
- ds_put_format(string, "apply_actions=0x%08"PRIx32"\n",
- ntohl(ts->apply_actions));
-
- if (ofp_version < OFP12_VERSION) {
- return;
- }
-
- ds_put_cstr(string, " ");
- ds_put_format(string, "write_setfields=0x%016"PRIx64"\n",
- ntohll(ts->write_setfields));
- ds_put_cstr(string, " ");
- ds_put_format(string, "apply_setfields=0x%016"PRIx64"\n",
- ntohll(ts->apply_setfields));
- ds_put_cstr(string, " ");
- ds_put_format(string, "metadata_match=0x%016"PRIx64"\n",
- ntohll(ts->metadata_match));
- ds_put_cstr(string, " ");
- ds_put_format(string, "metadata_write=0x%016"PRIx64"\n",
- ntohll(ts->metadata_write));
-}
-
-static void
-ofp_print_ofpst_table_reply13(struct ds *string, const struct ofp_header *oh,
- int verbosity)
-{
- struct ofp13_table_stats *ts;
- struct ofpbuf b;
- size_t n;
-
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
- ofpraw_pull_assert(&b);
-
- n = ofpbuf_size(&b) / sizeof *ts;
- ds_put_format(string, " %"PRIuSIZE" tables\n", n);
- if (verbosity < 1) {
- return;
- }
-
- for (;;) {
- ts = ofpbuf_try_pull(&b, sizeof *ts);
- if (!ts) {
- return;
- }
- ds_put_format(string,
- " %d: active=%"PRIu32", lookup=%"PRIu64 \
- ", matched=%"PRIu64"\n",
- ts->table_id, ntohl(ts->active_count),
- ntohll(ts->lookup_count), ntohll(ts->matched_count));
- }
-}
-
-static void
-ofp_print_ofpst_table_reply12(struct ds *string, const struct ofp_header *oh,
- int verbosity)
-{
- struct ofp12_table_stats *ts;
- struct ofpbuf b;
- size_t n;
-
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
- ofpraw_pull_assert(&b);
-
- n = ofpbuf_size(&b) / sizeof *ts;
- ds_put_format(string, " %"PRIuSIZE" tables\n", n);
- if (verbosity < 1) {
- return;
- }
-
- for (;;) {
- ts = ofpbuf_try_pull(&b, sizeof *ts);
- if (!ts) {
- return;
- }
-
- ofp_print_one_ofpst_table_reply(string, OFP12_VERSION, ts->name, ts);
- }
-}
-
-static void
-ofp_print_ofpst_table_reply11(struct ds *string, const struct ofp_header *oh,
- int verbosity)
-{
- struct ofp11_table_stats *ts;
- struct ofpbuf b;
- size_t n;
-
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
- ofpraw_pull_assert(&b);
-
- n = ofpbuf_size(&b) / sizeof *ts;
- ds_put_format(string, " %"PRIuSIZE" tables\n", n);
- if (verbosity < 1) {
- return;
- }
-
- for (;;) {
- struct ofp12_table_stats ts12;
-
- ts = ofpbuf_try_pull(&b, sizeof *ts);
- if (!ts) {
- return;
- }
-
- ts12.table_id = ts->table_id;
- ts12.wildcards = htonll(ntohl(ts->wildcards));
- ts12.max_entries = ts->max_entries;
- ts12.active_count = ts->active_count;
- ts12.lookup_count = ts->lookup_count;
- ts12.matched_count = ts->matched_count;
- ts12.match = htonll(ntohl(ts->match));
- ts12.instructions = ts->instructions;
- ts12.config = ts->config;
- ts12.write_actions = ts->write_actions;
- ts12.apply_actions = ts->apply_actions;
- ofp_print_one_ofpst_table_reply(string, OFP11_VERSION, ts->name, &ts12);
- }
-}
-
-static void
-ofp_print_ofpst_table_reply10(struct ds *string, const struct ofp_header *oh,
- int verbosity)
+ofp_print_table_stats_reply(struct ds *string, const struct ofp_header *oh)
{
- struct ofp10_table_stats *ts;
struct ofpbuf b;
- size_t n;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpraw_pull_assert(&b);
- n = ofpbuf_size(&b) / sizeof *ts;
- ds_put_format(string, " %"PRIuSIZE" tables\n", n);
- if (verbosity < 1) {
- return;
- }
-
for (;;) {
- struct ofp12_table_stats ts12;
+ struct ofputil_table_features features;
+ struct ofputil_table_stats stats;
+ int retval;
- ts = ofpbuf_try_pull(&b, sizeof *ts);
- if (!ts) {
+ retval = ofputil_decode_table_stats_reply(&b, &stats, &features);
+ if (retval) {
+ if (retval != EOF) {
+ ofp_print_error(string, retval);
+ }
return;
}
- ts12.table_id = ts->table_id;
- ts12.wildcards = htonll(ntohl(ts->wildcards));
- ts12.max_entries = ts->max_entries;
- ts12.active_count = ts->active_count;
- ts12.lookup_count = get_32aligned_be64(&ts->lookup_count);
- ts12.matched_count = get_32aligned_be64(&ts->matched_count);
- ofp_print_one_ofpst_table_reply(string, OFP10_VERSION, ts->name, &ts12);
- }
-}
-
-static void
-ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
- int verbosity)
-{
- switch ((enum ofp_version)oh->version) {
- case OFP15_VERSION:
- case OFP14_VERSION:
- case OFP13_VERSION:
- ofp_print_ofpst_table_reply13(string, oh, verbosity);
- break;
-
- case OFP12_VERSION:
- ofp_print_ofpst_table_reply12(string, oh, verbosity);
- break;
-
- case OFP11_VERSION:
- ofp_print_ofpst_table_reply11(string, oh, verbosity);
- break;
-
- case OFP10_VERSION:
- ofp_print_ofpst_table_reply10(string, oh, verbosity);
- break;
-
- default:
- OVS_NOT_REACHED();
+ ofp_print_table_features(string, &features, &stats);
}
}
@@ -2495,22 +2308,21 @@ static void
print_table_action_features(struct ds *s,
const struct ofputil_table_action_features *taf)
{
- ds_put_cstr(s, " actions: ");
- ofpact_bitmap_format(taf->ofpacts, s);
- ds_put_char(s, '\n');
+ if (taf->ofpacts) {
+ ds_put_cstr(s, " actions: ");
+ ofpact_bitmap_format(taf->ofpacts, s);
+ ds_put_char(s, '\n');
+ }
- ds_put_cstr(s, " supported on Set-Field: ");
if (!bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS)) {
int i;
+ ds_put_cstr(s, " supported on Set-Field:");
BITMAP_FOR_EACH_1 (i, MFF_N_IDS, taf->set_fields.bm) {
- ds_put_format(s, "%s,", mf_from_id(i)->name);
+ ds_put_format(s, " %s", mf_from_id(i)->name);
}
- ds_chomp(s, ',');
- } else {
- ds_put_cstr(s, "none");
+ ds_put_char(s, '\n');
}
- ds_put_char(s, '\n');
}
static bool
@@ -2521,30 +2333,38 @@ table_action_features_equal(const struct ofputil_table_action_features *a,
&& bitmap_equal(a->set_fields.bm, b->set_fields.bm, MFF_N_IDS));
}
+static bool
+table_action_features_empty(const struct ofputil_table_action_features *taf)
+{
+ return !taf->ofpacts && bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS);
+}
+
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);
+ if (!bitmap_is_all_zeros(tif->next, 255)) {
+ 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_chomp(s, ',');
- if (ds_last(s) == ' ') {
- ds_put_cstr(s, "none");
- }
- ds_put_char(s, '\n');
- ds_put_cstr(s, " instructions: ");
if (tif->instructions) {
+ ds_put_cstr(s, " instructions: ");
int i;
for (i = 0; i < 32; i++) {
@@ -2553,19 +2373,18 @@ print_table_instruction_features(
}
}
ds_chomp(s, ',');
- } else {
- ds_put_cstr(s, "none");
+ ds_put_char(s, '\n');
}
- 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 {
+ if (!table_action_features_equal(&tif->write, &tif->apply)) {
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);
+ } else if (tif->write.ofpacts
+ || !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) {
+ ds_put_cstr(s, " Write-Actions and Apply-Actions features:\n");
+ print_table_action_features(s, &tif->write);
}
}
@@ -2580,51 +2399,65 @@ table_instruction_features_equal(
&& table_action_features_equal(&a->apply, &b->apply));
}
-static void
-ofp_print_table_features(struct ds *s, const struct ofp_header *oh)
+static bool
+table_instruction_features_empty(
+ const struct ofputil_table_instruction_features *tif)
{
- struct ofpbuf b;
-
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
- for (;;) {
- struct ofputil_table_features tf;
- int retval;
- int i;
+ return (bitmap_is_all_zeros(tif->next, 255)
+ && !tif->instructions
+ && table_action_features_empty(&tif->write)
+ && table_action_features_empty(&tif->apply));
+}
- retval = ofputil_decode_table_features(&b, &tf, true);
- if (retval) {
- if (retval != EOF) {
- ofp_print_error(s, retval);
- }
- return;
- }
+static void
+ofp_print_table_features(struct ds *s,
+ const struct ofputil_table_features *features,
+ const struct ofputil_table_stats *stats)
+{
+ int i;
- ds_put_format(s, "\n table %"PRIu8":\n", tf.table_id);
- ds_put_format(s, " name=\"%s\"\n", tf.name);
+ ds_put_format(s, "\n table %"PRIu8, features->table_id);
+ if (features->name[0]) {
+ ds_put_format(s, " (\"%s\")", features->name);
+ }
+ ds_put_cstr(s, ":\n");
+ if (stats) {
+ ds_put_format(s, " active=%"PRIu32", ", stats->active_count);
+ ds_put_format(s, "lookup=%"PRIu64", ", stats->lookup_count);
+ ds_put_format(s, "matched=%"PRIu64"\n", stats->matched_count);
+ }
+ if (features->metadata_match || features->metadata_match) {
ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n",
- ntohll(tf.metadata_match), ntohll(tf.metadata_write));
+ ntohll(features->metadata_match),
+ ntohll(features->metadata_write));
+ }
+ if (features->config) {
ds_put_cstr(s, " config=");
- ofp_print_table_miss_config(s, tf.config);
+ ofp_print_table_miss_config(s, features->config);
+ }
- ds_put_format(s, " max_entries=%"PRIu32"\n", tf.max_entries);
+ if (features->max_entries) {
+ ds_put_format(s, " max_entries=%"PRIu32"\n", features->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);
- }
+ if (!table_instruction_features_equal(&features->nonmiss,
+ &features->miss)) {
+ ds_put_cstr(s, " instructions (other than table miss):\n");
+ print_table_instruction_features(s, &features->nonmiss);
+ ds_put_cstr(s, " instructions (table miss):\n");
+ print_table_instruction_features(s, &features->miss);
+ } else if (!table_instruction_features_empty(&features->nonmiss)) {
+ ds_put_cstr(s, " instructions (table miss and others):\n");
+ print_table_instruction_features(s, &features->nonmiss);
+ }
+ if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)){
ds_put_cstr(s, " matching:\n");
- BITMAP_FOR_EACH_1 (i, MFF_N_IDS, tf.match.bm) {
+ BITMAP_FOR_EACH_1 (i, MFF_N_IDS, features->match.bm) {
const struct mf_field *f = mf_from_id(i);
- bool mask = bitmap_is_set(tf.mask.bm, i);
- bool wildcard = bitmap_is_set(tf.wildcard.bm, i);
+ bool mask = bitmap_is_set(features->mask.bm, i);
+ bool wildcard = bitmap_is_set(features->wildcard.bm, i);
ds_put_format(s, " %s: %s\n",
f->name,
@@ -2635,6 +2468,28 @@ ofp_print_table_features(struct ds *s, const struct ofp_header *oh)
}
}
+static void
+ofp_print_table_features_reply(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;
+
+ retval = ofputil_decode_table_features(&b, &tf, true);
+ if (retval) {
+ if (retval != EOF) {
+ ofp_print_error(s, retval);
+ }
+ return;
+ }
+ ofp_print_table_features(s, &tf, NULL);
+ }
+}
+
static const char *
bundle_flags_to_name(uint32_t bit)
{
@@ -2760,7 +2615,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
- ofp_print_table_features(string, oh);
+ ofp_print_table_features_reply(string, oh);
break;
case OFPTYPE_HELLO:
@@ -2911,7 +2766,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
case OFPTYPE_TABLE_STATS_REPLY:
ofp_print_stats(string, oh);
- ofp_print_ofpst_table_reply(string, oh, verbosity);
+ ofp_print_table_stats_reply(string, oh);
break;
case OFPTYPE_AGGREGATE_STATS_REPLY:
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 0b78fee1b..c6027301d 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -4606,6 +4606,8 @@ ofputil_decode_table_features(struct ofpbuf *msg,
struct ofp13_table_features *otf;
unsigned int len;
+ memset(tf, 0, sizeof *tf);
+
if (!msg->frame) {
ofpraw_pull_assert(msg);
}
@@ -4991,108 +4993,160 @@ ofputil_decode_role_status(const struct ofp_header *oh,
/* Table stats. */
+/* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be
+ * matched and a field that must be wildcarded. This function returns a bitmap
+ * that contains both kinds of fields. */
+static struct mf_bitmap
+wild_or_nonmatchable_fields(const struct ofputil_table_features *features)
+{
+ struct mf_bitmap wc = features->match;
+ bitmap_not(wc.bm, MFF_N_IDS);
+ bitmap_or(wc.bm, features->wildcard.bm, MFF_N_IDS);
+ return wc;
+}
+
+struct ofp10_wc_map {
+ enum ofp10_flow_wildcards wc10;
+ enum mf_field_id mf;
+};
+
+static const struct ofp10_wc_map ofp10_wc_map[] = {
+ { OFPFW10_IN_PORT, MFF_IN_PORT },
+ { OFPFW10_DL_VLAN, MFF_VLAN_VID },
+ { OFPFW10_DL_SRC, MFF_ETH_SRC },
+ { OFPFW10_DL_DST, MFF_ETH_DST},
+ { OFPFW10_DL_TYPE, MFF_ETH_TYPE },
+ { OFPFW10_NW_PROTO, MFF_IP_PROTO },
+ { OFPFW10_TP_SRC, MFF_TCP_SRC },
+ { OFPFW10_TP_DST, MFF_TCP_DST },
+ { OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC },
+ { OFPFW10_NW_DST_MASK, MFF_IPV4_DST },
+ { OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP },
+ { OFPFW10_NW_TOS, MFF_IP_DSCP },
+};
+
+static ovs_be32
+mf_bitmap_to_of10(const struct mf_bitmap *fields)
+{
+ const struct ofp10_wc_map *p;
+ uint32_t wc10 = 0;
+
+ for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) {
+ if (bitmap_is_set(fields->bm, p->mf)) {
+ wc10 |= p->wc10;
+ }
+ }
+ return htonl(wc10);
+}
+
+static struct mf_bitmap
+mf_bitmap_from_of10(ovs_be32 wc10)
+{
+ struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
+ const struct ofp10_wc_map *p;
+
+ for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) {
+ if (wc10 & htonl(p->wc10)) {
+ bitmap_set1(fields.bm, p->mf);
+ }
+ }
+ return fields;
+}
+
static void
-ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *in,
+ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *stats,
+ const struct ofputil_table_features *features,
struct ofpbuf *buf)
{
- struct wc_map {
- enum ofp10_flow_wildcards wc10;
- enum mf_field_id mf;
- };
-
- static const struct wc_map wc_map[] = {
- { OFPFW10_IN_PORT, MFF_IN_PORT },
- { OFPFW10_DL_VLAN, MFF_VLAN_VID },
- { OFPFW10_DL_SRC, MFF_ETH_SRC },
- { OFPFW10_DL_DST, MFF_ETH_DST},
- { OFPFW10_DL_TYPE, MFF_ETH_TYPE },
- { OFPFW10_NW_PROTO, MFF_IP_PROTO },
- { OFPFW10_TP_SRC, MFF_TCP_SRC },
- { OFPFW10_TP_DST, MFF_TCP_DST },
- { OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC },
- { OFPFW10_NW_DST_MASK, MFF_IPV4_DST },
- { OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP },
- { OFPFW10_NW_TOS, MFF_IP_DSCP },
- };
-
+ struct mf_bitmap wc = wild_or_nonmatchable_fields(features);
struct ofp10_table_stats *out;
- const struct wc_map *p;
out = ofpbuf_put_zeros(buf, sizeof *out);
- out->table_id = in->table_id;
- ovs_strlcpy(out->name, in->name, sizeof out->name);
- out->wildcards = 0;
- for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) {
- if (bitmap_is_set(in->wildcards.bm, p->mf)) {
- out->wildcards |= htonl(p->wc10);
+ out->table_id = features->table_id;
+ ovs_strlcpy(out->name, features->name, sizeof out->name);
+ out->wildcards = mf_bitmap_to_of10(&wc);
+ out->max_entries = htonl(features->max_entries);
+ out->active_count = htonl(stats->active_count);
+ put_32aligned_be64(&out->lookup_count, htonll(stats->lookup_count));
+ put_32aligned_be64(&out->matched_count, htonll(stats->matched_count));
+}
+
+struct ofp11_wc_map {
+ enum ofp11_flow_match_fields wc11;
+ enum mf_field_id mf;
+};
+
+static const struct ofp11_wc_map ofp11_wc_map[] = {
+ { OFPFMF11_IN_PORT, MFF_IN_PORT },
+ { OFPFMF11_DL_VLAN, MFF_VLAN_VID },
+ { OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP },
+ { OFPFMF11_DL_TYPE, MFF_ETH_TYPE },
+ { OFPFMF11_NW_TOS, MFF_IP_DSCP },
+ { OFPFMF11_NW_PROTO, MFF_IP_PROTO },
+ { OFPFMF11_TP_SRC, MFF_TCP_SRC },
+ { OFPFMF11_TP_DST, MFF_TCP_DST },
+ { OFPFMF11_MPLS_LABEL, MFF_MPLS_LABEL },
+ { OFPFMF11_MPLS_TC, MFF_MPLS_TC },
+ /* I don't know what OFPFMF11_TYPE means. */
+ { OFPFMF11_DL_SRC, MFF_ETH_SRC },
+ { OFPFMF11_DL_DST, MFF_ETH_DST },
+ { OFPFMF11_NW_SRC, MFF_IPV4_SRC },
+ { OFPFMF11_NW_DST, MFF_IPV4_DST },
+ { OFPFMF11_METADATA, MFF_METADATA },
+};
+
+static ovs_be32
+mf_bitmap_to_of11(const struct mf_bitmap *fields)
+{
+ const struct ofp11_wc_map *p;
+ uint32_t wc11 = 0;
+
+ for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) {
+ if (bitmap_is_set(fields->bm, p->mf)) {
+ wc11 |= p->wc11;
}
}
- out->max_entries = htonl(in->max_entries);
- out->active_count = htonl(in->active_count);
- put_32aligned_be64(&out->lookup_count, htonll(in->lookup_count));
- put_32aligned_be64(&out->matched_count, htonll(in->matched_count));
+ return htonl(wc11);
}
-static ovs_be32
-fields_to_ofp11_flow_match_fields(const struct mf_bitmap *fields)
-{
- struct map {
- enum ofp11_flow_match_fields fmf11;
- enum mf_field_id mf;
- };
-
- static const struct map map[] = {
- { OFPFMF11_IN_PORT, MFF_IN_PORT },
- { OFPFMF11_DL_VLAN, MFF_VLAN_VID },
- { OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP },
- { OFPFMF11_DL_TYPE, MFF_ETH_TYPE },
- { OFPFMF11_NW_TOS, MFF_IP_DSCP },
- { OFPFMF11_NW_PROTO, MFF_IP_PROTO },
- { OFPFMF11_TP_SRC, MFF_TCP_SRC },
- { OFPFMF11_TP_DST, MFF_TCP_DST },
- { OFPFMF11_MPLS_LABEL, MFF_MPLS_LABEL },
- { OFPFMF11_MPLS_TC, MFF_MPLS_TC },
- /* I don't know what OFPFMF11_TYPE means. */
- { OFPFMF11_DL_SRC, MFF_ETH_SRC },
- { OFPFMF11_DL_DST, MFF_ETH_DST },
- { OFPFMF11_NW_SRC, MFF_IPV4_SRC },
- { OFPFMF11_NW_DST, MFF_IPV4_DST },
- { OFPFMF11_METADATA, MFF_METADATA },
- };
-
- const struct map *p;
- uint32_t fmf11;
-
- fmf11 = 0;
- for (p = map; p < &map[ARRAY_SIZE(map)]; p++) {
- if (bitmap_is_set(fields->bm, p->mf)) {
- fmf11 |= p->fmf11;
+static struct mf_bitmap
+mf_bitmap_from_of11(ovs_be32 wc11)
+{
+ struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
+ const struct ofp11_wc_map *p;
+
+ for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) {
+ if (wc11 & htonl(p->wc11)) {
+ bitmap_set1(fields.bm, p->mf);
}
}
- return htonl(fmf11);
+ return fields;
}
static void
-ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *in,
+ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *stats,
+ const struct ofputil_table_features *features,
struct ofpbuf *buf)
{
+ struct mf_bitmap wc = wild_or_nonmatchable_fields(features);
struct ofp11_table_stats *out;
out = ofpbuf_put_zeros(buf, sizeof *out);
- out->table_id = in->table_id;
- ovs_strlcpy(out->name, in->name, sizeof out->name);
- out->wildcards = fields_to_ofp11_flow_match_fields(&in->wildcards);
- out->match = fields_to_ofp11_flow_match_fields(&in->match);
- out->instructions = htonl(in->instructions);
- out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts,
- OFP11_VERSION);
- out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts,
- OFP11_VERSION);
- out->config = htonl(in->config);
- out->max_entries = htonl(in->max_entries);
- out->active_count = htonl(in->active_count);
- out->lookup_count = htonll(in->lookup_count);
- out->matched_count = htonll(in->matched_count);
+ out->table_id = features->table_id;
+ ovs_strlcpy(out->name, features->name, sizeof out->name);
+ out->wildcards = mf_bitmap_to_of11(&wc);
+ out->match = mf_bitmap_to_of11(&features->match);
+ out->instructions = ovsinst_bitmap_to_openflow(
+ features->nonmiss.instructions, OFP11_VERSION);
+ out->write_actions = ofpact_bitmap_to_openflow(
+ features->nonmiss.write.ofpacts, OFP11_VERSION);
+ out->apply_actions = ofpact_bitmap_to_openflow(
+ features->nonmiss.apply.ofpacts, OFP11_VERSION);
+ out->config = htonl(features->config);
+ out->max_entries = htonl(features->max_entries);
+ out->active_count = htonl(stats->active_count);
+ out->lookup_count = htonll(stats->lookup_count);
+ out->matched_count = htonll(stats->matched_count);
}
static ovs_be64
@@ -5114,84 +5168,274 @@ mf_bitmap_to_oxm_bitmap(const struct mf_bitmap *fields,
return htonll(oxm_bitmap);
}
+static struct mf_bitmap
+mf_bitmap_from_oxm_bitmap(ovs_be64 oxm_bitmap, enum ofp_version version)
+{
+ struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
+
+ for (enum mf_field_id id = 0; id < MFF_N_IDS; id++) {
+ const struct mf_field *f = mf_from_id(id);
+ uint32_t oxm = f->oxm_header;
+ uint32_t vendor = NXM_VENDOR(oxm);
+ int field = NXM_FIELD(oxm);
+
+ if (version >= f->oxm_version
+ && vendor == OFPXMC12_OPENFLOW_BASIC
+ && field < 64
+ && oxm_bitmap & htonll(UINT64_C(1) << field)) {
+ bitmap_set1(fields.bm, id);
+ }
+ }
+ return fields;
+}
+
static void
-ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *in,
+ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *stats,
+ const struct ofputil_table_features *features,
struct ofpbuf *buf)
{
struct ofp12_table_stats *out;
out = ofpbuf_put_zeros(buf, sizeof *out);
- out->table_id = in->table_id;
- ovs_strlcpy(out->name, in->name, sizeof out->name);
- out->match = mf_bitmap_to_oxm_bitmap(&in->match, OFP12_VERSION);
- out->wildcards = mf_bitmap_to_oxm_bitmap(&in->wildcards, OFP12_VERSION);
- out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts,
- OFP12_VERSION);
- out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts,
- OFP12_VERSION);
- out->write_setfields = mf_bitmap_to_oxm_bitmap(&in->write_setfields,
- OFP12_VERSION);
- out->apply_setfields = mf_bitmap_to_oxm_bitmap(&in->apply_setfields,
- OFP12_VERSION);
- out->metadata_match = in->metadata_match;
- out->metadata_write = in->metadata_write;
- out->instructions = htonl(in->instructions & OFPIT11_ALL);
- printf ("%d\n", in->instructions);
- out->config = htonl(in->config);
- out->max_entries = htonl(in->max_entries);
- out->active_count = htonl(in->active_count);
- out->lookup_count = htonll(in->lookup_count);
- out->matched_count = htonll(in->matched_count);
+ out->table_id = features->table_id;
+ ovs_strlcpy(out->name, features->name, sizeof out->name);
+ out->match = mf_bitmap_to_oxm_bitmap(&features->match, OFP12_VERSION);
+ out->wildcards = mf_bitmap_to_oxm_bitmap(&features->wildcard,
+ OFP12_VERSION);
+ out->write_actions = ofpact_bitmap_to_openflow(
+ features->nonmiss.write.ofpacts, OFP12_VERSION);
+ out->apply_actions = ofpact_bitmap_to_openflow(
+ features->nonmiss.apply.ofpacts, OFP12_VERSION);
+ out->write_setfields = mf_bitmap_to_oxm_bitmap(
+ &features->nonmiss.write.set_fields, OFP12_VERSION);
+ out->apply_setfields = mf_bitmap_to_oxm_bitmap(
+ &features->nonmiss.apply.set_fields, OFP12_VERSION);
+ out->metadata_match = features->metadata_match;
+ out->metadata_write = features->metadata_write;
+ out->instructions = ovsinst_bitmap_to_openflow(
+ features->nonmiss.instructions, OFP12_VERSION);
+ out->config = htonl(features->config);
+ out->max_entries = htonl(features->max_entries);
+ out->active_count = htonl(stats->active_count);
+ out->lookup_count = htonll(stats->lookup_count);
+ out->matched_count = htonll(stats->matched_count);
}
static void
-ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *in,
+ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *stats,
struct ofpbuf *buf)
{
struct ofp13_table_stats *out;
- out = ofpbuf_put_uninit(buf, sizeof *out);
- out->table_id = in->table_id;
- out->active_count = htonl(in->active_count);
- out->lookup_count = htonll(in->lookup_count);
- out->matched_count = htonll(in->matched_count);
+ out = ofpbuf_put_zeros(buf, sizeof *out);
+ out->table_id = stats->table_id;
+ out->active_count = htonl(stats->active_count);
+ out->lookup_count = htonll(stats->lookup_count);
+ out->matched_count = htonll(stats->matched_count);
}
struct ofpbuf *
-ofputil_encode_table_stats_reply(const struct ofputil_table_stats stats[],
- int n, const struct ofp_header *request)
+ofputil_encode_table_stats_reply(const struct ofp_header *request)
{
- struct ofpbuf *reply;
- int i;
+ return ofpraw_alloc_stats_reply(request, 0);
+}
+
+void
+ofputil_append_table_stats_reply(struct ofpbuf *reply,
+ const struct ofputil_table_stats *stats,
+ const struct ofputil_table_features *features)
+{
+ struct ofp_header *oh = ofpbuf_l2(reply);
- reply = ofpraw_alloc_stats_reply(request, n * sizeof *stats);
+ ovs_assert(stats->table_id == features->table_id);
- for (i = 0; i < n; i++) {
- switch ((enum ofp_version) request->version) {
- case OFP10_VERSION:
- ofputil_put_ofp10_table_stats(&stats[i], reply);
- break;
+ switch ((enum ofp_version) oh->version) {
+ case OFP10_VERSION:
+ ofputil_put_ofp10_table_stats(stats, features, reply);
+ break;
- case OFP11_VERSION:
- ofputil_put_ofp11_table_stats(&stats[i], reply);
- break;
+ case OFP11_VERSION:
+ ofputil_put_ofp11_table_stats(stats, features, reply);
+ break;
- case OFP12_VERSION:
- ofputil_put_ofp12_table_stats(&stats[i], reply);
- break;
+ case OFP12_VERSION:
+ ofputil_put_ofp12_table_stats(stats, features, reply);
+ break;
- case OFP13_VERSION:
- case OFP14_VERSION:
- case OFP15_VERSION:
- ofputil_put_ofp13_table_stats(&stats[i], reply);
- break;
+ case OFP13_VERSION:
+ case OFP14_VERSION:
+ case OFP15_VERSION:
+ ofputil_put_ofp13_table_stats(stats, reply);
+ break;
- default:
- OVS_NOT_REACHED();
- }
+ default:
+ OVS_NOT_REACHED();
}
+}
- return reply;
+static int
+ofputil_decode_ofp10_table_stats(struct ofpbuf *msg,
+ struct ofputil_table_stats *stats,
+ struct ofputil_table_features *features)
+{
+ struct ofp10_table_stats *ots;
+
+ ots = ofpbuf_try_pull(msg, sizeof *ots);
+ if (!ots) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ features->table_id = ots->table_id;
+ ovs_strlcpy(features->name, ots->name, sizeof features->name);
+ features->max_entries = ntohl(ots->max_entries);
+ features->match = features->wildcard = mf_bitmap_from_of10(ots->wildcards);
+
+ stats->table_id = ots->table_id;
+ stats->active_count = ntohl(ots->active_count);
+ stats->lookup_count = ntohll(get_32aligned_be64(&ots->lookup_count));
+ stats->matched_count = ntohll(get_32aligned_be64(&ots->matched_count));
+
+ return 0;
+}
+
+static int
+ofputil_decode_ofp11_table_stats(struct ofpbuf *msg,
+ struct ofputil_table_stats *stats,
+ struct ofputil_table_features *features)
+{
+ struct ofp11_table_stats *ots;
+
+ ots = ofpbuf_try_pull(msg, sizeof *ots);
+ if (!ots) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ features->table_id = ots->table_id;
+ ovs_strlcpy(features->name, ots->name, sizeof features->name);
+ features->max_entries = ntohl(ots->max_entries);
+ features->nonmiss.instructions = ovsinst_bitmap_from_openflow(
+ ots->instructions, OFP11_VERSION);
+ features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow(
+ ots->write_actions, OFP11_VERSION);
+ features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow(
+ ots->write_actions, OFP11_VERSION);
+ features->miss = features->nonmiss;
+ features->config = ntohl(ots->config);
+ features->match = mf_bitmap_from_of11(ots->match);
+ features->wildcard = mf_bitmap_from_of11(ots->wildcards);
+ bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS);
+
+ stats->table_id = ots->table_id;
+ stats->active_count = ntohl(ots->active_count);
+ stats->lookup_count = ntohll(ots->lookup_count);
+ stats->matched_count = ntohll(ots->matched_count);
+
+ return 0;
+}
+
+static int
+ofputil_decode_ofp12_table_stats(struct ofpbuf *msg,
+ struct ofputil_table_stats *stats,
+ struct ofputil_table_features *features)
+{
+ struct ofp12_table_stats *ots;
+
+ ots = ofpbuf_try_pull(msg, sizeof *ots);
+ if (!ots) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ features->table_id = ots->table_id;
+ ovs_strlcpy(features->name, ots->name, sizeof features->name);
+ features->metadata_match = ots->metadata_match;
+ features->metadata_write = ots->metadata_write;
+ features->config = ntohl(ots->config);
+ features->max_entries = ntohl(ots->max_entries);
+
+ features->nonmiss.instructions = ovsinst_bitmap_from_openflow(
+ ots->instructions, OFP12_VERSION);
+ features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow(
+ ots->write_actions, OFP12_VERSION);
+ features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow(
+ ots->apply_actions, OFP12_VERSION);
+ features->nonmiss.write.set_fields = mf_bitmap_from_oxm_bitmap(
+ ots->write_setfields, OFP12_VERSION);
+ features->nonmiss.apply.set_fields = mf_bitmap_from_oxm_bitmap(
+ ots->apply_setfields, OFP12_VERSION);
+ features->miss = features->nonmiss;
+
+ features->match = mf_bitmap_from_oxm_bitmap(ots->match, OFP12_VERSION);
+ features->wildcard = mf_bitmap_from_oxm_bitmap(ots->wildcards,
+ OFP12_VERSION);
+ bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS);
+
+ stats->table_id = ots->table_id;
+ stats->active_count = ntohl(ots->active_count);
+ stats->lookup_count = ntohll(ots->lookup_count);
+ stats->matched_count = ntohll(ots->matched_count);
+
+ return 0;
+}
+
+static int
+ofputil_decode_ofp13_table_stats(struct ofpbuf *msg,
+ struct ofputil_table_stats *stats,
+ struct ofputil_table_features *features)
+{
+ struct ofp13_table_stats *ots;
+
+ ots = ofpbuf_try_pull(msg, sizeof *ots);
+ if (!ots) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ features->table_id = ots->table_id;
+
+ stats->table_id = ots->table_id;
+ stats->active_count = ntohl(ots->active_count);
+ stats->lookup_count = ntohll(ots->lookup_count);
+ stats->matched_count = ntohll(ots->matched_count);
+
+ return 0;
+}
+
+int
+ofputil_decode_table_stats_reply(struct ofpbuf *msg,
+ struct ofputil_table_stats *stats,
+ struct ofputil_table_features *features)
+{
+ const struct ofp_header *oh;
+
+ if (!msg->frame) {
+ ofpraw_pull_assert(msg);
+ }
+ oh = msg->frame;
+
+ if (!ofpbuf_size(msg)) {
+ return EOF;
+ }
+
+ memset(stats, 0, sizeof *stats);
+ memset(features, 0, sizeof *features);
+
+ switch ((enum ofp_version) oh->version) {
+ case OFP10_VERSION:
+ return ofputil_decode_ofp10_table_stats(msg, stats, features);
+
+ case OFP11_VERSION:
+ return ofputil_decode_ofp11_table_stats(msg, stats, features);
+
+ case OFP12_VERSION:
+ return ofputil_decode_ofp12_table_stats(msg, stats, features);
+
+ case OFP13_VERSION:
+ case OFP14_VERSION:
+ case OFP15_VERSION:
+ return ofputil_decode_ofp13_table_stats(msg, stats, features);
+
+ default:
+ OVS_NOT_REACHED();
+ }
}
/* ofputil_flow_monitor_request */
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 38e7006cd..1ccfb2250 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -767,31 +767,28 @@ struct ofpbuf *ofputil_encode_role_status(
enum ofperr ofputil_decode_role_status(const struct ofp_header *oh,
struct ofputil_role_status *rs);
-/* Abstract table stats. */
-struct ofputil_table_stats {
- uint8_t table_id;
- 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. */
-
- struct mf_bitmap match; /* Fields table can match. */
- struct mf_bitmap wildcards; /* Fields table can wildcard. */
- uint64_t write_ofpacts; /* OFPACT_* supported on Write-Actions. */
- uint64_t apply_ofpacts; /* OFPACT_* supported on Apply-Actions. */
- struct mf_bitmap write_setfields; /* Fields that can be set in W-A. */
- struct mf_bitmap apply_setfields; /* Fields that can be set in A-A. */
- uint32_t instructions; /* Bitmap of OFPIT_* values supported. */
+/* Abstract table stats.
+ *
+ * This corresponds to the OpenFlow 1.3 table statistics structure, which only
+ * includes actual statistics. In earlier versions of OpenFlow, several
+ * members describe table features, so this structure has to be paired with
+ * struct ofputil_table_features to get all information. */
+struct ofputil_table_stats {
+ uint8_t table_id; /* Identifier of table. */
uint32_t active_count; /* Number of active entries. */
uint64_t lookup_count; /* Number of packets looked up in table. */
uint64_t matched_count; /* Number of packets that hit table. */
};
-struct ofpbuf *ofputil_encode_table_stats_reply(
- const struct ofputil_table_stats[], int n,
- const struct ofp_header *request);
+struct ofpbuf *ofputil_encode_table_stats_reply(const struct ofp_header *rq);
+void ofputil_append_table_stats_reply(struct ofpbuf *reply,
+ const struct ofputil_table_stats *,
+ const struct ofputil_table_features *);
+
+int ofputil_decode_table_stats_reply(struct ofpbuf *reply,
+ struct ofputil_table_stats *,
+ struct ofputil_table_features *);
/* Queue configuration request. */
struct ofpbuf *ofputil_encode_queue_get_config_request(enum ofp_version,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 1f1a27b74..a8a417d6c 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1503,27 +1503,23 @@ flush(struct ofproto *ofproto_)
}
static void
-get_features(struct ofproto *ofproto_ OVS_UNUSED,
- bool *arp_match_ip, uint64_t *ofpacts)
+query_tables(struct ofproto *ofproto,
+ struct ofputil_table_features *features,
+ struct ofputil_table_stats *stats)
{
- *arp_match_ip = true;
- *ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
-}
-
-static void
-get_tables(struct ofproto *ofproto, struct ofputil_table_stats *stats)
-{
- int i;
+ strcpy(features->name, "classifier");
- strcpy(stats->name, "classifier");
+ if (stats) {
+ int i;
- for (i = 0; i < ofproto->n_tables; i++) {
- unsigned long missed, matched;
+ for (i = 0; i < ofproto->n_tables; i++) {
+ unsigned long missed, matched;
- atomic_read(&ofproto->tables[i].n_matched, &matched);
- stats[i].matched_count = matched;
- atomic_read(&ofproto->tables[i].n_missed, &missed);
- stats[i].lookup_count = matched + missed;
+ atomic_read(&ofproto->tables[i].n_matched, &matched);
+ stats[i].matched_count = matched;
+ atomic_read(&ofproto->tables[i].n_missed, &missed);
+ stats[i].lookup_count = matched + missed;
+ }
}
}
@@ -5058,8 +5054,7 @@ const struct ofproto_class ofproto_dpif_class = {
NULL, /* get_memory_usage. */
type_get_memory_usage,
flush,
- get_features,
- get_tables,
+ query_tables,
port_alloc,
port_construct,
port_destruct,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 2d98a97e0..551539689 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -768,70 +768,49 @@ struct ofproto_class {
* than to do it one by one. */
void (*flush)(struct ofproto *ofproto);
- /* Helper for the OpenFlow OFPT_FEATURES_REQUEST request.
+ /* Helper for the OpenFlow OFPT_TABLE_FEATURES request.
*
- * The implementation should store true in '*arp_match_ip' if the switch
- * supports matching IP addresses inside ARP requests and replies, false
- * otherwise.
- *
- * The implementation should store in '*ofpacts' a bitmap of the supported
- * OFPACT_* actions. */
- void (*get_features)(struct ofproto *ofproto,
- bool *arp_match_ip,
- uint64_t *ofpacts);
-
- /* Helper for the OpenFlow OFPST_TABLE statistics request.
- *
- * The 'stats' array contains 'ofproto->n_tables' elements. Each element is
- * initialized as:
+ * The 'features' array contains 'ofproto->n_tables' elements. Each
+ * element is initialized as:
*
* - 'table_id' to the array index.
*
* - 'name' to "table#" where # is the table ID.
*
- * - 'match' and 'wildcards' to all fields.
- *
- * - 'write_actions' and 'apply_actions' to all actions.
- *
- * - 'write_setfields' and 'apply_setfields' to all writable fields.
- *
* - 'metadata_match' and 'metadata_write' to OVS_BE64_MAX.
*
- * - 'instructions' to all instructions.
- *
* - 'config' to the table miss configuration.
*
* - 'max_entries' to 1,000,000.
*
- * - 'active_count' to the classifier_count() for the table.
+ * - Both 'nonmiss' and 'miss' to:
*
- * - 'lookup_count' and 'matched_count' to 0.
+ * * 'next' to all 1-bits for all later tables.
*
- * The implementation should update any members in each element for which
- * it has better values:
+ * * 'instructions' to all instructions.
*
- * - 'name' to a more meaningful name.
+ * * 'write' and 'apply' both to:
*
- * - 'wildcards' to the set of wildcards actually supported by the table
- * (if it doesn't support all OpenFlow wildcards).
+ * - 'ofpacts': All actions.
*
- * - 'instructions' to set the instructions actually supported by
- * the table.
+ * - 'set_fields': All fields.
*
- * - 'write_actions' to set the write actions actually supported by
- * the table (if it doesn't support all OpenFlow actions).
+ * - 'match', 'mask', and 'wildcard' to all fields.
*
- * - 'apply_actions' to set the apply actions actually supported by
- * the table (if it doesn't support all OpenFlow actions).
+ * If 'stats' is nonnull, it also contains 'ofproto->n_tables' elements.
+ * Each element is initialized as:
*
- * - 'write_setfields' to set the write setfields actually supported by
- * the table.
+ * - 'table_id' to the array index.
+ *
+ * - 'active_count' to the classifier_count() for the table.
*
- * - 'apply_setfields' to set the apply setfields actually supported by
- * the table.
+ * - 'lookup_count' and 'matched_count' to 0.
+ *
+ * The implementation should update any members in each element for which
+ * it has better values:
*
- * - 'max_entries' to the maximum number of flows actually supported by
- * the hardware.
+ * - Any member of 'features' to better describe the implementation's
+ * capabilities.
*
* - 'lookup_count' to the number of packets looked up in this flow table
* so far.
@@ -839,8 +818,9 @@ struct ofproto_class {
* - 'matched_count' to the number of packets looked up in this flow
* table so far that matched one of the flow entries.
*/
- void (*get_tables)(struct ofproto *ofproto,
- struct ofputil_table_stats *stats);
+ void (*query_tables)(struct ofproto *ofproto,
+ struct ofputil_table_features *features,
+ struct ofputil_table_stats *stats);
/* ## ---------------- ## */
/* ## ofport Functions ## */
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 5ab7391a8..50b9ec6f6 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2777,6 +2777,103 @@ handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh)
return 0;
}
+static void
+query_tables(struct ofproto *ofproto,
+ struct ofputil_table_features **featuresp,
+ struct ofputil_table_stats **statsp)
+{
+ struct mf_bitmap rw_fields = MF_BITMAP_INITIALIZER;
+ struct ofputil_table_features *features;
+ struct ofputil_table_stats *stats;
+ int i;
+
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (mf_from_id(i)->writable) {
+ bitmap_set1(rw_fields.bm, i);
+ }
+ }
+
+ features = *featuresp = xcalloc(ofproto->n_tables, sizeof *features);
+ for (i = 0; i < ofproto->n_tables; i++) {
+ struct ofputil_table_features *f = &features[i];
+ unsigned int config;
+
+ f->table_id = i;
+ sprintf(f->name, "table%d", i);
+ f->metadata_match = OVS_BE64_MAX;
+ f->metadata_write = OVS_BE64_MAX;
+ atomic_read(&ofproto->tables[i].config, &config);
+ f->config = config;
+ f->max_entries = 1000000;
+
+ bitmap_set_multiple(f->nonmiss.next, i + 1,
+ ofproto->n_tables - (i + 1), true);
+ f->nonmiss.instructions = (1u << N_OVS_INSTRUCTIONS) - 1;
+ if (i == ofproto->n_tables - 1) {
+ f->nonmiss.instructions &= ~(1u << OVSINST_OFPIT11_GOTO_TABLE);
+ }
+ f->nonmiss.write.ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
+ f->nonmiss.write.set_fields = rw_fields;
+ f->nonmiss.apply = f->nonmiss.write;
+ f->miss = f->nonmiss;
+
+ bitmap_set_multiple(f->match.bm, 0, MFF_N_IDS, 1);
+ bitmap_set_multiple(f->mask.bm, 0, MFF_N_IDS, 1);
+ bitmap_set_multiple(f->wildcard.bm, 0, MFF_N_IDS, 1);
+ }
+
+ if (statsp) {
+ stats = *statsp = xcalloc(ofproto->n_tables, sizeof *stats);
+ for (i = 0; i < ofproto->n_tables; i++) {
+ struct ofputil_table_stats *s = &stats[i];
+ struct classifier *cls = &ofproto->tables[i].cls;
+
+ s->table_id = i;
+ s->active_count = classifier_count(cls);
+ }
+ } else {
+ stats = NULL;
+ }
+
+ ofproto->ofproto_class->query_tables(ofproto, features, stats);
+
+ for (i = 0; i < ofproto->n_tables; i++) {
+ const struct oftable *table = &ofproto->tables[i];
+ struct ofputil_table_features *f = &features[i];
+
+ if (table->name) {
+ ovs_strzcpy(f->name, table->name, sizeof f->name);
+ }
+
+ if (table->max_flows < f->max_entries) {
+ f->max_entries = table->max_flows;
+ }
+ }
+}
+
+static void
+query_switch_features(struct ofproto *ofproto,
+ bool *arp_match_ip, uint64_t *ofpacts)
+{
+ struct ofputil_table_features *features, *f;
+
+ *arp_match_ip = false;
+ *ofpacts = 0;
+
+ query_tables(ofproto, &features, NULL);
+ for (f = features; f < &features[ofproto->n_tables]; f++) {
+ *ofpacts |= f->nonmiss.apply.ofpacts | f->miss.apply.ofpacts;
+ if (bitmap_is_set(f->match.bm, MFF_ARP_SPA) ||
+ bitmap_is_set(f->match.bm, MFF_ARP_TPA)) {
+ *arp_match_ip = true;
+ }
+ }
+ free(features);
+
+ /* Sanity check. */
+ ovs_assert(*ofpacts & (UINT64_C(1) << OFPACT_OUTPUT));
+}
+
static enum ofperr
handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
@@ -2786,9 +2883,7 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
bool arp_match_ip;
struct ofpbuf *b;
- ofproto->ofproto_class->get_features(ofproto, &arp_match_ip,
- &features.ofpacts);
- ovs_assert(features.ofpacts & (UINT64_C(1) << OFPACT_OUTPUT));
+ query_switch_features(ofproto, &arp_match_ip, &features.ofpacts);
features.datapath_id = ofproto->datapath_id;
features.n_buffers = pktbuf_capacity();
@@ -3063,70 +3158,23 @@ static enum ofperr
handle_table_stats_request(struct ofconn *ofconn,
const struct ofp_header *request)
{
- struct mf_bitmap rw_fields = MF_BITMAP_INITIALIZER;
- struct ofproto *p = ofconn_get_ofproto(ofconn);
+ struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ struct ofputil_table_features *features;
struct ofputil_table_stats *stats;
- struct ofpbuf *msg;
- int n_tables;
+ struct ofpbuf *reply;
size_t i;
- for (i = 0; i < MFF_N_IDS; i++) {
- if (mf_from_id(i)->writable) {
- bitmap_set1(rw_fields.bm, i);
- }
- }
-
- /* Set up default values.
- *
- * ofp12_table_stats is used as a generic structure as
- * it is able to hold all the fields for ofp10_table_stats
- * and ofp11_table_stats (and of course itself).
- */
- stats = xcalloc(p->n_tables, sizeof *stats);
- for (i = 0; i < p->n_tables; i++) {
- unsigned int config;
-
- stats[i].table_id = i;
- sprintf(stats[i].name, "table%"PRIuSIZE, i);
- bitmap_set_multiple(stats[i].match.bm, 0, MFF_N_IDS, 1);
- bitmap_set_multiple(stats[i].wildcards.bm, 0, MFF_N_IDS, 1);
- stats[i].write_ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
- stats[i].apply_ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
- stats[i].write_setfields = rw_fields;
- stats[i].apply_setfields = rw_fields;
- stats[i].metadata_match = OVS_BE64_MAX;
- stats[i].metadata_write = OVS_BE64_MAX;
- stats[i].instructions = OFPIT13_ALL;
- atomic_read(&p->tables[i].config, &config);
- stats[i].config = config;
- stats[i].max_entries = 1000000; /* An arbitrary big number. */
- stats[i].active_count = classifier_count(&p->tables[i].cls);
- }
-
- p->ofproto_class->get_tables(p, stats);
-
- /* Post-process the tables, dropping hidden tables. */
- n_tables = p->n_tables;
- for (i = 0; i < p->n_tables; i++) {
- const struct oftable *table = &p->tables[i];
-
- if (table->flags & OFTABLE_HIDDEN) {
- n_tables = i;
- break;
- }
-
- if (table->name) {
- ovs_strzcpy(stats[i].name, table->name, sizeof stats[i].name);
- }
+ query_tables(ofproto, &features, &stats);
- if (table->max_flows < stats[i].max_entries) {
- stats[i].max_entries = table->max_flows;
+ reply = ofputil_encode_table_stats_reply(request);
+ for (i = 0; i < ofproto->n_tables; i++) {
+ if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) {
+ ofputil_append_table_stats_reply(reply, &stats[i], &features[i]);
}
}
+ ofconn_send_reply(ofconn, reply);
- msg = ofputil_encode_table_stats_reply(stats, n_tables, request);
- ofconn_send_reply(ofconn, msg);
-
+ free(features);
free(stats);
return 0;
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 3e35baa3c..d461e96f7 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -1384,34 +1384,84 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 3f ff ff 00 10 00 00 00 00 00 0b 00 00 00 00 \
00 00 00 00 00 00 00 00 00 00 00 00 \
"], [0], [dnl
-OFPST_TABLE reply (xid=0x1): 1 tables
- 0: classifier: wild=0x3fffff, max=1048576, active=11
- lookup=0, matched=0
+OFPST_TABLE reply (xid=0x1):
+ table 0 ("classifier"):
+ active=11, lookup=0, matched=0
+ max_entries=1048576
+ matching:
+ in_port: exact match or wildcard
+ eth_src: exact match or wildcard
+ eth_dst: exact match or wildcard
+ eth_type: exact match or wildcard
+ vlan_vid: exact match or wildcard
+ vlan_pcp: exact match or wildcard
+ ip_src: exact match or wildcard
+ ip_dst: exact match or wildcard
+ nw_proto: exact match or wildcard
+ nw_tos: exact match or wildcard
+ tcp_src: exact match or wildcard
+ tcp_dst: exact match or wildcard
])
AT_CLEANUP
AT_SETUP([OFPST_TABLE reply - OF1.2])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
-(mid="wild=0xfffffffff, max=1000000,"
- tail="
- match=0xfffffffff, instructions=0x00000007, config=0x00000000
- write_actions=0x00000000, apply_actions=0x00000000
- write_setfields=0x0000000fffffffff
- apply_setfields=0x0000000fffffffff
- metadata_match=0x0000000000000000
- metadata_write=0x0000000000000000"
- echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 255 tables
- 0: classifier: $mid active=1
- lookup=74614, matched=106024$tail"
+(tail="
+ max_entries=1000000
+ instructions (table miss and others):
+ instructions: write_metadata,goto_table
+ Write-Actions and Apply-Actions features:
+ supported on Set-Field: metadata in_port_oxm eth_src eth_dst eth_type vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_proto ip_dscp nw_ecn arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll
+ matching:
+ metadata: exact match or wildcard
+ in_port_oxm: exact match or wildcard
+ eth_src: exact match or wildcard
+ eth_dst: exact match or wildcard
+ eth_type: 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
+ 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
+ ip_dscp: exact match or wildcard
+ nw_ecn: 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
+ 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"
+ echo "OFPST_TABLE reply (OF1.2) (xid=0x2):
+ table 0 (\"classifier\"):
+ active=1, lookup=74614, matched=106024$tail"
x=1
while test $x -lt 254; do
- printf " %d: %-8s: $mid active=0
- lookup=0, matched=0$tail
+ printf "
+ table %d (\"%s\"):
+ active=0, lookup=0, matched=0$tail
" $x table$x
x=`expr $x + 1`
done
- echo " 254: table254: $mid active=2
- lookup=0, matched=0$tail") > expout
+ echo "
+ table 254 (\"table254\"):
+ active=2, lookup=0, matched=0$tail") > expout
(pad32="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
pad7="00 00 00 00 00 00 00 "
@@ -1453,9 +1503,12 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 00 00 00 00 00 01 00 01 00 00 00 00 00 00 0c \
00 00 00 00 00 00 02 01 00 00 00 00 00 00 01 01 \
"], [0], [dnl
-OFPST_TABLE reply (OF1.3) (xid=0x1): 2 tables
- 0: active=11, lookup=512, matched=256
- 1: active=12, lookup=513, matched=257
+OFPST_TABLE reply (OF1.3) (xid=0x1):
+ table 0:
+ active=11, lookup=512, matched=256
+
+ table 1:
+ active=12, lookup=513, matched=257
])
AT_CLEANUP
@@ -2270,8 +2323,7 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \
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"
+ table 0 ("table0"):
metadata: match=0xffffffffffffffff write=0xffffffffffffffff
config=Unknown
max_entries=1000000
@@ -2280,7 +2332,7 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \
instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table
Write-Actions and Apply-Actions features:
actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
- 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
+ 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
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 4386639cb..e63f5a79c 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -5527,11 +5527,14 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
NXST_FLOW reply:
])
-(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables"
- echo " 0: active=1, lookup=0, matched=0"
+(echo "OFPST_TABLE reply (OF1.3) (xid=0x2):
+ table 0:
+ active=1, lookup=0, matched=0"
x=1
while test $x -lt 254; do
- echo " $x: active=0, lookup=0, matched=0"
+ echo "
+ table $x:
+ active=0, lookup=0, matched=0"
x=`expr $x + 1`
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
@@ -5539,7 +5542,6 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP
-
AT_SETUP([ofproto-dpif packet-out controller (patch port)])
OVS_VSWITCHD_START(
[-- \
@@ -5571,19 +5573,24 @@ NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_l
metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
])
-(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables"
+(printf "OFPST_TABLE reply (OF1.3) (xid=0x2):"
x=0
while test $x -lt 254; do
- echo " $x: active=0, lookup=0, matched=0"
+ echo "
+ table $x:
+ active=0, lookup=0, matched=0"
x=`expr $x + 1`
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
-(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables"
- echo " 0: active=0, lookup=3, matched=0"
+(echo "OFPST_TABLE reply (OF1.3) (xid=0x2):
+ table 0:
+ active=0, lookup=3, matched=0"
x=1
while test $x -lt 254; do
- echo " $x: active=0, lookup=0, matched=0"
+ echo "
+ table $x:
+ active=0, lookup=0, matched=0"
x=`expr $x + 1`
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br1 ], [0], [expout])
@@ -5630,12 +5637,17 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-flows br0 | ofctl_strip | sort], [0], [dn
OFPST_FLOW reply (OF1.3):
])
-(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables"
- echo " 0: active=1, lookup=3, matched=3"
- echo " 1: active=1, lookup=3, matched=3"
+(echo "OFPST_TABLE reply (OF1.3) (xid=0x2):
+ table 0:
+ active=1, lookup=3, matched=3
+
+ table 1:
+ active=1, lookup=3, matched=3"
x=2
while test $x -lt 254; do
- echo " $x: active=0, lookup=0, matched=0"
+ echo "
+ table $x:
+ active=0, lookup=0, matched=0"
x=`expr $x + 1`
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
@@ -5678,12 +5690,17 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-flows br0 | ofctl_strip | sort], [0], [dn
OFPST_FLOW reply (OF1.3):
])
-(echo "OFPST_TABLE reply (OF1.3) (xid=0x2): 254 tables"
- echo " 0: active=0, lookup=3, matched=0"
- echo " 1: active=1, lookup=3, matched=3"
+(echo "OFPST_TABLE reply (OF1.3) (xid=0x2):
+ table 0:
+ active=0, lookup=3, matched=0
+
+ table 1:
+ active=1, lookup=3, matched=3"
x=2
while test $x -lt 254; do
- echo " $x: active=0, lookup=0, matched=0"
+ echo "
+ table $x:
+ active=0, lookup=0, matched=0"
x=`expr $x + 1`
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 5eef15b70..9ac3c6ee6 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -1028,15 +1028,30 @@ AT_CLEANUP
AT_SETUP([ofproto - flow table configuration (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Check the default configuration.
-(echo "OFPST_TABLE reply (xid=0x2): 254 tables
- 0: classifier: wild=0x3fffff, max=1000000, active=0
- lookup=0, matched=0"
- x=1
+(printf "OFPST_TABLE reply (xid=0x2):"
+ x=0
+ name=classifier
while test $x -lt 254; do
- printf " %d: %-8s: wild=0x3fffff, max=1000000, active=0
- lookup=0, matched=0
-" $x table$x
+ printf "
+ table %d (\"%s\"):
+ active=0, lookup=0, matched=0
+ max_entries=1000000
+ matching:
+ in_port: exact match or wildcard
+ eth_src: exact match or wildcard
+ eth_dst: exact match or wildcard
+ eth_type: exact match or wildcard
+ vlan_vid: exact match or wildcard
+ vlan_pcp: exact match or wildcard
+ ip_src: exact match or wildcard
+ ip_dst: exact match or wildcard
+ nw_proto: exact match or wildcard
+ nw_tos: exact match or wildcard
+ tcp_src: exact match or wildcard
+ tcp_dst: exact match or wildcard
+" $x $name
x=`expr $x + 1`
+ name=table$x
done) > expout
AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout])
# Change the configuration.
@@ -1051,12 +1066,8 @@ AT_CHECK(
])
# Check that the configuration was updated.
mv expout orig-expout
-(echo "OFPST_TABLE reply (xid=0x2): 254 tables
- 0: main : wild=0x3fffff, max=1000000, active=0
- lookup=0, matched=0
- 1: table1 : wild=0x3fffff, max= 1024, active=0
- lookup=0, matched=0"
- tail -n +6 orig-expout) > expout
+sed -e 's/classifier/main/
+21s/1000000/1024/' orig-expout > expout
AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP
@@ -1064,22 +1075,58 @@ AT_CLEANUP
AT_SETUP([ofproto - flow table configuration (OpenFlow 1.2)])
OVS_VSWITCHD_START
# Check the default configuration.
-(mid="wild=0x1ffffffffd, max=1000000,"
- tail="
- lookup=0, matched=0
- match=0x1ffffffffd, instructions=0x0000003e, config=0x00000003
- write_actions=0x03ff8001, apply_actions=0x03ff8001
- write_setfields=0x0000000c0fe7fbdd
- apply_setfields=0x0000000c0fe7fbdd
- metadata_match=0xffffffffffffffff
- metadata_write=0xffffffffffffffff"
- echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables
- 0: classifier: $mid active=0$tail"
- x=1
+(printf "OFPST_TABLE reply (OF1.2) (xid=0x2):"
+ x=0
+ name=classifier
while test $x -lt 254; do
- printf " %d: %-8s: $mid active=0$tail
-" $x table$x
+ echo "
+ table $x (\"$name\"):
+ active=0, lookup=0, matched=0
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ max_entries=1000000
+ instructions (table miss and others):
+ instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table
+ Write-Actions and Apply-Actions features:
+ actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
+ supported on Set-Field: metadata in_port_oxm eth_src eth_dst vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ip_dscp nw_ecn arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst
+ matching:
+ metadata: exact match or wildcard
+ in_port_oxm: exact match or wildcard
+ eth_src: exact match or wildcard
+ eth_dst: exact match or wildcard
+ eth_type: 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
+ 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
+ ip_dscp: exact match or wildcard
+ nw_ecn: 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
+ 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"
x=`expr $x + 1`
+ name=table$x
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout])
# Change the configuration.
@@ -1094,11 +1141,8 @@ AT_CHECK(
])
# Check that the configuration was updated.
mv expout orig-expout
-(echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables
- 0: main : wild=0x1ffffffffd, max=1000000, active=0"
- tail -n +3 orig-expout | head -7
- echo " 1: table1 : wild=0x1ffffffffd, max= 1024, active=0"
- tail -n +11 orig-expout) > expout
+sed 's/classifier/main/
+51s/1000000/1024/' < orig-expout > expout
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP