mirror of
https://github.com/openvswitch/ovs
synced 2025-08-30 05:47:55 +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.
|
release. See ovs-vswitchd(8) for details.
|
||||||
- OpenFlow:
|
- OpenFlow:
|
||||||
* OpenFlow 1.5 (draft) extended registers are now supported.
|
* 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
|
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.
|
Currently we always report OFPBRC_MULTIPART_BUFFER_OVERFLOW.
|
||||||
[optional for OF1.3+]
|
[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
|
* IPv6 extension header handling support. Fully implementing this
|
||||||
requires kernel support. This likely will take some careful and
|
requires kernel support. This likely will take some careful and
|
||||||
probably time-consuming design work. The actual coding, once
|
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
|
/* 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
|
* an IP netmask with a 1 in each bit that must match and a 0 in each bit that
|
||||||
* is wildcarded.
|
* is wildcarded.
|
||||||
@ -4801,6 +4831,108 @@ ofputil_encode_table_features_request(enum ofp_version ofp_version)
|
|||||||
return request;
|
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 */
|
/* ofputil_table_mod */
|
||||||
|
|
||||||
/* Given 'config', taken from an OpenFlow 'version' message that specifies
|
/* 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 *,
|
int ofputil_decode_table_features(struct ofpbuf *,
|
||||||
struct ofputil_table_features *, bool loose);
|
struct ofputil_table_features *, bool loose);
|
||||||
struct ofpbuf *ofputil_encode_table_features_request(
|
struct ofpbuf *ofputil_encode_table_features_request(enum ofp_version);
|
||||||
enum ofp_version ofp_version);
|
|
||||||
void ofputil_append_table_features_reply(
|
void ofputil_append_table_features_reply(
|
||||||
const struct ofputil_table_features *tf,
|
const struct ofputil_table_features *tf, struct list *replies);
|
||||||
struct list *replies);
|
|
||||||
|
|
||||||
/* Meter band configuration for all supported band types. */
|
/* Meter band configuration for all supported band types. */
|
||||||
struct ofputil_meter_band {
|
struct ofputil_meter_band {
|
||||||
|
@ -3189,6 +3189,37 @@ handle_table_stats_request(struct ofconn *ofconn,
|
|||||||
return 0;
|
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
|
static void
|
||||||
append_port_stat(struct ofport *port, struct list *replies)
|
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:
|
case OFPTYPE_TABLE_STATS_REQUEST:
|
||||||
return handle_table_stats_request(ofconn, oh);
|
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:
|
case OFPTYPE_PORT_STATS_REQUEST:
|
||||||
return handle_port_stats_request(ofconn, oh);
|
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_STATS_REPLY:
|
||||||
case OFPTYPE_METER_CONFIG_STATS_REPLY:
|
case OFPTYPE_METER_CONFIG_STATS_REPLY:
|
||||||
case OFPTYPE_METER_FEATURES_STATS_REPLY:
|
case OFPTYPE_METER_FEATURES_STATS_REPLY:
|
||||||
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
|
|
||||||
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
|
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
|
||||||
case OFPTYPE_ROLE_STATUS:
|
case OFPTYPE_ROLE_STATUS:
|
||||||
default:
|
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
|
OVS_VSWITCHD_STOP
|
||||||
AT_CLEANUP
|
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)])
|
AT_SETUP([ofproto - hard limits on flow table size (OpenFlow 1.0)])
|
||||||
OVS_VSWITCHD_START
|
OVS_VSWITCHD_START
|
||||||
# Configure a maximum of 4 flows.
|
# Configure a maximum of 4 flows.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user