[ovs-dev] [PATCH 9/9] ofproto: Implement OpenFlow 1.3+ table features request.
Ben Pfaff
blp at nicira.com
Mon Aug 4 16:21:10 UTC 2014
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
NEWS | 1 +
OPENFLOW-1.1+ | 3 --
lib/ofp-util.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/ofp-util.h | 7 ++-
ofproto/ofproto.c | 36 ++++++++++++++-
tests/ofproto.at | 105 +++++++++++++++++++++++++++++++++++++++++++
6 files changed, 276 insertions(+), 8 deletions(-)
diff --git a/NEWS b/NEWS
index 742ae22..23e19d1 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Post-v2.3.0
- The OVS database now reports controller rate limiting statistics.
- OpenFlow:
* OpenFlow 1.5 (draft) extended registers are now supported.
+ * OpenFlow 1.3+ table features requests are now supported (read-only).
v2.3.0 - xx xxx xxxx
diff --git a/OPENFLOW-1.1+ b/OPENFLOW-1.1+
index 476f79a..01adf72 100644
--- a/OPENFLOW-1.1+
+++ b/OPENFLOW-1.1+
@@ -82,9 +82,6 @@ didn't compare the specs carefully yet.)
Currently we always report OFPBRC_MULTIPART_BUFFER_OVERFLOW.
[optional for OF1.3+]
- * Add OFPMP_TABLE_FEATURES statistics. Alexander Wu has posted a
- patch series. [optional for OF1.3+]
-
* IPv6 extension header handling support. Fully implementing this
requires kernel support. This likely will take some careful and
probably time-consuming design work. The actual coding, once
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 9b6ece9..261220c 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -120,6 +120,36 @@ log_property(bool loose, const char *message, ...)
}
}
+static size_t
+start_property(struct ofpbuf *msg, uint16_t type)
+{
+ size_t start_ofs = ofpbuf_size(msg);
+ struct ofp_prop_header *oph;
+
+ oph = ofpbuf_put_uninit(msg, sizeof *oph);
+ oph->type = htons(type);
+ oph->len = htons(4); /* May be updated later by end_property(). */
+ return start_ofs;
+}
+
+static void
+end_property(struct ofpbuf *msg, size_t start_ofs)
+{
+ struct ofp_prop_header *oph;
+
+ oph = ofpbuf_at_assert(msg, start_ofs, sizeof *oph);
+ oph->len = htons(ofpbuf_size(msg) - start_ofs);
+ ofpbuf_padto(msg, ROUND_UP(ofpbuf_size(msg), 8));
+}
+
+static void
+put_bitmap_properties(struct ofpbuf *msg, uint64_t bitmap)
+{
+ for (; bitmap; bitmap = zero_rightmost_1bit(bitmap)) {
+ start_property(msg, rightmost_1bit_idx(bitmap));
+ }
+}
+
/* Given the wildcard bit count in the least-significant 6 of 'wcbits', returns
* an IP netmask with a 1 in each bit that must match and a 0 in each bit that
* is wildcarded.
@@ -4801,6 +4831,108 @@ ofputil_encode_table_features_request(enum ofp_version ofp_version)
return request;
}
+static void
+put_fields_property(struct ofpbuf *reply,
+ const struct mf_bitmap *fields,
+ const struct mf_bitmap *masks,
+ enum ofp13_table_feature_prop_type property,
+ enum ofp_version version)
+{
+ size_t start_ofs;
+ int field;
+
+ start_ofs = start_property(reply, property);
+ BITMAP_FOR_EACH_1 (field, MFF_N_IDS, fields->bm) {
+ uint32_t h_oxm = mf_oxm_header(field, version);
+ ovs_be32 n_oxm;
+
+ if (masks && bitmap_is_set(masks->bm, field)) {
+ h_oxm = NXM_MAKE_WILD_HEADER(h_oxm);
+ }
+
+ n_oxm = htonl(h_oxm);
+ ofpbuf_put(reply, &n_oxm, sizeof n_oxm);
+ }
+ end_property(reply, start_ofs);
+}
+
+static void
+put_table_action_features(struct ofpbuf *reply,
+ const struct ofputil_table_action_features *taf,
+ enum ofp13_table_feature_prop_type actions_type,
+ enum ofp13_table_feature_prop_type set_fields_type,
+ int miss_offset, enum ofp_version version)
+{
+ size_t start_ofs;
+
+ start_ofs = start_property(reply, actions_type + miss_offset);
+ put_bitmap_properties(reply,
+ ntohl(ofpact_bitmap_to_openflow(taf->ofpacts,
+ version)));
+ end_property(reply, start_ofs);
+
+ put_fields_property(reply, &taf->set_fields, NULL,
+ set_fields_type + miss_offset, version);
+}
+
+static void
+put_table_instruction_features(
+ struct ofpbuf *reply, const struct ofputil_table_instruction_features *tif,
+ int miss_offset, enum ofp_version version)
+{
+ size_t start_ofs;
+ uint8_t table_id;
+
+ start_ofs = start_property(reply, OFPTFPT13_INSTRUCTIONS + miss_offset);
+ put_bitmap_properties(reply,
+ ntohl(ovsinst_bitmap_to_openflow(tif->instructions,
+ version)));
+ end_property(reply, start_ofs);
+
+ start_ofs = start_property(reply, OFPTFPT13_NEXT_TABLES + miss_offset);
+ BITMAP_FOR_EACH_1 (table_id, 255, tif->next) {
+ ofpbuf_put(reply, &table_id, 1);
+ }
+ end_property(reply, start_ofs);
+
+ put_table_action_features(reply, &tif->write,
+ OFPTFPT13_WRITE_ACTIONS,
+ OFPTFPT13_WRITE_SETFIELD, miss_offset, version);
+ put_table_action_features(reply, &tif->apply,
+ OFPTFPT13_APPLY_ACTIONS,
+ OFPTFPT13_APPLY_SETFIELD, miss_offset, version);
+}
+
+void
+ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
+ struct list *replies)
+{
+ struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
+ enum ofp_version version = ofpmp_version(replies);
+ size_t start_ofs = ofpbuf_size(reply);
+ struct ofp13_table_features *otf;
+
+ otf = ofpbuf_put_zeros(reply, sizeof *otf);
+ otf->table_id = tf->table_id;
+ ovs_strlcpy(otf->name, tf->name, sizeof otf->name);
+ otf->metadata_match = tf->metadata_match;
+ otf->metadata_write = tf->metadata_write;
+ otf->config = ofputil_table_miss_to_config(tf->miss_config, version);
+ otf->max_entries = htonl(tf->max_entries);
+
+ put_table_instruction_features(reply, &tf->nonmiss, 0, version);
+ put_table_instruction_features(reply, &tf->miss, 1, version);
+
+ put_fields_property(reply, &tf->match, &tf->mask,
+ OFPTFPT13_MATCH, version);
+ put_fields_property(reply, &tf->wildcard, NULL,
+ OFPTFPT13_WILDCARDS, version);
+
+ otf = ofpbuf_at_assert(reply, start_ofs, sizeof *otf);
+ otf->length = htons(ofpbuf_size(reply) - start_ofs);
+ ofpmp_postappend(replies, start_ofs);
+}
+
/* ofputil_table_mod */
/* Given 'config', taken from an OpenFlow 'version' message that specifies
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index b9d2ae8..1db98de 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -678,11 +678,10 @@ struct ofputil_table_features {
int ofputil_decode_table_features(struct ofpbuf *,
struct ofputil_table_features *, bool loose);
-struct ofpbuf *ofputil_encode_table_features_request(
- enum ofp_version ofp_version);
+struct ofpbuf *ofputil_encode_table_features_request(enum ofp_version);
+
void ofputil_append_table_features_reply(
- const struct ofputil_table_features *tf,
- struct list *replies);
+ const struct ofputil_table_features *tf, struct list *replies);
/* Meter band configuration for all supported band types. */
struct ofputil_meter_band {
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 6bcec1e..cbac36a 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3189,6 +3189,38 @@ handle_table_stats_request(struct ofconn *ofconn,
return 0;
}
+static enum ofperr
+handle_table_features_request(struct ofconn *ofconn,
+ const struct ofp_header *request)
+{
+ struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ struct ofputil_table_features *features;
+ struct list replies;
+ struct ofpbuf msg;
+ size_t i;
+
+ ofpbuf_use_const(&msg, request, ntohs(request->length));
+ ofpraw_pull_assert(&msg);
+ if (ofpbuf_size(&msg) || ofpmp_more(request)) {
+ return OFPERR_OFPTFFC_EPERM;
+ }
+
+ query_tables(ofproto, &features, NULL);
+
+ ofpmp_init(&replies, request);
+ for (i = 0; i < ofproto->n_tables; i++) {
+ if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) {
+ ofputil_append_table_features_reply(&features[i], &replies);
+
+ }
+ }
+ ofconn_send_replies(ofconn, &replies);
+
+ free(features);
+
+ return 0;
+}
+
static void
append_port_stat(struct ofport *port, struct list *replies)
{
@@ -5993,6 +6025,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
case OFPTYPE_TABLE_STATS_REQUEST:
return handle_table_stats_request(ofconn, oh);
+ case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
+ return handle_table_features_request(ofconn, oh);
+
case OFPTYPE_PORT_STATS_REQUEST:
return handle_port_stats_request(ofconn, oh);
@@ -6057,7 +6092,6 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
case OFPTYPE_METER_STATS_REPLY:
case OFPTYPE_METER_CONFIG_STATS_REPLY:
case OFPTYPE_METER_FEATURES_STATS_REPLY:
- case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
case OFPTYPE_ROLE_STATUS:
default:
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 42072cb..d2e7196 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -1148,6 +1148,111 @@ 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=254
+ else
+ next=$y-254
+ fi
+ echo " table $x (\"$name\"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ max_entries=1000000
+ instructions (table miss and others):
+ next tables: $next
+ 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 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 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
+ matching:
+ dp_hash: arbitrary mask
+ recirc_id: exact match or wildcard
+ tun_id: arbitrary mask
+ tun_src: arbitrary mask
+ tun_dst: arbitrary mask
+ metadata: arbitrary mask
+ in_port: exact match or wildcard
+ in_port_oxm: exact match or wildcard
+ pkt_mark: arbitrary mask
+ reg0: arbitrary mask
+ reg1: arbitrary mask
+ reg2: arbitrary mask
+ reg3: arbitrary mask
+ reg4: arbitrary mask
+ reg5: arbitrary mask
+ reg6: arbitrary mask
+ reg7: arbitrary mask
+ xreg0: arbitrary mask
+ xreg1: arbitrary mask
+ xreg2: arbitrary mask
+ xreg3: arbitrary mask
+ eth_src: arbitrary mask
+ eth_dst: arbitrary mask
+ eth_type: exact match or wildcard
+ vlan_tci: arbitrary mask
+ vlan_vid: arbitrary mask
+ vlan_pcp: exact match or wildcard
+ mpls_label: exact match or wildcard
+ mpls_tc: exact match or wildcard
+ mpls_bos: exact match or wildcard
+ ip_src: arbitrary mask
+ ip_dst: arbitrary mask
+ ipv6_src: arbitrary mask
+ ipv6_dst: arbitrary mask
+ ipv6_label: arbitrary mask
+ nw_proto: exact match or wildcard
+ nw_tos: exact match or wildcard
+ ip_dscp: exact match or wildcard
+ nw_ecn: exact match or wildcard
+ nw_ttl: exact match or wildcard
+ ip_frag: arbitrary mask
+ arp_op: exact match or wildcard
+ arp_spa: arbitrary mask
+ arp_tpa: arbitrary mask
+ arp_sha: arbitrary mask
+ arp_tha: arbitrary mask
+ tcp_src: arbitrary mask
+ tcp_dst: arbitrary mask
+ tcp_flags: arbitrary mask
+ udp_src: arbitrary mask
+ udp_dst: arbitrary mask
+ sctp_src: arbitrary mask
+ sctp_dst: arbitrary mask
+ icmp_type: exact match or wildcard
+ icmp_code: exact match or wildcard
+ icmpv6_type: exact match or wildcard
+ 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])
+# Change the configuration.
+AT_CHECK(
+ [ovs-vsctl \
+ -- --id=@t0 create Flow_Table name=main \
+ -- --id=@t1 create Flow_Table flow-limit=1024 \
+ -- set bridge br0 'flow_tables={1=@t1,0=@t0}' \
+ | ${PERL} $srcdir/uuidfilt.pl],
+ [0], [<0>
+<1>
+])
+# Check that the configuration was updated.
+mv expout orig-expout
+sed 's/classifier/main/
+73s/1000000/1024/' < orig-expout > expout
+AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d
+/^OFPST_TABLE_FEATURES/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.
--
1.9.1
More information about the dev
mailing list