summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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