Signed-off-by: Ben Pfaff <b...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev