/* OpenFlow. */
static enum ofperr add_flow(struct ofproto *, struct ofconn *,
- const struct ofputil_flow_mod *,
+ struct ofputil_flow_mod *,
const struct ofp_header *);
static void delete_flow__(struct rule *, struct ofopgroup *,
enum ofp_flow_removed_reason);
static bool handle_openflow(struct ofconn *, const struct ofpbuf *);
static enum ofperr handle_flow_mod__(struct ofproto *, struct ofconn *,
- const struct ofputil_flow_mod *,
+ struct ofputil_flow_mod *,
const struct ofp_header *);
static void calc_duration(long long int start, long long int now,
uint32_t *sec, uint32_t *nsec);
static uint64_t pick_fallback_dpid(void);
static void ofproto_destroy__(struct ofproto *);
static void update_mtu(struct ofproto *, struct ofport *);
+static void meter_delete(struct ofproto *, uint32_t first, uint32_t last);
/* unixctl. */
static void ofproto_unixctl_init(void);
error = ofproto->ofproto_class->construct(ofproto);
if (error) {
VLOG_ERR("failed to open datapath %s: %s",
- datapath_name, strerror(error));
+ datapath_name, ovs_strerror(error));
ofproto_destroy__(ofproto);
return error;
}
if (error) {
VLOG_WARN("%s: CFM configuration on port %"PRIu16" (%s) failed (%s)",
ofproto->name, ofp_port, netdev_get_name(ofport->netdev),
- strerror(error));
+ ovs_strerror(error));
}
}
if (error) {
VLOG_WARN("%s: bfd configuration on port %"PRIu16" (%s) failed (%s)",
ofproto->name, ofp_port, netdev_get_name(ofport->netdev),
- strerror(error));
+ ovs_strerror(error));
}
}
ovs_assert(list_is_empty(&ofproto->pending));
ovs_assert(!ofproto->n_pending);
+ if (ofproto->meters) {
+ meter_delete(ofproto, 1, ofproto->meter_features.max_meters);
+ free(ofproto->meters);
+ }
+
connmgr_destroy(ofproto->connmgr);
hmap_remove(&all_ofprotos, &ofproto->hmap_node);
error = class->type_run ? class->type_run(datapath_type) : 0;
if (error && error != EAGAIN) {
VLOG_ERR_RL(&rl, "%s: type_run failed (%s)",
- datapath_type, strerror(error));
+ datapath_type, ovs_strerror(error));
}
return error;
}
error = class->type_run_fast ? class->type_run_fast(datapath_type) : 0;
if (error && error != EAGAIN) {
VLOG_ERR_RL(&rl, "%s: type_run_fast failed (%s)",
- datapath_type, strerror(error));
+ datapath_type, ovs_strerror(error));
}
return error;
}
error = p->ofproto_class->run(p);
if (error && error != EAGAIN) {
- VLOG_ERR_RL(&rl, "%s: run failed (%s)", p->name, strerror(error));
+ VLOG_ERR_RL(&rl, "%s: run failed (%s)", p->name, ovs_strerror(error));
}
if (p->ofproto_class->port_poll) {
error = p->ofproto_class->run_fast ? p->ofproto_class->run_fast(p) : 0;
if (error && error != EAGAIN) {
VLOG_ERR_RL(&rl, "%s: fastpath run failed (%s)",
- p->name, strerror(error));
+ p->name, ovs_strerror(error));
}
return error;
}
*
* This is a helper function for in-band control and fail-open. */
int
-ofproto_flow_mod(struct ofproto *ofproto, const struct ofputil_flow_mod *fm)
+ofproto_flow_mod(struct ofproto *ofproto, struct ofputil_flow_mod *fm)
{
return handle_flow_mod__(ofproto, NULL, fm, NULL);
}
"cannot be opened (%s)",
ofproto->name,
ofproto_port->name, ofproto_port->ofp_port,
- ofproto_port->name, strerror(error));
+ ofproto_port->name, ovs_strerror(error));
return NULL;
}
error:
VLOG_WARN_RL(&rl, "%s: could not add port %s (%s)",
- p->name, netdev_name, strerror(error));
+ p->name, netdev_name, ovs_strerror(error));
if (ofport) {
ofport_destroy__(ofport);
} else {
return 0;
}
-/* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are
- * appropriate for a packet with the prerequisites satisfied by 'flow'.
+/* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are appropriate
+ * for a packet with the prerequisites satisfied by 'flow' in table 'table_id'.
* 'flow' may be temporarily modified, but is restored at return.
*/
static enum ofperr
ofproto_check_ofpacts(struct ofproto *ofproto,
const struct ofpact ofpacts[], size_t ofpacts_len,
- struct flow *flow)
+ struct flow *flow, uint8_t table_id)
{
enum ofperr error;
uint32_t mid;
- error = ofpacts_check(ofpacts, ofpacts_len, flow, ofproto->max_ports);
+ error = ofpacts_check(ofpacts, ofpacts_len, flow, ofproto->max_ports,
+ table_id);
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);
+ error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0);
if (!error) {
error = p->ofproto_class->packet_out(p, payload, &flow,
po.ofpacts, po.ofpacts_len);
* Returns false if the port did not have CFM configured, in which case
* '*status' is indeterminate.
*
- * The caller must provide and owns '*status', but it does not own and must not
- * modify or free the array returned in 'status->rmps'. */
+ * The caller must provide and owns '*status', and must free 'status->rmps'. */
bool
ofproto_port_get_cfm_status(const struct ofproto *ofproto, ofp_port_t ofp_port,
struct ofproto_cfm_status *status)
struct queue_stats_cbdata {
struct ofport *ofport;
struct list replies;
+ long long int now;
};
static void
put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
const struct netdev_queue_stats *stats)
{
+ struct ofputil_queue_stats oqs;
- struct ofputil_queue_stats oqs = {
- .port_no = cbdata->ofport->pp.port_no,
- .queue_id = queue_id,
- .stats = *stats,
- };
+ oqs.port_no = cbdata->ofport->pp.port_no;
+ oqs.queue_id = queue_id;
+ oqs.tx_bytes = stats->tx_bytes;
+ oqs.tx_packets = stats->tx_packets;
+ oqs.tx_errors = stats->tx_errors;
+ if (stats->created != LLONG_MIN) {
+ calc_duration(stats->created, cbdata->now,
+ &oqs.duration_sec, &oqs.duration_nsec);
+ } else {
+ oqs.duration_sec = oqs.duration_nsec = UINT32_MAX;
+ }
ofputil_append_queue_stat(&cbdata->replies, &oqs);
}
COVERAGE_INC(ofproto_queue_req);
ofpmp_init(&cbdata.replies, rq);
+ cbdata.now = time_msec();
error = ofputil_decode_queue_stats_request(rq, &oqsr);
if (error) {
* if any. */
static enum ofperr
add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
- const struct ofputil_flow_mod *fm, const struct ofp_header *request)
+ struct ofputil_flow_mod *fm, const struct ofp_header *request)
{
struct oftable *table;
struct ofopgroup *group;
return OFPERR_OFPBRC_EPERM;
}
+ /* Verify actions. */
+ error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
+ &fm->match.flow, table_id);
+ if (error) {
+ return error;
+ }
+
/* Allocate new rule and initialize classifier rule. */
rule = ofproto->ofproto_class->rule_alloc();
if (!rule) {
VLOG_WARN_RL(&rl, "%s: failed to create rule (%s)",
- ofproto->name, strerror(error));
+ ofproto->name, ovs_strerror(error));
return ENOMEM;
}
cls_rule_init(&rule->cr, &fm->match, fm->priority);
* Returns 0 on success, otherwise an OpenFlow error code. */
static enum ofperr
modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
- const struct ofputil_flow_mod *fm,
- const struct ofp_header *request,
+ struct ofputil_flow_mod *fm, const struct ofp_header *request,
struct list *rules)
{
struct ofopgroup *group;
continue;
}
+ /* Verify actions. */
+ error = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
+ ofproto->max_ports, rule->table_id);
+ if (error) {
+ return error;
+ }
+
actions_changed = !ofpacts_equal(fm->ofpacts, fm->ofpacts_len,
rule->ofpacts, rule->ofpacts_len);
op = ofoperation_create(group, rule, OFOPERATION_MODIFY, 0);
- if (fm->new_cookie != htonll(UINT64_MAX)) {
+ if (fm->modify_cookie && fm->new_cookie != htonll(UINT64_MAX)) {
ofproto_rule_change_cookie(ofproto, rule, fm->new_cookie);
}
if (actions_changed) {
static enum ofperr
modify_flows_add(struct ofproto *ofproto, struct ofconn *ofconn,
- const struct ofputil_flow_mod *fm,
- const struct ofp_header *request)
+ struct ofputil_flow_mod *fm, const struct ofp_header *request)
{
if (fm->cookie_mask != htonll(0) || fm->new_cookie == htonll(UINT64_MAX)) {
return 0;
* if any. */
static enum ofperr
modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
- const struct ofputil_flow_mod *fm,
+ struct ofputil_flow_mod *fm,
const struct ofp_header *request)
{
struct list rules;
* if any. */
static enum ofperr
modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
- const struct ofputil_flow_mod *fm,
+ struct ofputil_flow_mod *fm,
const struct ofp_header *request)
{
struct list rules;
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
&ofpacts);
- if (!error) {
- error = ofproto_check_ofpacts(ofproto, fm.ofpacts, fm.ofpacts_len,
- &fm.match.flow);
- }
-
if (!error) {
error = handle_flow_mod__(ofproto, ofconn, &fm, oh);
}
static enum ofperr
handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
- const struct ofputil_flow_mod *fm,
- const struct ofp_header *oh)
+ struct ofputil_flow_mod *fm, const struct ofp_header *oh)
{
if (ofproto->n_pending >= 50) {
ovs_assert(!list_is_empty(&ofproto->pending));
return meter;
}
+static void
+meter_delete(struct ofproto *ofproto, uint32_t first, uint32_t last)
+{
+ uint32_t mid;
+ for (mid = first; mid <= last; ++mid) {
+ struct meter *meter = ofproto->meters[mid];
+ if (meter) {
+ ofproto->meters[mid] = NULL;
+ ofproto->ofproto_class->meter_del(ofproto,
+ meter->provider_meter_id);
+ free(meter->bands);
+ free(meter);
+ }
+ }
+}
+
static enum ofperr
handle_add_meter(struct ofproto *ofproto, struct ofputil_meter_mod *mm)
{
}
/* Delete the meters. */
- for (meter_id = first; meter_id <= last; ++meter_id) {
- struct meter *meter = ofproto->meters[meter_id];
- if (meter) {
- ofproto->meters[meter_id] = NULL;
- ofproto->ofproto_class->meter_del(ofproto,
- meter->provider_meter_id);
- free(meter->bands);
- free(meter);
- }
- }
+ meter_delete(ofproto, first, last);
return 0;
}
if (!meter) {
continue; /* Skip non-existing meters. */
}
- if (type == OFPTYPE_METER_REQUEST) {
+ if (type == OFPTYPE_METER_STATS_REQUEST) {
struct ofputil_meter_stats stats;
stats.meter_id = meter_id;
case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
return handle_flow_monitor_request(ofconn, oh);
- case OFPTYPE_METER_REQUEST:
- case OFPTYPE_METER_CONFIG_REQUEST:
+ case OFPTYPE_METER_STATS_REQUEST:
+ case OFPTYPE_METER_CONFIG_STATS_REQUEST:
return handle_meter_request(ofconn, oh, type);
- case OFPTYPE_METER_FEATURES_REQUEST:
+ case OFPTYPE_METER_FEATURES_STATS_REQUEST:
return handle_meter_features_request(ofconn, oh);
/* FIXME: Change the following once they are implemented: */
case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
case OFPTYPE_GET_ASYNC_REQUEST:
- case OFPTYPE_GROUP_REQUEST:
- case OFPTYPE_GROUP_DESC_REQUEST:
- case OFPTYPE_GROUP_FEATURES_REQUEST:
- case OFPTYPE_TABLE_FEATURES_REQUEST:
+ case OFPTYPE_GROUP_STATS_REQUEST:
+ case OFPTYPE_GROUP_DESC_STATS_REQUEST:
+ case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
+ case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
return OFPERR_OFPBRC_BAD_TYPE;
case OFPTYPE_HELLO:
case OFPTYPE_FLOW_MONITOR_RESUMED:
case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
case OFPTYPE_GET_ASYNC_REPLY:
- case OFPTYPE_GROUP_REPLY:
- case OFPTYPE_GROUP_DESC_REPLY:
- case OFPTYPE_GROUP_FEATURES_REPLY:
- case OFPTYPE_METER_REPLY:
- case OFPTYPE_METER_CONFIG_REPLY:
- case OFPTYPE_METER_FEATURES_REPLY:
- case OFPTYPE_TABLE_FEATURES_REPLY:
+ case OFPTYPE_GROUP_STATS_REPLY:
+ case OFPTYPE_GROUP_DESC_STATS_REPLY:
+ case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
+ case OFPTYPE_METER_STATS_REPLY:
+ case OFPTYPE_METER_CONFIG_STATS_REPLY:
+ case OFPTYPE_METER_FEATURES_STATS_REPLY:
+ case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
default:
return OFPERR_OFPBRC_BAD_TYPE;
}
}
VLOG_WARN("%s: could not get MAC address for %s (%s)",
ofproto->name, netdev_get_name(port->netdev),
- strerror(error));
+ ovs_strerror(error));
}
return ofproto->fallback_dpid;
}
if (error) {
VLOG_WARN("%s: setting realdev on port %"PRIu16" (%s) failed (%s)",
ofproto->name, vlandev_ofp_port,
- netdev_get_name(ofport->netdev), strerror(error));
+ netdev_get_name(ofport->netdev), ovs_strerror(error));
}
return error;
}