From 03c72922c2c7b00933d97235fddfd7956948349d Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 2 Jul 2015 20:35:44 -0700 Subject: [PATCH] Implement OpenFlow 1.4+ OFPMP_TABLE_DESC message. Signed-off-by: Ben Pfaff Co-authored-by: Saloni Jain Signed-off-by: Saloni Jain Acked-by: Jarno Rajahalme --- NEWS | 1 + include/openflow/openflow-1.4.h | 10 +++ lib/learning-switch.c | 2 + lib/ofp-msgs.h | 10 +++ lib/ofp-print.c | 39 +++++++++ lib/ofp-util.c | 135 ++++++++++++++++++++++++++++++++ lib/ofp-util.h | 21 +++++ lib/rconn.c | 2 + ofproto/ofproto.c | 45 +++++++++++ ovn/controller/ofctrl.c | 2 + tests/ofproto.at | 22 ++++++ utilities/ovs-ofctl.8.in | 4 + utilities/ovs-ofctl.c | 19 +++++ 13 files changed, 312 insertions(+) diff --git a/NEWS b/NEWS index 57e4f89e3..59f25527f 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Post-v2.4.0 now supported. * OpenFlow 1.4+ "importance" is now considered for flow eviction. * OpenFlow 1.4+ OFPTC_EVICTION is now implemented. + * OpenFlow 1.4+ OFPMP_TABLE_DESC is now implemented. - Support for matching and generating options with Geneve tunnels. - Support Multicast Listener Discovery (MLDv1 and MLDv2). diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h index 7631e47c4..567aaaea9 100644 --- a/include/openflow/openflow-1.4.h +++ b/include/openflow/openflow-1.4.h @@ -155,6 +155,16 @@ struct ofp14_table_mod { }; OFP_ASSERT(sizeof(struct ofp14_table_mod) == 8); +/* Body of reply to OFPMP_TABLE_DESC request. */ +struct ofp14_table_desc { + ovs_be16 length; /* Length is padded to 64 bits. */ + uint8_t table_id; /* Identifier of table. Lower numbered tables + are consulted first. */ + uint8_t pad[1]; /* Align to 32-bits. */ + ovs_be32 config; /* Bitmap of OFPTC_* values. */ + /* Followed by 0 or more OFPTMPT14_* properties. */ +}; +OFP_ASSERT(sizeof(struct ofp14_table_desc) == 8); /* ## ---------------- ## */ /* ## ofp14_port_stats ## */ diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 2fe38a0ac..1753ceac0 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -447,6 +447,8 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg) case OFPTYPE_METER_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_BUNDLE_CONTROL: case OFPTYPE_BUNDLE_ADD_MESSAGE: case OFPTYPE_NXT_GENEVE_TABLE_MOD: diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h index e28bd507a..29729c098 100644 --- a/lib/ofp-msgs.h +++ b/lib/ofp-msgs.h @@ -369,6 +369,12 @@ enum ofpraw { /* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */ OFPRAW_OFPST13_TABLE_FEATURES_REPLY, + /* OFPST 1.4+ (15): void. */ + OFPRAW_OFPST14_TABLE_DESC_REQUEST, + + /* OFPST 1.4+ (15): struct ofp14_table_desc, uint8_t[8][]. */ + OFPRAW_OFPST14_TABLE_DESC_REPLY, + /* OFPST 1.0-1.4 (13): void. */ OFPRAW_OFPST10_PORT_DESC_REQUEST, /* OFPST 1.5+ (13): ovs_be32. */ @@ -611,6 +617,10 @@ enum ofptype { OFPTYPE_TABLE_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. */ + OFPTYPE_TABLE_DESC_REQUEST, /* OFPRAW_OFPST14_TABLE_DESC_REQUEST. */ + + OFPTYPE_TABLE_DESC_REPLY, /* OFPRAW_OFPST14_TABLE_DESC_REPLY. */ + OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST10_PORT_DESC_REQUEST. * OFPRAW_OFPST15_PORT_DESC_REQUEST. */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index d76134f74..4603bb7cc 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1025,6 +1025,18 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh) } } +/* This function will print the Table description properties. */ +static void +ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc *td) +{ + ds_put_format(string, "\n table %"PRIu8, td->table_id); + ds_put_cstr(string, ":\n"); + ds_put_format(string, " eviction=%s eviction_flags=", + ofputil_table_eviction_to_string(td->eviction)); + ofputil_put_eviction_flags(string, td->eviction_flags); + ds_put_char(string, '\n'); +} + static void ofp_print_queue_get_config_request(struct ds *string, const struct ofp_header *oh) @@ -2607,6 +2619,28 @@ ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh) } } +static void +ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh) +{ + struct ofpbuf b; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + + for (;;) { + struct ofputil_table_desc td; + int retval; + + retval = ofputil_decode_table_desc(&b, &td, oh->version); + if (retval) { + if (retval != EOF) { + ofp_print_error(s, retval); + } + return; + } + ofp_print_table_desc(s, &td); + } +} + static const char * bundle_flags_to_name(uint32_t bit) { @@ -2814,6 +2848,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, ofp_print_table_features_reply(string, oh); break; + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: + ofp_print_table_desc_reply(string, oh); + break; + case OFPTYPE_HELLO: ofp_print_hello(string, oh); break; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 2e9ae47fa..f7dbdd549 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -4886,6 +4886,139 @@ ofputil_append_table_features_reply(const struct ofputil_table_features *tf, ofpmp_postappend(replies, start_ofs); } +static enum ofperr +parse_table_desc_eviction_property(struct ofpbuf *property, + struct ofputil_table_desc *td) +{ + struct ofp14_table_mod_prop_eviction *ote = property->data; + + if (property->size != sizeof *ote) { + return OFPERR_OFPBPC_BAD_LEN; + } + + td->eviction_flags = ntohl(ote->flags); + return 0; +} + +/* Decodes the next OpenFlow "table desc" message (of possibly several) from + * 'msg' into an abstract form in '*td'. Returns 0 if successful, EOF if the + * last "table desc" in 'msg' was already decoded, otherwise an OFPERR_* + * value. */ +int +ofputil_decode_table_desc(struct ofpbuf *msg, + struct ofputil_table_desc *td, + enum ofp_version version) +{ + struct ofp14_table_desc *otd; + struct ofpbuf properties; + size_t length; + + memset(td, 0, sizeof *td); + + if (!msg->header) { + ofpraw_pull_assert(msg); + } + + if (!msg->size) { + return EOF; + } + + otd = ofpbuf_try_pull(msg, sizeof *otd); + if (!otd) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFP14_TABLE_DESC reply has %"PRIu32" " + "leftover bytes at end", msg->size); + return OFPERR_OFPBRC_BAD_LEN; + } + + td->table_id = otd->table_id; + length = ntohs(otd->length); + if (length < sizeof *otd || length - sizeof *otd > msg->size) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFP14_TABLE_DESC reply claims invalid " + "length %"PRIuSIZE, length); + return OFPERR_OFPBRC_BAD_LEN; + } + length -= sizeof *otd; + ofpbuf_use_const(&properties, ofpbuf_pull(msg, length), length); + + td->eviction = ofputil_decode_table_eviction(otd->config, version); + td->eviction_flags = UINT32_MAX; + + while (properties.size > 0) { + struct ofpbuf payload; + enum ofperr error; + uint16_t type; + + error = ofputil_pull_property(&properties, &payload, &type); + if (error) { + return error; + } + + switch (type) { + case OFPTMPT14_EVICTION: + error = parse_table_desc_eviction_property(&payload, td); + break; + + default: + log_property(true, "unknown table_desc property %"PRIu16, type); + error = 0; + break; + } + + if (error) { + return error; + } + } + + return 0; +} + +/* Encodes and returns a request to obtain description of tables of a switch. + * The message is encoded for OpenFlow version 'ofp_version'. */ +struct ofpbuf * +ofputil_encode_table_desc_request(enum ofp_version ofp_version) +{ + struct ofpbuf *request = NULL; + + if (ofp_version >= OFP14_VERSION) { + request = ofpraw_alloc(OFPRAW_OFPST14_TABLE_DESC_REQUEST, + ofp_version, 0); + } else { + ovs_fatal(0, "dump-table-desc needs OpenFlow 1.4 or later " + "(\'-O OpenFlow14\')"); + } + + return request; +} + +/* Function to append Table desc information in a reply list. */ +void +ofputil_append_table_desc_reply(const struct ofputil_table_desc *td, + struct ovs_list *replies, + enum ofp_version version) +{ + struct ofpbuf *reply = ofpbuf_from_list(list_back(replies)); + size_t start_otd; + struct ofp14_table_desc *otd; + + start_otd = reply->size; + ofpbuf_put_zeros(reply, sizeof *otd); + if (td->eviction_flags != UINT32_MAX) { + struct ofp14_table_mod_prop_eviction *ote; + + ote = ofpbuf_put_zeros(reply, sizeof *ote); + ote->type = htons(OFPTMPT14_EVICTION); + ote->length = htons(sizeof *ote); + ote->flags = htonl(td->eviction_flags); + } + + otd = ofpbuf_at_assert(reply, start_otd, sizeof *otd); + otd->length = htons(reply->size - start_otd); + otd->table_id = td->table_id; + otd->config = ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT, + td->eviction, version); + ofpmp_postappend(replies, start_otd); +} + static enum ofperr parse_table_mod_eviction_property(struct ofpbuf *property, struct ofputil_table_mod *tm) @@ -8890,6 +9023,7 @@ ofputil_is_bundlable(enum ofptype type) case OFPTYPE_AGGREGATE_STATS_REQUEST: case OFPTYPE_TABLE_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: + case OFPTYPE_TABLE_DESC_REQUEST: case OFPTYPE_PORT_STATS_REQUEST: case OFPTYPE_QUEUE_STATS_REQUEST: case OFPTYPE_PORT_DESC_STATS_REQUEST: @@ -8931,6 +9065,7 @@ ofputil_is_bundlable(enum ofptype type) case OFPTYPE_METER_CONFIG_STATS_REPLY: case OFPTYPE_METER_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_ROLE_STATUS: case OFPTYPE_NXT_GENEVE_TABLE_REQUEST: case OFPTYPE_NXT_GENEVE_TABLE_REPLY: diff --git a/lib/ofp-util.h b/lib/ofp-util.h index fbc8abf9e..431f165a8 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -638,6 +638,13 @@ struct ofputil_table_mod { uint32_t eviction_flags; /* OFPTMPEF14_*. */ }; +/* Abstract ofp14_table_desc. */ +struct ofputil_table_desc { + uint8_t table_id; /* ID of the table. */ + enum ofputil_table_eviction eviction; + uint32_t eviction_flags; /* UINT32_MAX if not present. */ +}; + enum ofperr ofputil_decode_table_mod(const struct ofp_header *, struct ofputil_table_mod *); struct ofpbuf *ofputil_encode_table_mod(const struct ofputil_table_mod *, @@ -726,11 +733,22 @@ struct ofputil_table_features { int ofputil_decode_table_features(struct ofpbuf *, struct ofputil_table_features *, bool loose); + +int ofputil_decode_table_desc(struct ofpbuf *, + struct ofputil_table_desc *, + enum ofp_version); + struct ofpbuf *ofputil_encode_table_features_request(enum ofp_version); +struct ofpbuf *ofputil_encode_table_desc_request(enum ofp_version); + void ofputil_append_table_features_reply( const struct ofputil_table_features *tf, struct ovs_list *replies); +void ofputil_append_table_desc_reply(const struct ofputil_table_desc *td, + struct ovs_list *replies, + enum ofp_version); + /* Meter band configuration for all supported band types. */ struct ofputil_meter_band { uint16_t type; @@ -857,6 +875,9 @@ struct ofputil_table_stats { }; struct ofpbuf *ofputil_encode_table_stats_reply(const struct ofp_header *rq); + +struct ofpbuf *ofputil_encode_table_desc_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 *); diff --git a/lib/rconn.c b/lib/rconn.c index 776ab9e98..37adfa2d5 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -1365,6 +1365,8 @@ is_admitted_msg(const struct ofpbuf *b) case OFPTYPE_GROUP_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: return false; case OFPTYPE_PACKET_IN: diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 970aca399..7ca6504fa 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -3576,6 +3576,47 @@ handle_table_features_request(struct ofconn *ofconn, return 0; } +/* This function queries the database for dumping table-desc. */ +static void +query_tables_desc(struct ofproto *ofproto, struct ofputil_table_desc **descp) +{ + struct ofputil_table_desc *table_desc; + size_t i; + + table_desc = *descp = xcalloc(ofproto->n_tables, sizeof *table_desc); + for (i = 0; i < ofproto->n_tables; i++) { + struct ofputil_table_desc *td = &table_desc[i]; + td->table_id = i; + td->eviction = (ofproto->tables[i].eviction & EVICTION_OPENFLOW + ? OFPUTIL_TABLE_EVICTION_ON + : OFPUTIL_TABLE_EVICTION_OFF); + td->eviction_flags = OFPROTO_EVICTION_FLAGS; + } +} + +/* Function to handle dump-table-desc request. */ +static enum ofperr +handle_table_desc_request(struct ofconn *ofconn, + const struct ofp_header *request) +{ + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); + struct ofputil_table_desc *table_desc; + struct ovs_list replies; + size_t i; + + query_tables_desc(ofproto, &table_desc); + ofpmp_init(&replies, request); + for (i = 0; i < ofproto->n_tables; i++) { + if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) { + ofputil_append_table_desc_reply(&table_desc[i], &replies, + request->version); + } + } + ofconn_send_replies(ofconn, &replies); + free(table_desc); + return 0; +} + static void append_port_stat(struct ofport *port, struct ovs_list *replies) { @@ -7105,6 +7146,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: return handle_table_features_request(ofconn, oh); + case OFPTYPE_TABLE_DESC_REQUEST: + return handle_table_desc_request(ofconn, oh); + case OFPTYPE_PORT_STATS_REQUEST: return handle_port_stats_request(ofconn, oh); @@ -7176,6 +7220,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_METER_CONFIG_STATS_REPLY: case OFPTYPE_METER_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_ROLE_STATUS: case OFPTYPE_NXT_GENEVE_TABLE_REPLY: default: diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c index 84050013e..2c424a682 100644 --- a/ovn/controller/ofctrl.c +++ b/ovn/controller/ofctrl.c @@ -225,6 +225,8 @@ ofctrl_recv(const struct ofpbuf *msg) case OFPTYPE_METER_FEATURES_STATS_REPLY: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REPLY: + case OFPTYPE_TABLE_DESC_REQUEST: + case OFPTYPE_TABLE_DESC_REPLY: case OFPTYPE_BUNDLE_CONTROL: case OFPTYPE_BUNDLE_ADD_MESSAGE: case OFPTYPE_NXT_GENEVE_TABLE_MOD: diff --git a/tests/ofproto.at b/tests/ofproto.at index 54c077d69..232dd2fe9 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -1664,6 +1664,28 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto - table description (OpenFlow 1.4)]) +OVS_VSWITCHD_START +(x=0 + while test $x -lt 254; do + y=`expr $x + 1` + echo " table $x: + eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME" + x=$y + done) > expout +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d +/^OFPST_TABLE_DESC/d'], [0], [expout]) + +# Change the configuration. +AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 evict]) +# Check that the configuration was updated. +mv expout orig-expout +sed -e '2s/eviction=off/eviction=on/' expout +AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d +/^OFPST_TABLE_DESC/d'], [0], [expout]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto - hard limits on flow table size (OpenFlow 1.0)]) OVS_VSWITCHD_START # Configure a maximum of 4 flows. diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 058d20539..0a40efa1f 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -62,6 +62,10 @@ Prints to the console statistics for each of the flow tables used by \fBdump\-table\-features \fIswitch\fR Prints to the console features for each of the flow tables used by \fIswitch\fR. +.TP +\fBdump\-table\-desc \fIswitch\fR +Prints to the console configuration for each of the flow tables used +by \fIswitch\fR for OpenFlow 1.4+. .IP "\fBmod\-table \fIswitch\fR \fItable_id\fR \fIsetting\fR" This command configures flow table settings for OpenFlow table \fItable_id\fR within \fIswitch\fR. The available settings depend on diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index f16cc2591..566a6b42f 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -338,6 +338,7 @@ usage(void) " dump-desc SWITCH print switch description\n" " dump-tables SWITCH print table stats\n" " dump-table-features SWITCH print table features\n" + " dump-table-desc SWITCH print table description (OF1.4+)\n" " mod-port SWITCH IFACE ACT modify port behavior\n" " mod-table SWITCH MOD modify flow table behavior\n" " OF1.1/1.2 MOD: controller, continue, drop\n" @@ -737,6 +738,22 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx) vconn_close(vconn); } +static void +ofctl_dump_table_desc(struct ovs_cmdl_context *ctx) +{ + struct ofpbuf *request; + struct vconn *vconn; + + open_vconn(ctx->argv[1], &vconn); + request = ofputil_encode_table_desc_request(vconn_get_version(vconn)); + if (request) { + dump_stats_transaction(vconn, request); + } + + vconn_close(vconn); +} + + static bool fetch_port_by_stats(struct vconn *, const char *port_name, ofp_port_t port_no, struct ofputil_phy_port *); @@ -3612,6 +3629,8 @@ static const struct ovs_cmdl_command all_commands[] = { 1, 1, ofctl_dump_tables }, { "dump-table-features", "switch", 1, 1, ofctl_dump_table_features }, + { "dump-table-desc", "switch", + 1, 1, ofctl_dump_table_desc }, { "dump-flows", "switch", 1, 2, ofctl_dump_flows }, { "dump-aggregate", "switch", -- 2.20.1