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.*/
}
static void
-ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
+ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm)
{
- struct ofputil_meter_mod mm;
- struct ofpbuf bands;
- enum ofperr error;
-
- ofpbuf_init(&bands, 64);
- error = ofputil_decode_meter_mod(oh, &mm, &bands);
- if (error) {
- ofpbuf_uninit(&bands);
- ofp_print_error(s, error);
- return;
- }
-
- switch (mm.command) {
+ switch (mm->command) {
case OFPMC13_ADD:
ds_put_cstr(s, " ADD ");
break;
ds_put_cstr(s, " DEL ");
break;
default:
- ds_put_format(s, " cmd:%d ", mm.command);
+ ds_put_format(s, " cmd:%d ", mm->command);
}
- ofp_print_meter_config(s, &mm.meter);
+ ofp_print_meter_config(s, &mm->meter);
+}
+
+static void
+ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
+{
+ struct ofputil_meter_mod mm;
+ struct ofpbuf bands;
+ enum ofperr error;
+
+ ofpbuf_init(&bands, 64);
+ error = ofputil_decode_meter_mod(oh, &mm, &bands);
+ if (error) {
+ ofp_print_error(s, error);
+ } else {
+ ofp_print_meter_mod__(s, &mm);
+ }
ofpbuf_uninit(&bands);
}
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpraw_pull_assert(&b);
- for (;;) {
+ struct ofputil_table_features prev_features;
+ struct ofputil_table_stats prev_stats;
+ for (int i = 0;; i++) {
struct ofputil_table_features features;
struct ofputil_table_stats stats;
int retval;
return;
}
- ofp_print_table_features(string, &features, &stats);
+ ds_put_char(string, '\n');
+ ofp_print_table_features(string,
+ &features, i ? &prev_features : NULL,
+ &stats, i ? &prev_stats : NULL);
+ prev_features = features;
+ prev_stats = stats;
}
}
static void
ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
- struct ovs_list *p_buckets, struct ofputil_group_props *props,
+ const struct ovs_list *p_buckets,
+ const struct ofputil_group_props *props,
enum ofp_version ofp_version, bool suppress_type)
{
struct ofputil_bucket *bucket;
ds_put_cstr(s, "bucket=");
ofp_print_bucket_id(s, "bucket_id:", bucket->bucket_id, ofp_version);
- if (bucket->weight != 1) {
+ if (bucket->weight != (type == OFPGT11_SELECT ? 1 : 0)) {
ds_put_format(s, "weight:%"PRIu16",", bucket->weight);
}
if (bucket->watch_port != OFPP_NONE) {
}
static void
-ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
+ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version,
+ const struct ofputil_group_mod *gm)
{
- struct ofputil_group_mod gm;
- int error;
bool bucket_command = false;
- error = ofputil_decode_group_mod(oh, &gm);
- if (error) {
- ofp_print_error(s, error);
- return;
- }
-
ds_put_char(s, '\n');
ds_put_char(s, ' ');
- switch (gm.command) {
+ switch (gm->command) {
case OFPGC11_ADD:
ds_put_cstr(s, "ADD");
break;
break;
default:
- ds_put_format(s, "cmd:%"PRIu16"", gm.command);
+ ds_put_format(s, "cmd:%"PRIu16"", gm->command);
}
ds_put_char(s, ' ');
if (bucket_command) {
ofp_print_bucket_id(s, "command_bucket_id:",
- gm.command_bucket_id, oh->version);
+ gm->command_bucket_id, ofp_version);
}
- ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, &gm.props,
- oh->version, bucket_command);
+ ofp_print_group(s, gm->group_id, gm->type, &gm->buckets, &gm->props,
+ ofp_version, bucket_command);
+}
+
+static void
+ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
+{
+ struct ofputil_group_mod gm;
+ int error;
+
+ error = ofputil_decode_group_mod(oh, &gm);
+ if (error) {
+ ofp_print_error(s, error);
+ return;
+ }
+ ofp_print_group_mod__(s, oh->version, &gm);
ofputil_bucket_list_destroy(&gm.buckets);
}
static void
print_table_instruction_features(
- struct ds *s, const struct ofputil_table_instruction_features *tif)
+ struct ds *s,
+ const struct ofputil_table_instruction_features *tif,
+ const struct ofputil_table_instruction_features *prev_tif)
{
int start, end;
}
if (tif->instructions) {
- ds_put_cstr(s, " instructions: ");
- int i;
+ if (prev_tif && tif->instructions == prev_tif->instructions) {
+ ds_put_cstr(s, " (same instructions)\n");
+ } else {
+ ds_put_cstr(s, " instructions: ");
+ int i;
- for (i = 0; i < 32; i++) {
- if (tif->instructions & (1u << i)) {
- ds_put_format(s, "%s,", ovs_instruction_name_from_type(i));
+ for (i = 0; i < 32; i++) {
+ if (tif->instructions & (1u << i)) {
+ ds_put_format(s, "%s,", ovs_instruction_name_from_type(i));
+ }
}
+ ds_chomp(s, ',');
+ ds_put_char(s, '\n');
}
- ds_chomp(s, ',');
- ds_put_char(s, '\n');
}
- if (!table_action_features_equal(&tif->write, &tif->apply)) {
+ if (prev_tif
+ && table_action_features_equal(&tif->write, &prev_tif->write)
+ && table_action_features_equal(&tif->apply, &prev_tif->apply)
+ && !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) {
+ ds_put_cstr(s, " (same actions)\n");
+ } 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");
&& table_action_features_empty(&tif->apply));
}
-static void
+static bool
+table_features_equal(const struct ofputil_table_features *a,
+ const struct ofputil_table_features *b)
+{
+ return (a->metadata_match == b->metadata_match
+ && a->metadata_write == b->metadata_write
+ && a->miss_config == b->miss_config
+ && a->supports_eviction == b->supports_eviction
+ && a->supports_vacancy_events == b->supports_vacancy_events
+ && a->max_entries == b->max_entries
+ && table_instruction_features_equal(&a->nonmiss, &b->nonmiss)
+ && table_instruction_features_equal(&a->miss, &b->miss)
+ && bitmap_equal(a->match.bm, b->match.bm, MFF_N_IDS));
+}
+
+static bool
+table_features_empty(const struct ofputil_table_features *tf)
+{
+ return (!tf->metadata_match
+ && !tf->metadata_write
+ && tf->miss_config == OFPUTIL_TABLE_MISS_DEFAULT
+ && tf->supports_eviction < 0
+ && tf->supports_vacancy_events < 0
+ && !tf->max_entries
+ && table_instruction_features_empty(&tf->nonmiss)
+ && table_instruction_features_empty(&tf->miss)
+ && bitmap_is_all_zeros(tf->match.bm, MFF_N_IDS));
+}
+
+static bool
+table_stats_equal(const struct ofputil_table_stats *a,
+ const struct ofputil_table_stats *b)
+{
+ return (a->active_count == b->active_count
+ && a->lookup_count == b->lookup_count
+ && a->matched_count == b->matched_count);
+}
+
+void
ofp_print_table_features(struct ds *s,
const struct ofputil_table_features *features,
- const struct ofputil_table_stats *stats)
+ const struct ofputil_table_features *prev_features,
+ const struct ofputil_table_stats *stats,
+ const struct ofputil_table_stats *prev_stats)
{
int i;
- ds_put_format(s, "\n table %"PRIu8, features->table_id);
+ ds_put_format(s, " table %"PRIu8, features->table_id);
if (features->name[0]) {
ds_put_format(s, " (\"%s\")", features->name);
}
- ds_put_cstr(s, ":\n");
+ ds_put_char(s, ':');
+
+ bool same_stats = prev_stats && table_stats_equal(stats, prev_stats);
+ bool same_features = prev_features && table_features_equal(features,
+ prev_features);
+ if ((!stats || same_stats) && same_features) {
+ ds_put_cstr(s, " ditto");
+ return;
+ }
+ ds_put_char(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) {
+ if (same_features) {
+ if (!table_features_empty(features)) {
+ ds_put_cstr(s, " (same features)\n");
+ }
+ return;
+ }
+ if (features->metadata_match || features->metadata_write) {
ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n",
ntohll(features->metadata_match),
ntohll(features->metadata_write));
ds_put_format(s, " max_entries=%"PRIu32"\n", features->max_entries);
}
- if (!table_instruction_features_equal(&features->nonmiss,
- &features->miss)) {
+ const struct ofputil_table_instruction_features *prev_nonmiss
+ = prev_features ? &prev_features->nonmiss : NULL;
+ const struct ofputil_table_instruction_features *prev_miss
+ = prev_features ? &prev_features->miss : NULL;
+ if (prev_features
+ && table_instruction_features_equal(&features->nonmiss, prev_nonmiss)
+ && table_instruction_features_equal(&features->miss, prev_miss)) {
+ if (!table_instruction_features_empty(&features->nonmiss)) {
+ ds_put_cstr(s, " (same instructions)\n");
+ }
+ } else 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);
+ print_table_instruction_features(s, &features->nonmiss, prev_nonmiss);
ds_put_cstr(s, " instructions (table miss):\n");
- print_table_instruction_features(s, &features->miss);
+ print_table_instruction_features(s, &features->miss, prev_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);
+ print_table_instruction_features(s, &features->nonmiss, prev_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, features->match.bm) {
- const struct mf_field *f = mf_from_id(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,
- (mask ? "arbitrary mask"
- : wildcard ? "exact match or wildcard"
- : "must exact match"));
+ if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)) {
+ if (prev_features
+ && bitmap_equal(features->match.bm, prev_features->match.bm,
+ MFF_N_IDS)) {
+ ds_put_cstr(s, " (same matching)\n");
+ } else {
+ ds_put_cstr(s, " matching:\n");
+ 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(features->mask.bm, i);
+ bool wildcard = bitmap_is_set(features->wildcard.bm, i);
+
+ ds_put_format(s, " %s: %s\n",
+ f->name,
+ (mask ? "arbitrary mask"
+ : wildcard ? "exact match or wildcard"
+ : "must exact match"));
+ }
}
}
}
ofpbuf_use_const(&b, oh, ntohs(oh->length));
- for (;;) {
+ struct ofputil_table_features prev;
+ for (int i = 0; ; i++) {
struct ofputil_table_features tf;
int retval;
}
return;
}
- ofp_print_table_features(s, &tf, NULL);
+
+ ds_put_char(s, '\n');
+ ofp_print_table_features(s, &tf, i ? &prev : NULL, NULL, NULL);
+ prev = tf;
}
}
ofputil_uninit_geneve_table(>r.mappings);
}
+/* This function will print the request forward message. The reason for
+ * request forward is taken from rf.request.type */
+static void
+ofp_print_requestforward(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofputil_requestforward rf;
+ enum ofperr error;
+
+ error = ofputil_decode_requestforward(oh, &rf);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ ds_put_cstr(string, " reason=");
+
+ switch (rf.reason) {
+ case OFPRFR_GROUP_MOD:
+ ds_put_cstr(string, "group_mod");
+ ofp_print_group_mod__(string, oh->version, rf.group_mod);
+ break;
+
+ case OFPRFR_METER_MOD:
+ ds_put_cstr(string, "meter_mod");
+ ofp_print_meter_mod__(string, rf.meter_mod);
+ break;
+ }
+ ofputil_destroy_requestforward(&rf);
+}
+
static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
ofp_print_role_status_message(string, oh);
break;
+ case OFPTYPE_REQUESTFORWARD:
+ ofp_print_requestforward(string, oh);
+ break;
+
case OFPTYPE_METER_STATS_REQUEST:
case OFPTYPE_METER_CONFIG_STATS_REQUEST:
ofp_print_stats(string, oh);