mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
ofproto: Implement OpenFlow 1.3+ table features request.
Signed-off-by: Ben Pfaff <blp@nicira.com> Acked-by: Jarno Rajahalme <jrajahalme@nicira.com>
This commit is contained in:
parent
e722782135
commit
3c4e10fbd4
1
NEWS
1
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
|
||||
|
@ -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
|
||||
|
132
lib/ofp-util.c
132
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
|
||||
|
@ -679,11 +679,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 {
|
||||
|
@ -3189,6 +3189,37 @@ 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 +6024,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 +6091,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:
|
||||
|
105
tests/ofproto.at
105
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user