Signed-off-by: Simon Horman <ho...@verge.net.au> ---
v12 * No change v11 * No change v10 * No change v9 * Set wildcards, match, write_setfields and apply_setfields based on a bitmap of (1 << OFPXMT_*) v8 * Manual rebase * Make use of enum ofp_version * Add ofp-tests v7 * Omitted v6 * No change v5 * Manual rebase * Add OFPST_TABLE entry for Open Flow 1.1 and 1.2 to ofputil_msg_types, this wires-up decoding of table statistics messages. v4 * Initial post table test --- include/openflow/openflow-1.1.h | 4 ++ include/openflow/openflow-1.2.h | 5 ++ ofproto/ofproto-dpif.c | 32 ++++++++-- ofproto/ofproto-provider.h | 71 +++++++++++++++++++-- ofproto/ofproto.c | 133 ++++++++++++++++++++++++++++++++++++---- tests/ofp-print.at | 16 ++++- 6 files changed, 237 insertions(+), 24 deletions(-) diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h index 696c3ec..5592520 100644 --- a/include/openflow/openflow-1.1.h +++ b/include/openflow/openflow-1.1.h @@ -281,6 +281,10 @@ enum ofp11_instruction_type { OFPIT11_EXPERIMENTER = 0xFFFF /* Experimenter instruction */ }; +#define OFPIT11_ALL OFPIT11_GOTO_TABLE | OFPIT11_WRITE_METADATA | \ + OFPIT11_WRITE_ACTIONS | OFPIT11_APPLY_ACTIONS | \ + OFPIT11_CLEAR_ACTIONS + #define OFP11_INSTRUCTION_ALIGN 8 /* Generic ofp_instruction structure. */ diff --git a/include/openflow/openflow-1.2.h b/include/openflow/openflow-1.2.h index 0a73ed1..64bc993 100644 --- a/include/openflow/openflow-1.2.h +++ b/include/openflow/openflow-1.2.h @@ -106,8 +106,13 @@ enum oxm12_ofb_match_fields { OFPXMT12_OFB_IPV6_ND_TLL, /* Target link-layer for ND. */ OFPXMT12_OFB_MPLS_LABEL, /* MPLS label. */ OFPXMT12_OFB_MPLS_TC, /* MPLS TC. */ + + /* End Marker */ + OFPXMT12_OFB_MAX, }; +#define OFPXMT12_MASK ((1ULL << OFPXMT12_OFB_MAX) - 1) + /* OXM implementation makes use of NXM as they are the same format * with different field definitions */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 10d450e..36ab8d7 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1153,17 +1153,37 @@ get_features(struct ofproto *ofproto_ OVS_UNUSED, } static void -get_tables(struct ofproto *ofproto_, struct ofp10_table_stats *ots) +get_tables(struct ofproto *ofproto_, struct ofproto_table_stats *ots) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct dpif_dp_stats s; - strcpy(ots->name, "classifier"); - dpif_get_dp_stats(ofproto->dpif, &s); - put_32aligned_be64(&ots->lookup_count, htonll(s.n_hit + s.n_missed)); - put_32aligned_be64(&ots->matched_count, - htonll(s.n_hit + ofproto->n_matches)); + + switch ((enum ofp_version)ots->ofp_version) { + case OFP12_VERSION: + strcpy(ots->o12ts->name, "classifier"); + ots->o12ts->lookup_count = htonll(s.n_hit + s.n_missed); + ots->o12ts->matched_count = htonll(s.n_hit + ofproto->n_matches); + break; + + case OFP11_VERSION: + strcpy(ots->o11ts->name, "classifier"); + ots->o11ts->lookup_count = htonll(s.n_hit + s.n_missed); + ots->o11ts->matched_count = htonll(s.n_hit + ofproto->n_matches); + break; + + case OFP10_VERSION: + strcpy(ots->o10ts->name, "classifier"); + put_32aligned_be64(&ots->o10ts->lookup_count, + htonll(s.n_hit + s.n_missed)); + put_32aligned_be64(&ots->o10ts->matched_count, + htonll(s.n_hit + ofproto->n_matches)); + break; + + default: + NOT_REACHED(); + } } static struct ofport * diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 15dc347..c1757a4 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -194,6 +194,15 @@ struct rule { uint64_t modify_seqno; /* Sequence number when changed. */ }; +struct ofproto_table_stats { + enum ofp_version ofp_version; + union { + struct ofp10_table_stats *o10ts; + struct ofp11_table_stats *o11ts; + struct ofp12_table_stats *o12ts; + }; +}; + static inline struct rule * rule_from_cls_rule(const struct cls_rule *cls_rule) { @@ -449,14 +458,48 @@ struct ofproto_class { /* Helper for the OpenFlow OFPST_TABLE statistics request. * - * The 'ots' array contains 'ofproto->n_tables' elements. Each element is - * initialized as: + * The 'ots' structure contains two elements + * + * - 'ofp_version' the OpenFLow version in use, set to one of: + * OFP10_VERSION, OFP11_VERSION, OFP12_VERSION. + * These values denote OpenFLow 1.0, 1.1 and 1.2 + * respectively. + * + * - A union of 'o10ts', 'o11ts' and 'o12ts'. + * + * This is an array of OpenFLow version-specific table statistics + * elements. + * + * 'o10ts' should be used for OpenFLow 1.0. + * 'o11ts' should be used for OpenFLow 1.1. + * 'o12ts' should be used for OpenFLow 1.2. + * + * The 'o1Xts' 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. * - * - 'wildcards' to OFPFW10_ALL. + * - 'wildcards' to OFPFW10_ALL (OpenFLow 1.0) or + * OFPFW11_ALL (OpenFLow 1.1 and 1.2). + * + * - 'instructions' to OFPIT11_ALL (OpenFLow 1.1 and 1.2). + * Not present in OpenFLow 1.0. + * + * - 'write_actions' to OFPAT11_OUTPUT (OpenFLow 1.1) or + * OFPAT12_OUTPUT (OpenFLow 1.2). + * Not present in OpenFLow 1.0. + * + * - 'apply_actions' to OFPAT11_OUTPUT (OpenFLow 1.1) or + * OFPAT12_OUTPUT (OpenFLow 1.2). + * Not present in OpenFLow 1.0. + * + * - 'write_setfields' to OFPXMT12_SUPPORTED (OpenFLow 1.2). + * Not present in OpenFLow 1.0 or 1.1. + * + * - 'apply_setfields' to OFPXMT12_SUPPORTED (OpenFLow 1.2). + * Not present in OpenFLow 1.0 or 1.1. * * - 'max_entries' to 1,000,000. * @@ -472,6 +515,21 @@ struct ofproto_class { * - 'wildcards' to the set of wildcards actually supported by the table * (if it doesn't support all OpenFlow wildcards). * + * - 'instructions' to set the instructions actually supported by + * the table. + * + * - 'write_actions' to set the write actions actually supported by + * the table (if it doesn't support all OpenFlow actions). + * + * - 'apply_actions' to set the apply actions actually supported by + * the table (if it doesn't support all OpenFlow actions). + * + * - 'write_setfields' to set the write setfields actually supported by + * the table. + * + * - 'apply_setfields' to set the apply setfields actually supported by + * the table. + * * - 'max_entries' to the maximum number of flows actually supported by * the hardware. * @@ -481,10 +539,11 @@ 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. * - * Keep in mind that all of the members of struct ofp10_table_stats are in - * network byte order. + * Keep in mind that all of the members of elements of the oXts array + * are in network byte order. */ - void (*get_tables)(struct ofproto *ofproto, struct ofp10_table_stats *ots); + void (*get_tables)(struct ofproto *ofproto, + struct ofproto_table_stats *ots); /* ## ---------------- ## */ /* ## ofport Functions ## */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 5c9ab9d..3a39cca 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2203,9 +2203,21 @@ handle_desc_stats_request(struct ofconn *ofconn, return 0; } -static enum ofperr -handle_table_stats_request(struct ofconn *ofconn, - const struct ofp_header *request) +static void +stats_request_finish(const struct oftable *table, + char *name, size_t namelen, ovs_be32 *max_entries) { + if (table->name) { + ovs_strzcpy(name, table->name, namelen); + } + + if (table->max_flows < ntohl(*max_entries)) { + *max_entries = htonl(table->max_flows); + } +} + +static void +handle_table_stats_request10(struct ofconn *ofconn, + const struct ofp_header *request) { struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp10_table_stats *ots; @@ -2222,21 +2234,120 @@ handle_table_stats_request(struct ofconn *ofconn, ots[i].active_count = htonl(classifier_count(&p->tables[i].cls)); } - p->ofproto_class->get_tables(p, ots); + { + struct ofproto_table_stats ts = { + .ofp_version = OFP10_VERSION, + .o10ts = ots + }; + p->ofproto_class->get_tables(p, &ts); + } for (i = 0; i < p->n_tables; i++) { - const struct oftable *table = &p->tables[i]; + stats_request_finish(p->tables + i, ots[i].name, sizeof ots[i].name, + &ots[i].max_entries); + } - if (table->name) { - ovs_strzcpy(ots[i].name, table->name, sizeof ots[i].name); - } + ofconn_send_reply(ofconn, msg); +} - if (table->max_flows < ntohl(ots[i].max_entries)) { - ots[i].max_entries = htonl(table->max_flows); - } +static void +handle_table_stats_request11(struct ofconn *ofconn, + const struct ofp_header *request) +{ + struct ofproto *p = ofconn_get_ofproto(ofconn); + struct ofp11_table_stats *ots; + struct ofpbuf *msg; + size_t i; + + msg = ofpraw_alloc_stats_reply(request, sizeof *ots * p->n_tables); + ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables); + for (i = 0; i < p->n_tables; i++) { + ots[i].table_id = i; + sprintf(ots[i].name, "table%zu", i); + ots[i].wildcards = ots[i].match = htonl(OFPFW11_ALL); + ots[i].instructions = htonl(OFPIT11_ALL); + ots[i].write_actions = ots[i].apply_actions = htonl(OFPAT11_OUTPUT); + ots[i].config = ots[i].apply_actions = htonl(0); + ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */ + ots[i].active_count = htonl(classifier_count(&p->tables[i].cls)); + } + + { + struct ofproto_table_stats ts = { + .ofp_version = OFP11_VERSION, + .o11ts = ots + }; + p->ofproto_class->get_tables(p, &ts); + } + + for (i = 0; i < p->n_tables; i++) { + stats_request_finish(p->tables + i, ots[i].name, sizeof ots[i].name, + &ots[i].max_entries); + } + + ofconn_send_reply(ofconn, msg); +} + +static void +handle_table_stats_request12(struct ofconn *ofconn, + const struct ofp_header *request) +{ + struct ofproto *p = ofconn_get_ofproto(ofconn); + struct ofp12_table_stats *ots; + struct ofpbuf *msg; + size_t i; + + msg = ofpraw_alloc_stats_reply(request, sizeof *ots * p->n_tables); + ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables); + for (i = 0; i < p->n_tables; i++) { + ots[i].table_id = i; + sprintf(ots[i].name, "table%zu", i); + ots[i].wildcards = ots[i].match = ots[i].write_setfields = + ots[i].apply_setfields = htonll(OFPXMT12_MASK); + ots[i].write_actions = ots[i].apply_actions = htonl(OFPAT12_OUTPUT); + ots[i].instructions = htonl(OFPIT11_ALL); + ots[i].config = ots[i].apply_actions = htonl(0); + ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */ + ots[i].active_count = htonl(classifier_count(&p->tables[i].cls)); + } + + { + struct ofproto_table_stats ts = { + .ofp_version = OFP12_VERSION, + .o12ts = ots + }; + p->ofproto_class->get_tables(p, &ts); + } + + for (i = 0; i < p->n_tables; i++) { + stats_request_finish(p->tables + i, ots[i].name, sizeof ots[i].name, + &ots[i].max_entries); } ofconn_send_reply(ofconn, msg); +} + +static enum ofperr +handle_table_stats_request(struct ofconn *ofconn, + const struct ofp_header *request) +{ + switch (request->version) { + case OFP12_VERSION: + handle_table_stats_request12(ofconn, request); + break; + + case OFP11_VERSION: + handle_table_stats_request11(ofconn, request); + break; + + case OFP10_VERSION: + handle_table_stats_request10(ofconn, request); + break; + + default: + NOT_REACHED(); + } + return 0; } diff --git a/tests/ofp-print.at b/tests/ofp-print.at index aca502a..093c69b 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -794,13 +794,27 @@ OFPST_AGGREGATE reply (OF1.2) (xid=0x2): packet_count=121 byte_count=19279 flow_ ]) AT_CLEANUP -AT_SETUP([OFPST_TABLE request]) +AT_SETUP([OFPST_TABLE request - OF1.0]) AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) AT_CHECK([ovs-ofctl ofp-print "0110000c0000000100030000"], [0], [dnl OFPST_TABLE request (xid=0x1): ]) AT_CLEANUP +AT_SETUP([OFPST_TABLE request - OF1.1]) +AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) +AT_CHECK([ovs-ofctl ofp-print "02120010000000020003000000000000"], [0], [dnl +OFPST_TABLE request (OF1.1) (xid=0x2): +]) +AT_CLEANUP + +AT_SETUP([OFPST_TABLE request - OF1.2]) +AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) +AT_CHECK([ovs-ofctl ofp-print "03120010000000020003000000000000"], [0], [dnl +OFPST_TABLE request (OF1.2) (xid=0x2): +]) +AT_CLEANUP + AT_SETUP([OFPST_TABLE reply - OF1.0]) AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) AT_CHECK([ovs-ofctl ofp-print "\ -- 1.7.10.2.484.gcd07cc5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev