#include "random.h"
#include "shash.h"
#include "simap.h"
+#include "smap.h"
#include "sset.h"
#include "timeval.h"
#include "unaligned.h"
{
const struct ofproto_class *class = ofproto_class_find__(type);
return class ? class->enumerate_names(type, names) : EAFNOSUPPORT;
- }
+}
int
ofproto_create(const char *datapath_name, const char *datapath_type,
return error;
}
+static void
+flow_mod_init(struct ofputil_flow_mod *fm,
+ const struct match *match, unsigned int priority,
+ const struct ofpact *ofpacts, size_t ofpacts_len,
+ enum ofp_flow_mod_command command)
+{
+ memset(fm, 0, sizeof *fm);
+ fm->match = *match;
+ fm->priority = priority;
+ fm->cookie = 0;
+ fm->new_cookie = 0;
+ fm->modify_cookie = false;
+ fm->table_id = 0;
+ fm->command = command;
+ fm->idle_timeout = 0;
+ fm->hard_timeout = 0;
+ fm->buffer_id = UINT32_MAX;
+ fm->out_port = OFPP_ANY;
+ fm->out_group = OFPG_ANY;
+ fm->flags = 0;
+ fm->ofpacts = CONST_CAST(struct ofpact *, ofpacts);
+ fm->ofpacts_len = ofpacts_len;
+}
+
static int
simple_flow_mod(struct ofproto *ofproto,
const struct match *match, unsigned int priority,
{
struct ofputil_flow_mod fm;
- memset(&fm, 0, sizeof fm);
- fm.match = *match;
- fm.priority = priority;
- fm.cookie = 0;
- fm.new_cookie = 0;
- fm.modify_cookie = false;
- fm.table_id = 0;
- fm.command = command;
- fm.idle_timeout = 0;
- fm.hard_timeout = 0;
- fm.buffer_id = UINT32_MAX;
- fm.out_port = OFPP_ANY;
- fm.out_group = OFPG_ANY;
- fm.flags = 0;
- fm.ofpacts = CONST_CAST(struct ofpact *, ofpacts);
- fm.ofpacts_len = ofpacts_len;
+ flow_mod_init(&fm, match, priority, ofpacts, ofpacts_len, command);
return handle_flow_mod__(ofproto, NULL, &fm, NULL);
}
static enum ofperr
ofproto_check_ofpacts(struct ofproto *ofproto,
const struct ofpact ofpacts[], size_t ofpacts_len,
- struct flow *flow, uint8_t table_id)
+ struct flow *flow, uint8_t table_id,
+ const struct ofp_header *oh)
{
enum ofperr error;
uint32_t mid;
error = ofpacts_check(ofpacts, ofpacts_len, flow,
- u16_to_ofp(ofproto->max_ports), table_id);
+ u16_to_ofp(ofproto->max_ports), table_id,
+ oh && oh->version > OFP10_VERSION);
if (error) {
return error;
}
/* Verify actions against packet, then send packet if successful. */
in_port_.ofp_port = po.in_port;
flow_extract(payload, 0, 0, NULL, &in_port_, &flow);
- error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0);
+ error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0, oh);
if (!error) {
error = p->ofproto_class->packet_out(p, payload, &flow,
po.ofpacts, po.ofpacts_len);
/* Verify actions. */
error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
- &fm->match.flow, table_id);
+ &fm->match.flow, table_id, request);
if (error) {
cls_rule_destroy(&cr);
return error;
enum ofperr error;
size_t i;
+ /* Verify actions before we start to modify any rules, to avoid partial
+ * flow table modifications. */
+ for (i = 0; i < rules->n; i++) {
+ struct rule *rule = rules->rules[i];
+
+ error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
+ &fm->match.flow, rule->table_id,
+ request);
+ if (error) {
+ return error;
+ }
+ }
+
type = fm->command == OFPFC_ADD ? OFOPERATION_REPLACE : OFOPERATION_MODIFY;
group = ofopgroup_create(ofproto, ofconn, request, fm->buffer_id);
error = OFPERR_OFPBRC_EPERM;
continue;
}
- /* Verify actions. */
- error = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
- u16_to_ofp(ofproto->max_ports), rule->table_id);
- if (error) {
- return error;
- }
-
actions_changed = !ofpacts_equal(fm->ofpacts, fm->ofpacts_len,
rule->actions->ofpacts,
rule->actions->ofpacts_len);
return 0;
}
+static enum ofperr
+handle_queue_get_config_request(struct ofconn *ofconn,
+ const struct ofp_header *oh)
+{
+ struct ofproto *p = ofconn_get_ofproto(ofconn);
+ struct netdev_queue_dump queue_dump;
+ struct ofport *ofport;
+ unsigned int queue_id;
+ struct ofpbuf *reply;
+ struct smap details;
+ ofp_port_t request;
+ enum ofperr error;
+
+ error = ofputil_decode_queue_get_config_request(oh, &request);
+ if (error) {
+ return error;
+ }
+
+ ofport = ofproto_get_port(p, request);
+ if (!ofport) {
+ return OFPERR_OFPQOFC_BAD_PORT;
+ }
+
+ reply = ofputil_encode_queue_get_config_reply(oh);
+
+ smap_init(&details);
+ NETDEV_QUEUE_FOR_EACH (&queue_id, &details, &queue_dump, ofport->netdev) {
+ struct ofputil_queue_config queue;
+
+ /* None of the existing queues have compatible properties, so we
+ * hard-code omitting min_rate and max_rate. */
+ queue.queue_id = queue_id;
+ queue.min_rate = UINT16_MAX;
+ queue.max_rate = UINT16_MAX;
+ ofputil_append_queue_get_config_reply(reply, &queue);
+ }
+ smap_destroy(&details);
+
+ ofconn_send_reply(ofconn, reply);
+
+ return 0;
+}
+
/* Implements OFPGC11_ADD
* in which no matching flow already exists in the flow table.
*
delete_group__(struct ofproto *ofproto, struct ofgroup *ofgroup)
OVS_RELEASES(ofproto->groups_rwlock)
{
+ struct match match;
+ struct ofputil_flow_mod fm;
+
+ /* Delete all flow entries containing this group in a group action */
+ match_init_catchall(&match);
+ flow_mod_init(&fm, &match, 0, NULL, 0, OFPFC_DELETE);
+ fm.out_group = ofgroup->group_id;
+ handle_flow_mod__(ofproto, NULL, &fm, NULL);
+
/* Must wait until existing readers are done,
* while holding the container's write lock at the same time. */
ovs_rwlock_wrlock(&ofgroup->rwlock);
if (error) {
return error;
}
+ if (oh->version >= OFP13_VERSION && ofpmsg_is_stat_request(oh)
+ && ofpmp_more(oh)) {
+ /* We have no buffer implementation for multipart requests.
+ * Report overflow for requests which consists of multiple
+ * messages. */
+ return OFPERR_OFPBRC_MULTIPART_BUFFER_OVERFLOW;
+ }
switch (type) {
/* OpenFlow requests. */
case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
return handle_group_features_stats_request(ofconn, oh);
- /* FIXME: Change the following once they are implemented: */
case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
- case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
- return OFPERR_OFPBRC_BAD_TYPE;
+ return handle_queue_get_config_request(ofconn, oh);
case OFPTYPE_HELLO:
case OFPTYPE_ERROR:
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:
- return OFPERR_OFPBRC_BAD_TYPE;
+ if (ofpmsg_is_stat_request(oh)) {
+ return OFPERR_OFPBRC_BAD_STAT;
+ } else {
+ return OFPERR_OFPBRC_BAD_TYPE;
+ }
}
}
ofproto->vlans_changed = false;
OFPROTO_FOR_EACH_TABLE (oftable, ofproto) {
- const struct cls_table *table;
+ const struct cls_subtable *table;
ovs_rwlock_rdlock(&oftable->cls.rwlock);
- HMAP_FOR_EACH (table, hmap_node, &oftable->cls.tables) {
+ HMAP_FOR_EACH (table, hmap_node, &oftable->cls.subtables) {
if (minimask_get_vid_mask(&table->mask) == VLAN_VID_MASK) {
const struct cls_rule *rule;