[ovs-dev] [PATCH v2 09/16] ofproto: Implement OpenFlow 1.3+ table features request.

Ben Pfaff blp at nicira.com
Thu Aug 7 23:13:55 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 bf7eb2f..94232b7 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Post-v2.3.0
      release.  See ovs-vswitchd(8) for details.
    - 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.7.10.4




More information about the dev mailing list