#include "meta-flow.h"
#include "netdev.h"
#include "nx-match.h"
+#include "ofp-actions.h"
#include "ofp-errors.h"
#include "ofp-print.h"
#include "ofp-util.h"
struct rule *rule; /* Rule being operated upon. */
enum ofoperation_type type; /* Type of operation. */
struct rule *victim; /* OFOPERATION_ADDING: Replaced rule. */
- union ofp_action *actions; /* OFOPERATION_MODIFYING: Replaced actions. */
- int n_actions; /* OFOPERATION_MODIFYING: # of old actions. */
+ struct ofpact *ofpacts; /* OFOPERATION_MODIFYING: Replaced actions. */
+ size_t ofpacts_len; /* OFOPERATION_MODIFYING: Bytes of ofpacts. */
ovs_be64 flow_cookie; /* Rule's old flow cookie. */
};
assert(ofproto->n_tables);
ofproto->datapath_id = pick_datapath_id(ofproto);
- VLOG_INFO("using datapath ID %016"PRIx64, ofproto->datapath_id);
init_ports(ofproto);
*ofprotop = ofproto;
}
}
+uint64_t
+ofproto_get_datapath_id(const struct ofproto *ofproto)
+{
+ return ofproto->datapath_id;
+}
+
void
ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
{
uint64_t old_dpid = p->datapath_id;
p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p);
if (p->datapath_id != old_dpid) {
- VLOG_INFO("datapath ID changed to %016"PRIx64, p->datapath_id);
-
/* Force all active connections to reconnect, since there is no way to
* notify a controller that the datapath ID has changed. */
ofproto_reconnect_controllers(p);
if (mfr_desc) {
if (strlen(mfr_desc) >= sizeof ods->mfr_desc) {
- VLOG_WARN("truncating mfr_desc, must be less than %zu characters",
- sizeof ods->mfr_desc);
+ VLOG_WARN("%s: truncating mfr_desc, must be less than %zu bytes",
+ p->name, sizeof ods->mfr_desc);
}
free(p->mfr_desc);
p->mfr_desc = xstrdup(mfr_desc);
}
if (hw_desc) {
if (strlen(hw_desc) >= sizeof ods->hw_desc) {
- VLOG_WARN("truncating hw_desc, must be less than %zu characters",
- sizeof ods->hw_desc);
+ VLOG_WARN("%s: truncating hw_desc, must be less than %zu bytes",
+ p->name, sizeof ods->hw_desc);
}
free(p->hw_desc);
p->hw_desc = xstrdup(hw_desc);
}
if (sw_desc) {
if (strlen(sw_desc) >= sizeof ods->sw_desc) {
- VLOG_WARN("truncating sw_desc, must be less than %zu characters",
- sizeof ods->sw_desc);
+ VLOG_WARN("%s: truncating sw_desc, must be less than %zu bytes",
+ p->name, sizeof ods->sw_desc);
}
free(p->sw_desc);
p->sw_desc = xstrdup(sw_desc);
}
if (serial_desc) {
if (strlen(serial_desc) >= sizeof ods->serial_num) {
- VLOG_WARN("truncating serial_desc, must be less than %zu "
- "characters",
- sizeof ods->serial_num);
+ VLOG_WARN("%s: truncating serial_desc, must be less than %zu "
+ "bytes", p->name, sizeof ods->serial_num);
}
free(p->serial_desc);
p->serial_desc = xstrdup(serial_desc);
}
if (dp_desc) {
if (strlen(dp_desc) >= sizeof ods->dp_desc) {
- VLOG_WARN("truncating dp_desc, must be less than %zu characters",
- sizeof ods->dp_desc);
+ VLOG_WARN("%s: truncating dp_desc, must be less than %zu bytes",
+ p->name, sizeof ods->dp_desc);
}
free(p->dp_desc);
p->dp_desc = xstrdup(dp_desc);
s.length -= 2;
ds_put_char(&s, ')');
- VLOG_INFO("%s", ds_cstr(&s));
+ VLOG_INFO("%s: %s", p->name, ds_cstr(&s));
ds_destroy(&s);
p->n_add = p->n_delete = p->n_modify = 0;
* (0...65535, inclusive) then the flow will be visible to OpenFlow
* controllers; otherwise, it will be hidden.
*
- * The caller retains ownership of 'cls_rule' and 'actions'.
+ * The caller retains ownership of 'cls_rule' and 'ofpacts'.
*
* This is a helper function for in-band control and fail-open. */
void
ofproto_add_flow(struct ofproto *ofproto, const struct cls_rule *cls_rule,
- const union ofp_action *actions, size_t n_actions)
+ const struct ofpact *ofpacts, size_t ofpacts_len)
{
const struct rule *rule;
rule = rule_from_cls_rule(classifier_find_rule_exactly(
&ofproto->tables[0].cls, cls_rule));
- if (!rule || !ofputil_actions_equal(rule->actions, rule->n_actions,
- actions, n_actions)) {
+ if (!rule || !ofpacts_equal(rule->ofpacts, rule->ofpacts_len,
+ ofpacts, ofpacts_len)) {
struct ofputil_flow_mod fm;
memset(&fm, 0, sizeof fm);
fm.cr = *cls_rule;
fm.buffer_id = UINT32_MAX;
- fm.actions = (union ofp_action *) actions;
- fm.n_actions = n_actions;
+ fm.ofpacts = xmemdup(ofpacts, ofpacts_len);
+ fm.ofpacts_len = ofpacts_len;
add_flow(ofproto, NULL, &fm, NULL);
+ free(fm.ofpacts);
}
}
sset_destroy(&devnames);
}
-/* Opens and returns a netdev for 'ofproto_port', or a null pointer if the
- * netdev cannot be opened. On success, also fills in 'opp'. */
+/* Opens and returns a netdev for 'ofproto_port' in 'ofproto', or a null
+ * pointer if the netdev cannot be opened. On success, also fills in
+ * 'opp'. */
static struct netdev *
-ofport_open(const struct ofproto_port *ofproto_port,
+ofport_open(const struct ofproto *ofproto,
+ const struct ofproto_port *ofproto_port,
struct ofputil_phy_port *pp)
{
enum netdev_flags flags;
error = netdev_open(ofproto_port->name, ofproto_port->type, &netdev);
if (error) {
- VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s "
+ VLOG_WARN_RL(&rl, "%s: ignoring port %s (%"PRIu16") because netdev %s "
"cannot be opened (%s)",
+ ofproto->name,
ofproto_port->name, ofproto_port->ofp_port,
ofproto_port->name, strerror(error));
return NULL;
/* Fetch 'name''s location and properties from the datapath. */
netdev = (!ofproto_port_query_by_name(ofproto, name, &ofproto_port)
- ? ofport_open(&ofproto_port, &pp)
+ ? ofport_open(ofproto, &ofproto_port, &pp)
: NULL);
if (netdev) {
port = ofproto_get_port(ofproto, ofproto_port.ofp_port);
OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, p) {
uint16_t ofp_port = ofproto_port.ofp_port;
if (ofproto_get_port(p, ofp_port)) {
- VLOG_WARN_RL(&rl, "ignoring duplicate port %"PRIu16" in datapath",
- ofp_port);
+ VLOG_WARN_RL(&rl, "%s: ignoring duplicate port %"PRIu16" "
+ "in datapath", p->name, ofp_port);
} else if (shash_find(&p->port_by_name, ofproto_port.name)) {
- VLOG_WARN_RL(&rl, "ignoring duplicate device %s in datapath",
- ofproto_port.name);
+ VLOG_WARN_RL(&rl, "%s: ignoring duplicate device %s in datapath",
+ p->name, ofproto_port.name);
} else {
struct ofputil_phy_port pp;
struct netdev *netdev;
- netdev = ofport_open(&ofproto_port, &pp);
+ netdev = ofport_open(p, &ofproto_port, &pp);
if (netdev) {
ofport_install(p, netdev, &pp);
}
ofproto_rule_destroy__(struct rule *rule)
{
if (rule) {
- free(rule->actions);
+ free(rule->ofpacts);
rule->ofproto->ofproto_class->rule_dealloc(rule);
}
}
}
/* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action
- * that outputs to 'out_port' (output to OFPP_FLOOD and OFPP_ALL doesn't
- * count). */
+ * that outputs to 'port' (output to OFPP_FLOOD and OFPP_ALL doesn't count). */
static bool
-rule_has_out_port(const struct rule *rule, uint16_t out_port)
+rule_has_out_port(const struct rule *rule, uint16_t port)
{
- const union ofp_action *oa;
- size_t left;
-
- if (out_port == OFPP_NONE) {
- return true;
- }
- OFPUTIL_ACTION_FOR_EACH_UNSAFE (oa, left, rule->actions, rule->n_actions) {
- if (action_outputs_to_port(oa, htons(out_port))) {
- return true;
- }
- }
- return false;
+ return (port == OFPP_NONE
+ || ofpacts_output_to_port(rule->ofpacts, rule->ofpacts_len, port));
}
/* Executes the actions indicated by 'rule' on 'packet' and credits 'rule''s
struct ofproto *p = ofconn_get_ofproto(ofconn);
struct ofputil_packet_out po;
struct ofpbuf *payload;
+ uint64_t ofpacts_stub[1024 / 8];
+ struct ofpbuf ofpacts;
struct flow flow;
enum ofperr error;
error = reject_slave_controller(ofconn);
if (error) {
- return error;
+ goto exit;
}
/* Decode message. */
- error = ofputil_decode_packet_out(&po, opo);
+ ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+ error = ofputil_decode_packet_out(&po, opo, &ofpacts);
if (error) {
- return error;
+ goto exit_free_ofpacts;
}
/* Get payload. */
if (po.buffer_id != UINT32_MAX) {
error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
if (error || !payload) {
- return error;
+ goto exit_free_ofpacts;
}
} else {
payload = xmalloc(sizeof *payload);
/* Send out packet. */
flow_extract(payload, 0, 0, po.in_port, &flow);
error = p->ofproto_class->packet_out(p, payload, &flow,
- po.actions, po.n_actions);
+ po.ofpacts, po.ofpacts_len);
ofpbuf_delete(payload);
+exit_free_ofpacts:
+ ofpbuf_uninit(&ofpacts);
+exit:
return error;
}
fs.hard_age = age_secs(now - rule->modified);
ofproto->ofproto_class->rule_get_stats(rule, &fs.packet_count,
&fs.byte_count);
- fs.actions = rule->actions;
- fs.n_actions = rule->n_actions;
+ fs.ofpacts = rule->ofpacts;
+ fs.ofpacts_len = rule->ofpacts_len;
ofputil_append_flow_stats_reply(&fs, &replies);
}
ofconn_send_replies(ofconn, &replies);
ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
cls_rule_format(&rule->cr, results);
ds_put_char(results, ',');
- if (rule->n_actions > 0) {
- ofp_print_actions(results, rule->actions, rule->n_actions);
+ if (rule->ofpacts_len > 0) {
+ ofpacts_format(rule->ofpacts, rule->ofpacts_len, results);
} else {
ds_put_cstr(results, "drop");
}
put_queue_stats(cbdata, queue_id, stats);
}
-static void
+static enum ofperr
handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id,
struct queue_stats_cbdata *cbdata)
{
if (!netdev_get_queue_stats(port->netdev, queue_id, &stats)) {
put_queue_stats(cbdata, queue_id, &stats);
+ } else {
+ return OFPERR_OFPQOFC_BAD_QUEUE;
}
}
+ return 0;
}
static enum ofperr
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct queue_stats_cbdata cbdata;
- struct ofport *port;
unsigned int port_no;
+ struct ofport *port;
uint32_t queue_id;
+ enum ofperr error;
COVERAGE_INC(ofproto_queue_req);
port_no = ntohs(qsr->port_no);
queue_id = ntohl(qsr->queue_id);
if (port_no == OFPP_ALL) {
+ error = OFPERR_OFPQOFC_BAD_QUEUE;
HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
- handle_queue_stats_for_port(port, queue_id, &cbdata);
+ if (!handle_queue_stats_for_port(port, queue_id, &cbdata)) {
+ error = 0;
+ }
}
- } else if (port_no < OFPP_MAX) {
+ } else {
port = ofproto_get_port(ofproto, port_no);
- if (port) {
- handle_queue_stats_for_port(port, queue_id, &cbdata);
- }
+ error = (port
+ ? handle_queue_stats_for_port(port, queue_id, &cbdata)
+ : OFPERR_OFPQOFC_BAD_PORT);
+ }
+ if (!error) {
+ ofconn_send_replies(ofconn, &cbdata.replies);
} else {
ofpbuf_list_delete(&cbdata.replies);
- return OFPERR_OFPQOFC_BAD_PORT;
}
- ofconn_send_replies(ofconn, &cbdata.replies);
- return 0;
+ return error;
}
static bool
* error code on failure, or OFPROTO_POSTPONE if the operation cannot be
* initiated now but may be retried later.
*
+ * Upon successful return, takes ownership of 'fm->ofpacts'. On failure,
+ * ownership remains with the caller.
+ *
* 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
* if any. */
static enum ofperr
rule->hard_timeout = fm->hard_timeout;
rule->table_id = table - ofproto->tables;
rule->send_flow_removed = (fm->flags & OFPFF_SEND_FLOW_REM) != 0;
- rule->actions = ofputil_actions_clone(fm->actions, fm->n_actions);
- rule->n_actions = fm->n_actions;
+ rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len);
+ rule->ofpacts_len = fm->ofpacts_len;
rule->evictable = true;
rule->eviction_group = NULL;
continue;
}
- if (!ofputil_actions_equal(fm->actions, fm->n_actions,
- rule->actions, rule->n_actions)) {
+ if (!ofpacts_equal(fm->ofpacts, fm->ofpacts_len,
+ rule->ofpacts, rule->ofpacts_len)) {
ofoperation_create(group, rule, OFOPERATION_MODIFY);
- rule->pending->actions = rule->actions;
- rule->pending->n_actions = rule->n_actions;
- rule->actions = ofputil_actions_clone(fm->actions, fm->n_actions);
- rule->n_actions = fm->n_actions;
- ofproto->ofproto_class->rule_modify_actions(rule);
+ rule->pending->ofpacts = rule->ofpacts;
+ rule->pending->ofpacts_len = rule->ofpacts_len;
+ rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len);
+ rule->ofpacts_len = fm->ofpacts_len;
+ rule->ofproto->ofproto_class->rule_modify_actions(rule);
} else {
rule->modified = time_msec();
}
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct ofputil_flow_mod fm;
+ uint64_t ofpacts_stub[1024 / 8];
+ struct ofpbuf ofpacts;
enum ofperr error;
long long int now;
error = reject_slave_controller(ofconn);
if (error) {
- return error;
+ goto exit;
}
- error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn));
+ ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+ error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
+ &ofpacts);
if (error) {
- return error;
+ goto exit_free_ofpacts;
}
/* We do not support the OpenFlow 1.0 emergency flow cache, which is not
* required in OpenFlow 1.0.1 and removed from OpenFlow 1.1. */
if (fm.flags & OFPFF_EMERG) {
- /* There isn't a good fit for an error code, so just state that the
- * flow table is full. */
- return OFPERR_OFPFMFC_ALL_TABLES_FULL;
+ /* We do not support the emergency flow cache. It will hopefully get
+ * dropped from OpenFlow in the near future. There is no good error
+ * code, so just state that the flow table is full. */
+ error = OFPERR_OFPFMFC_ALL_TABLES_FULL;
+ } else {
+ error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
}
-
- error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
if (error) {
- return error;
+ goto exit_free_ofpacts;
}
/* Record the operation for logging a summary report. */
}
ofproto->last_op = now;
- return 0;
+exit_free_ofpacts:
+ ofpbuf_uninit(&ofpacts);
+exit:
+ return error;
}
static enum ofperr
default:
if (fm->command > 0xff) {
- VLOG_WARN_RL(&rl, "flow_mod has explicit table_id but "
- "flow_mod_table_id extension is not enabled");
+ VLOG_WARN_RL(&rl, "%s: flow_mod has explicit table_id but "
+ "flow_mod_table_id extension is not enabled",
+ ofproto->name);
}
return OFPERR_OFPFMFC_BAD_COMMAND;
}
hmap_remove(&group->ofproto->deletions, &op->hmap_node);
}
list_remove(&op->group_node);
- free(op->actions);
+ free(op->ofpacts);
free(op);
if (list_is_empty(&group->ops) && !list_is_empty(&group->ofproto_node)) {
if (!error) {
rule->modified = time_msec();
} else {
- free(rule->actions);
- rule->actions = op->actions;
- rule->n_actions = op->n_actions;
- op->actions = NULL;
+ free(rule->ofpacts);
+ rule->ofpacts = op->ofpacts;
+ rule->ofpacts_len = op->ofpacts_len;
+ op->ofpacts = NULL;
}
break;
if (!error) {
return eth_addr_to_uint64(ea);
}
- VLOG_WARN("could not get MAC address for %s (%s)",
- netdev_get_name(port->netdev), strerror(error));
+ VLOG_WARN("%s: could not get MAC address for %s (%s)",
+ ofproto->name, netdev_get_name(port->netdev),
+ strerror(error));
}
return ofproto->fallback_dpid;
}