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);
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);
if (rule) {
cls_rule_destroy(&rule->cr);
free(rule->ofpacts);
+ ovs_mutex_destroy(&rule->timeout_mutex);
rule->ofproto->ofproto_class->rule_dealloc(rule);
}
}
fs.cookie = rule->flow_cookie;
fs.table_id = rule->table_id;
calc_duration(rule->created, now, &fs.duration_sec, &fs.duration_nsec);
- fs.idle_timeout = rule->idle_timeout;
- fs.hard_timeout = rule->hard_timeout;
fs.idle_age = age_secs(now - rule->used);
fs.hard_age = age_secs(now - rule->modified);
ofproto->ofproto_class->rule_get_stats(rule, &fs.packet_count,
fs.ofpacts = rule->ofpacts;
fs.ofpacts_len = rule->ofpacts_len;
fs.flags = 0;
+
+ ovs_mutex_lock(&rule->timeout_mutex);
+ fs.idle_timeout = rule->idle_timeout;
+ fs.hard_timeout = rule->hard_timeout;
+ ovs_mutex_unlock(&rule->timeout_mutex);
+
if (rule->send_flow_removed) {
fs.flags |= OFPFF_SEND_FLOW_REM;
/* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
* 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) {
rule->pending = NULL;
rule->flow_cookie = fm->new_cookie;
rule->created = rule->modified = rule->used = time_msec();
+
+ ovs_mutex_init(&rule->timeout_mutex, OVS_MUTEX_ADAPTIVE);
+ ovs_mutex_lock(&rule->timeout_mutex);
rule->idle_timeout = fm->idle_timeout;
rule->hard_timeout = fm->hard_timeout;
+ ovs_mutex_unlock(&rule->timeout_mutex);
+
rule->table_id = table - ofproto->tables;
rule->send_flow_removed = (fm->flags & OFPFF_SEND_FLOW_REM) != 0;
/* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
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) {
fr.table_id = rule->table_id;
calc_duration(rule->created, time_msec(),
&fr.duration_sec, &fr.duration_nsec);
+ ovs_mutex_lock(&rule->timeout_mutex);
fr.idle_timeout = rule->idle_timeout;
fr.hard_timeout = rule->hard_timeout;
+ ovs_mutex_unlock(&rule->timeout_mutex);
rule->ofproto->ofproto_class->rule_get_stats(rule, &fr.packet_count,
&fr.byte_count);
fu.event = (flags & (NXFMF_INITIAL | NXFMF_ADD)
? NXFME_ADDED : NXFME_MODIFIED);
fu.reason = 0;
+ ovs_mutex_lock(&rule->timeout_mutex);
fu.idle_timeout = rule->idle_timeout;
fu.hard_timeout = rule->hard_timeout;
+ ovs_mutex_unlock(&rule->timeout_mutex);
fu.table_id = rule->table_id;
fu.cookie = rule->flow_cookie;
minimatch_expand(&rule->cr.match, &match);
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;
}
uint32_t expiration_offset;
/* Calculate time of expiration. */
+ ovs_mutex_lock(&rule->timeout_mutex);
hard_expiration = (rule->hard_timeout
? rule->modified + rule->hard_timeout * 1000
: LLONG_MAX);
? rule->used + rule->idle_timeout * 1000
: LLONG_MAX);
expiration = MIN(hard_expiration, idle_expiration);
+ ovs_mutex_unlock(&rule->timeout_mutex);
if (expiration == LLONG_MAX) {
return 0;
}
{
struct ofproto *ofproto = rule->ofproto;
struct oftable *table = &ofproto->tables[rule->table_id];
+ bool has_timeout;
- if (table->eviction_fields
- && (rule->hard_timeout || rule->idle_timeout)) {
+ ovs_mutex_lock(&rule->timeout_mutex);
+ has_timeout = rule->hard_timeout || rule->idle_timeout;
+ ovs_mutex_unlock(&rule->timeout_mutex);
+
+ if (table->eviction_fields && has_timeout) {
struct eviction_group *evg;
evg = eviction_group_find(table, eviction_group_hash_rule(rule));
struct ofproto *ofproto = rule->ofproto;
struct oftable *table = &ofproto->tables[rule->table_id];
struct rule *victim;
- bool may_expire = rule->hard_timeout || rule->idle_timeout;
+ bool may_expire;
+
+ ovs_mutex_lock(&rule->timeout_mutex);
+ may_expire = rule->hard_timeout || rule->idle_timeout;
+ ovs_mutex_unlock(&rule->timeout_mutex);
if (may_expire) {
list_insert(&ofproto->expirable, &rule->expirable);