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.*/
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
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) && (!features || 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;
}
}
/*
- * Copyright (c) 2008, 2009, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2011, 2012, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct ofp_flow_mod;
struct ofp_header;
struct ofputil_flow_stats;
+struct ofputil_table_features;
+struct ofputil_table_stats;
#ifdef __cplusplus
extern "C" {
void ofp_print_flow_stats(struct ds *, struct ofputil_flow_stats *);
void ofp_print_version(const struct ofp_header *, struct ds *);
+void ofp_print_table_features(
+ struct ds *, const struct ofputil_table_features *features,
+ const struct ofputil_table_features *prev_features,
+ const struct ofputil_table_stats *stats,
+ const struct ofputil_table_stats *prev_stats);
#ifdef __cplusplus
}
AT_SETUP([OFPST_TABLE reply - OF1.2])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
-(tail="
+(echo 'OFPST_TABLE reply (OF1.2) (xid=0x2):
+ table 0 ("classifier"):
+ active=1, lookup=74614, matched=106024
config=controller
max_entries=1000000
instructions (table miss and others):
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 "
- table %d (\"%s\"):
- active=0, lookup=0, matched=0$tail
-" $x table$x
- x=`expr $x + 1`
+ nd_tll: exact match or wildcard
+
+ table 1 ("table1"):
+ active=0, lookup=0, matched=0
+ (same features)
+'
+ for i in `seq 2 253`; do
+ printf ' table %d ("table%d"): ditto\n' $i $i
done
- echo "
- table 254 (\"table254\"):
- active=2, lookup=0, matched=0$tail") > expout
+ echo ' table 254 ("table254"):
+ active=2, lookup=0, matched=0
+ (same features)') > 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 "
(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 "
- table $x:
- active=0, lookup=0, matched=0"
- x=`expr $x + 1`
+ active=1, lookup=0, matched=0
+
+ table 1:
+ active=0, lookup=0, matched=0
+"
+ for i in `seq 2 253`; do
+ printf ' table %d: ditto\n' $i
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
])
-(printf "OFPST_TABLE reply (OF1.3) (xid=0x2):"
- x=0
- while test $x -lt 254; do
- echo "
- table $x:
- active=0, lookup=0, matched=0"
- x=`expr $x + 1`
+(echo "OFPST_TABLE reply (OF1.3) (xid=0x2):
+ table 0:
+ active=0, lookup=0, matched=0
+"
+ for i in `seq 1 253`; do
+ printf ' table %d: ditto\n' $i
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
(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 "
- table $x:
- active=0, lookup=0, matched=0"
- x=`expr $x + 1`
+ active=0, lookup=3, matched=0
+
+ table 1:
+ active=0, lookup=0, matched=0
+"
+ for i in `seq 2 253`; do
+ printf ' table %d: ditto\n' $i
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br1 ], [0], [expout])
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 "
- table $x:
- active=0, lookup=0, matched=0"
- x=`expr $x + 1`
+ table 1: ditto
+ table 2:
+ active=0, lookup=0, matched=0
+"
+ for i in `seq 3 253`; do
+ printf ' table %d: ditto\n' $i
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
active=0, lookup=3, matched=0
table 1:
- active=1, lookup=3, matched=3"
- x=2
- while test $x -lt 254; do
- echo "
- table $x:
- active=0, lookup=0, matched=0"
- x=`expr $x + 1`
+ active=1, lookup=3, matched=3
+
+ table 2:
+ active=0, lookup=0, matched=0
+"
+ for i in `seq 3 253`; do
+ printf ' table %d: ditto\n' $i
done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-tables br0 ], [0], [expout])
AT_SETUP([ofproto - flow table configuration (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Check the default configuration.
-(printf "OFPST_TABLE reply (xid=0x2):"
- x=0
- name=classifier
- while test $x -lt 254; do
- printf "
- table %d (\"%s\"):
+head_table() {
+ printf 'OFPST_TABLE reply (xid=0x2):
+ table 0 ("%s"):
active=0, lookup=0, matched=0
max_entries=1000000
matching:
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
+
+' $1
+}
+ditto() {
+ for i in `seq $1 $2`; do
+ printf ' table %d ("table%d"): ditto\n' $i $i
+ done
+}
+(head_table classifier; ditto 1 253) > expout
AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout])
# Change the configuration.
AT_CHECK(
<1>
])
# Check that the configuration was updated.
-mv expout orig-expout
-sed -e 's/classifier/main/
-21s/1000000/1024/' orig-expout > expout
+(head_table main; echo ' table 1 ("table1"):
+ active=0, lookup=0, matched=0
+ max_entries=1024
+ (same matching)
+
+ table 2 ("table2"):
+ active=0, lookup=0, matched=0
+ max_entries=1000000
+ (same matching)
+'; ditto 3 253) > expout
AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_CHECK([test `grep '240\.0\.0\.1' stdout | grep -v table_id= | wc -l` -gt 0])
# Check that dump-tables doesn't count the hidden flows.
-(printf "OFPST_TABLE reply (xid=0x2):"
- x=0
- name=classifier
- while test $x -lt 254; do
- printf "
- table %d (\"%s\"):
+head_table() {
+ printf 'OFPST_TABLE reply (xid=0x2):
+ table 0 ("%s"):
active=0, lookup=0, matched=0
max_entries=1000000
matching:
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
+
+' $1
+}
+ditto() {
+ for i in `seq $1 $2`; do
+ printf ' table %d ("table%d"): ditto\n' $i $i
+ done
+}
+(head_table classifier; ditto 1 253) > expout
AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout])
OVS_VSWITCHD_STOP(["/cannot find route for controller/d"])
AT_CLEANUP
AT_SETUP([ofproto - flow table configuration (OpenFlow 1.2)])
OVS_VSWITCHD_START
# Check the default configuration.
-(printf "OFPST_TABLE reply (OF1.2) (xid=0x2):"
- x=0
- name=classifier
- while test $x -lt 254; do
- if test $x = 253; then
- goto=
- else
- goto=,goto_table
- fi
- echo "
- table $x (\"$name\"):
+head_table() {
+ printf 'OFPST_TABLE reply (OF1.2) (xid=0x2):
+ table 0 ("%s"):
active=0, lookup=0, matched=0
metadata: match=0xffffffffffffffff write=0xffffffffffffffff
config=controller
max_entries=1000000
instructions (table miss and others):
- instructions: apply_actions,clear_actions,write_actions,write_metadata$goto
+ 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 ipv6_label 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 nd_target nd_sll nd_tll
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
+ nd_tll: exact match or wildcard
+
+' $1
+}
+ditto() {
+ for i in `seq $1 $2`; do
+ printf ' table %d ("table%d"): ditto\n' $i $i
+ done
+}
+tail_table() {
+ printf ' table 253 ("table253"):
+ active=0, lookup=0, matched=0
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ config=controller
+ max_entries=1000000
+ instructions (table miss and others):
+ instructions: apply_actions,clear_actions,write_actions,write_metadata
+ (same actions)
+ (same matching)
+'
+}
+(head_table classifier; ditto 1 252; tail_table) > expout
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout])
# Change the configuration.
AT_CHECK(
<1>
])
# Check that the configuration was updated.
-mv expout orig-expout
-sed 's/classifier/main/
-53s/1000000/1024/' < orig-expout > expout
+(head_table main; echo ' table 1 ("table1"):
+ active=0, lookup=0, matched=0
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ config=controller
+ max_entries=1024
+ (same instructions)
+ (same matching)
+
+ table 2 ("table2"):
+ active=0, lookup=0, matched=0
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ config=controller
+ max_entries=1000000
+ (same instructions)
+ (same matching)
+'; ditto 3 252; tail_table) > expout
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([ofproto - table features (OpenFlow 1.3)])
OVS_VSWITCHD_START
-(x=0
- name=classifier
- while test $x -lt 254; do
- y=`expr $x + 1`
- if test $x = 253; then
- next=
- goto=
- else
- goto=,goto_table
- if test $x = 252; then
- next='
- next tables: 253'
- else
- next="
- next tables: $y-253"
- fi
- fi
- echo " table $x (\"$name\"):
+head_table () {
+ printf ' table 0 ("%s"):
metadata: match=0xffffffffffffffff write=0xffffffffffffffff
max_entries=1000000
- instructions (table miss and others):$next
- instructions: meter,apply_actions,clear_actions,write_actions,write_metadata$goto
+ instructions (table miss and others):
+ next tables: 1-253
+ instructions: meter,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 tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label 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 nd_target nd_sll nd_tll
icmpv6_code: exact match or wildcard
nd_target: arbitrary mask
nd_sll: arbitrary mask
- nd_tll: arbitrary mask"
- x=$y
- name=table$x
- done) > expout
-AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d
-/^OFPST_TABLE_FEATURES/d'], [0], [expout])
+ nd_tll: arbitrary mask
+
+' $1
+}
+ditto() {
+ printf ' table %d ("%s"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ max_entries=%d
+ instructions (table miss and others):
+ next tables: %d-253
+ (same instructions)
+ (same actions)
+ (same matching)
+
+' $1 $2 $3 `expr $1 + 1`
+}
+tail_tables() {
+echo ' table 252 ("table252"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ max_entries=1000000
+ instructions (table miss and others):
+ next tables: 253
+ (same instructions)
+ (same actions)
+ (same matching)
+
+ table 253 ("table253"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ max_entries=1000000
+ instructions (table miss and others):
+ instructions: meter,apply_actions,clear_actions,write_actions,write_metadata
+ (same actions)
+ (same matching)
+'
+}
+(head_table classifier
+ for i in `seq 1 251`; do
+ ditto $i table$i 1000000
+ done
+ tail_tables) > expout
+AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout])
# Change the configuration.
AT_CHECK(
[ovs-vsctl \
<1>
])
# Check that the configuration was updated.
-mv expout orig-expout
-sed 's/classifier/main/
-142s/1000000/1024/' < orig-expout > expout
-AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d
-/^OFPST_TABLE_FEATURES/d'], [0], [expout])
+(head_table main
+ ditto 1 table1 1024
+ for i in `seq 2 251`; do
+ ditto $i table$i 1000000
+ done
+ tail_tables) > expout
+AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP
open_vconn(ctx->argv[1], &vconn);
request = ofputil_encode_table_features_request(vconn_get_version(vconn));
- if (request) {
- dump_stats_transaction(vconn, request);
+
+ /* The following is similar to dump_trivial_stats_transaction(), but it
+ * maintains the previous 'ofputil_table_features' from one stats reply
+ * message to the next, which allows duplication to be eliminated in the
+ * output across messages. Otherwise the output is much larger and harder
+ * to read, because only 17 or so ofputil_table_features elements fit in a
+ * single 64 kB OpenFlow message and therefore you get a ton of repetition
+ * (every 17th element is printed in full instead of abbreviated). */
+
+ const struct ofp_header *request_oh = request->data;
+ ovs_be32 send_xid = request_oh->xid;
+ bool done = false;
+
+ struct ofputil_table_features prev;
+ int n = 0;
+
+ send_openflow_buffer(vconn, request);
+ while (!done) {
+ ovs_be32 recv_xid;
+ struct ofpbuf *reply;
+
+ run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
+ recv_xid = ((struct ofp_header *) reply->data)->xid;
+ if (send_xid == recv_xid) {
+ enum ofptype type;
+ enum ofperr error;
+ error = ofptype_decode(&type, reply->data);
+ if (error) {
+ ovs_fatal(0, "decode error: %s", ofperr_get_name(error));
+ } else if (type == OFPTYPE_ERROR) {
+ ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+ done = true;
+ } else if (type == OFPTYPE_TABLE_FEATURES_STATS_REPLY) {
+ done = !ofpmp_more(reply->data);
+ for (;;) {
+ struct ofputil_table_features tf;
+ int retval;
+
+ retval = ofputil_decode_table_features(reply, &tf, true);
+ if (retval) {
+ if (retval != EOF) {
+ ovs_fatal(0, "decode error: %s",
+ ofperr_get_name(retval));
+ }
+ break;
+ }
+
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ofp_print_table_features(&s, &tf, n ? &prev : NULL,
+ NULL, NULL);
+ puts(ds_cstr(&s));
+ ds_destroy(&s);
+
+ prev = tf;
+ n++;
+ }
+ } else {
+ ovs_fatal(0, "received bad reply: %s",
+ ofp_to_string(reply->data, reply->size,
+ verbosity + 1));
+ }
+ } else {
+ VLOG_DBG("received reply with xid %08"PRIx32" "
+ "!= expected %08"PRIx32, recv_xid, send_xid);
+ }
+ ofpbuf_delete(reply);
}
vconn_close(vconn);