ofproto has a concept of "hidden" OpenFlow tables. Currently these are used internally only for ofproto-dpif for a couple of unimportant purposes. However, hidden tables were not hidden well enough, because OFTest was able to spot ofproto-dpif's hidden table and, seeing that it had a couple of flows in it even after OFTest had tried to delete all flows, failed at least one test.
This commit hides the tables better: - The number of tables reported in a feature reply no longer counts hidden tables. - Table stats replies omit hidden tables. This commit introduces the requirement that hidden tables, if any, be the highest-numbered tables. This is because it's not clear to me that OpenFlow intends to allow tables to be numbered noncontiguously. Found by openflow_protocol_messages.ModifyStateDelete in OFTest. Signed-off-by: Ben Pfaff <b...@nicira.com> --- ofproto/ofproto-provider.h | 23 +++++++++++++++++++++++ ofproto/ofproto.c | 32 ++++++++++++++++++++++++++++++-- tests/ofproto.at | 12 +++++------- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index a62473b..5de36ae 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -116,6 +116,29 @@ struct ofport { void ofproto_port_set_state(struct ofport *, enum ofputil_port_state); +/* OpenFlow table flags: + * + * - "Hidden" tables are not included in OpenFlow operations that operate on + * "all tables". For example, a request for flow stats on all tables will + * omit flows in hidden tables, table stats requests will omit the table + * entirely, and the switch features reply will not count the hidden table. + * + * However, operations that specifically name the particular table still + * operate on it. For example, flow_mods and flow stats requests on a + * hidden table work. + * + * To avoid gaps in table IDs (which have unclear validity in OpenFlow), + * hidden tables must be the highest-numbered tables that a provider + * implements. + * + * - "Read-only" tables can't be changed through OpenFlow operations. (At + * the moment all flow table operations go effectively through OpenFlow, so + * this means that read-only tables can't be changed at all after the + * read-only flag is set.) + * + * The generic ofproto layer never sets these flags. An ofproto provider can + * set them if it is appropriate. + */ enum oftable_flags { OFTABLE_HIDDEN = 1 << 0, /* Hide from most OpenFlow operations. */ OFTABLE_READONLY = 1 << 1 /* Don't allow OpenFlow to change this table. */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 444717e..d14d1d3 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -349,6 +349,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, const struct ofproto_class *class; struct ofproto *ofproto; int error; + int i; *ofprotop = NULL; @@ -414,7 +415,14 @@ ofproto_create(const char *datapath_name, const char *datapath_type, return error; } + /* Check that hidden tables, if any, are at the end. */ assert(ofproto->n_tables); + for (i = 0; i + 1 < ofproto->n_tables; i++) { + enum oftable_flags flags = ofproto->tables[i].flags; + enum oftable_flags next_flags = ofproto->tables[i + 1].flags; + + assert(!(flags & OFTABLE_HIDDEN) || next_flags & OFTABLE_HIDDEN); + } ofproto->datapath_id = pick_datapath_id(ofproto); init_ports(ofproto); @@ -2012,14 +2020,26 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) struct ofport *port; bool arp_match_ip; struct ofpbuf *b; + int n_tables; + int i; ofproto->ofproto_class->get_features(ofproto, &arp_match_ip, &features.actions); assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */ + /* Count only non-hidden tables in the number of tables. (Hidden tables, + * if present, are always at the end.) */ + n_tables = ofproto->n_tables; + for (i = 0; i < ofproto->n_tables; i++) { + if (ofproto->tables[i].flags & OFTABLE_HIDDEN) { + n_tables = i; + break; + } + } + features.datapath_id = ofproto->datapath_id; features.n_buffers = pktbuf_capacity(); - features.n_tables = ofproto->n_tables; + features.n_tables = n_tables; features.capabilities = (OFPUTIL_C_FLOW_STATS | OFPUTIL_C_TABLE_STATS | OFPUTIL_C_PORT_STATS | OFPUTIL_C_QUEUE_STATS); if (arp_match_ip) { @@ -2244,6 +2264,7 @@ handle_table_stats_request(struct ofconn *ofconn, struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp12_table_stats *ots; struct ofpbuf *msg; + int n_tables; size_t i; /* Set up default values. @@ -2272,9 +2293,16 @@ handle_table_stats_request(struct ofconn *ofconn, p->ofproto_class->get_tables(p, ots); + /* 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(ots[i].name, table->name, sizeof ots[i].name); } @@ -2284,7 +2312,7 @@ handle_table_stats_request(struct ofconn *ofconn, } } - msg = ofputil_encode_table_stats_reply(ots, p->n_tables, request); + msg = ofputil_encode_table_stats_reply(ots, n_tables, request); ofconn_send_reply(ofconn, msg); free(ots); diff --git a/tests/ofproto.at b/tests/ofproto.at index cbf07bc..5debeba 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -11,7 +11,7 @@ OVS_VSWITCHD_START AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout]) AT_CHECK([STRIP_XIDS stdout], [0], [dnl OFPT_FEATURES_REPLY: dpid:fedcba9876543210 -n_tables:255, n_buffers:256 +n_tables:254, n_buffers:256 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE LOCAL(br0): addr:aa:55:aa:55:00:00 @@ -91,7 +91,7 @@ do AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout]) AT_CHECK_UNQUOTED([STRIP_XIDS stdout], [0], [dnl OFPT_FEATURES_REPLY: dpid:fedcba9876543210 -n_tables:255, n_buffers:256 +n_tables:254, n_buffers:256 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE LOCAL(br0): addr:aa:55:aa:55:00:00 @@ -397,7 +397,7 @@ AT_CLEANUP AT_SETUP([ofproto - flow table configuration]) OVS_VSWITCHD_START # Check the default configuration. -(echo "OFPST_TABLE reply (xid=0x2): 255 tables +(echo "OFPST_TABLE reply (xid=0x2): 254 tables 0: classifier: wild=0x3fffff, max=1000000, active=0 lookup=0, matched=0" x=1 @@ -406,9 +406,7 @@ OVS_VSWITCHD_START lookup=0, matched=0 " $x table$x x=`expr $x + 1` - done - echo " 254: table254: wild=0x3fffff, max=1000000, active=2 - lookup=0, matched=0") > expout + done) > expout AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout]) # Change the configuration. AT_CHECK( @@ -422,7 +420,7 @@ AT_CHECK( ]) # Check that the configuration was updated. mv expout orig-expout -(echo "OFPST_TABLE reply (xid=0x2): 255 tables +(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 -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev