The final flow stats are available only after there are no references
to the rule. Postpone sending the flow removed message until the
final stats are available.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
OFPRR_GROUP_DELETE, /* Group was removed. */
OFPRR_METER_DELETE, /* Meter was removed. */
OFPRR_EVICTION, /* Switch eviction to free resources. */
OFPRR_GROUP_DELETE, /* Group was removed. */
OFPRR_METER_DELETE, /* Meter was removed. */
OFPRR_EVICTION, /* Switch eviction to free resources. */
+
+ OVS_OFPRR_NONE /* OVS internal_use only, keep last!. */
};
/* What changed about the physical port */
};
/* What changed about the physical port */
return "eviction";
case OFPRR_METER_DELETE:
return "meter_delete";
return "eviction";
case OFPRR_METER_DELETE:
return "meter_delete";
default:
snprintf(reasonbuf, bufsize, "%d", (int) reason);
return reasonbuf;
default:
snprintf(reasonbuf, bufsize, "%d", (int) reason);
return reasonbuf;
/* Eviction precedence. */
uint16_t importance OVS_GUARDED;
/* Eviction precedence. */
uint16_t importance OVS_GUARDED;
+ /* Removal reason for sending flow removed message.
+ * Used only if 'flags' has OFPUTIL_FF_SEND_FLOW_REM set and if the
+ * value is not OVS_OFPRR_NONE. */
+ uint8_t removed_reason;
+
/* Eviction groups (see comment on struct eviction_group for explanation) .
*
* 'eviction_group' is this rule's eviction group, or NULL if it is not in
/* Eviction groups (see comment on struct eviction_group for explanation) .
*
* 'eviction_group' is this rule's eviction group, or NULL if it is not in
-static void ofproto_rule_send_removed(struct rule *, uint8_t reason);
+static void ofproto_rule_send_removed(struct rule *)
+ OVS_EXCLUDED(ofproto_mutex);
static bool rule_is_readonly(const struct rule *);
static void ofproto_rule_insert__(struct ofproto *, struct rule *)
OVS_REQUIRES(ofproto_mutex);
static bool rule_is_readonly(const struct rule *);
static void ofproto_rule_insert__(struct ofproto *, struct rule *)
OVS_REQUIRES(ofproto_mutex);
static void
rule_destroy_cb(struct rule *rule)
static void
rule_destroy_cb(struct rule *rule)
+ OVS_NO_THREAD_SAFETY_ANALYSIS
+ /* Send rule removed if needed. */
+ if (rule->flags & OFPUTIL_FF_SEND_FLOW_REM
+ && rule->removed_reason != OVS_OFPRR_NONE
+ && !rule_is_hidden(rule)) {
+ ofproto_rule_send_removed(rule);
+ }
rule->ofproto->ofproto_class->rule_destruct(rule);
ofproto_rule_destroy__(rule);
}
rule->ofproto->ofproto_class->rule_destruct(rule);
ofproto_rule_destroy__(rule);
}
rule->idle_timeout = fm->idle_timeout;
rule->hard_timeout = fm->hard_timeout;
rule->importance = fm->importance;
rule->idle_timeout = fm->idle_timeout;
rule->hard_timeout = fm->hard_timeout;
rule->importance = fm->importance;
+ rule->removed_reason = OVS_OFPRR_NONE;
*CONST_CAST(uint8_t *, &rule->table_id) = table_id;
rule->flags = fm->flags & OFPUTIL_FF_STATE;
*CONST_CAST(uint8_t *, &rule->table_id) = table_id;
rule->flags = fm->flags & OFPUTIL_FF_STATE;
} else {
/* XXX: This is slight duplication with delete_flows_finish__() */
} else {
/* XXX: This is slight duplication with delete_flows_finish__() */
- /* XXX: This call should done when rule's refcount reaches
- * zero to get accurate stats in the flow removed message. */
- ofproto_rule_send_removed(old_rule, OFPRR_EVICTION);
+ old_rule->removed_reason = OFPRR_EVICTION;
ofmonitor_report(ofproto->connmgr, old_rule, NXFME_DELETED,
OFPRR_EVICTION,
ofmonitor_report(ofproto->connmgr, old_rule, NXFME_DELETED,
OFPRR_EVICTION,
for (size_t i = 0; i < rules->n; i++) {
struct rule *rule = rules->rules[i];
for (size_t i = 0; i < rules->n; i++) {
struct rule *rule = rules->rules[i];
- ofproto_rule_send_removed(rule, reason);
+ /* This value will be used to send the flow removed message right
+ * before the rule is actually destroyed. */
+ rule->removed_reason = reason;
+
ofmonitor_report(ofproto->connmgr, rule, NXFME_DELETED, reason,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
ofmonitor_report(ofproto->connmgr, rule, NXFME_DELETED, reason,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
-/* XXX: This should be sent right when the rule refcount gets to zero! */
+/* This may only be called by rule_destroy_cb()! */
-ofproto_rule_send_removed(struct rule *rule, uint8_t reason)
- OVS_REQUIRES(ofproto_mutex)
+ofproto_rule_send_removed(struct rule *rule)
+ OVS_EXCLUDED(ofproto_mutex)
{
struct ofputil_flow_removed fr;
long long int used;
{
struct ofputil_flow_removed fr;
long long int used;
- if (rule_is_hidden(rule) ||
- !(rule->flags & OFPUTIL_FF_SEND_FLOW_REM)) {
- return;
- }
-
minimatch_expand(&rule->cr.match, &fr.match);
fr.priority = rule->cr.priority;
minimatch_expand(&rule->cr.match, &fr.match);
fr.priority = rule->cr.priority;
+
+ ovs_mutex_lock(&ofproto_mutex);
fr.cookie = rule->flow_cookie;
fr.cookie = rule->flow_cookie;
+ fr.reason = rule->removed_reason;
fr.table_id = rule->table_id;
calc_duration(rule->created, time_msec(),
&fr.duration_sec, &fr.duration_nsec);
fr.table_id = rule->table_id;
calc_duration(rule->created, time_msec(),
&fr.duration_sec, &fr.duration_nsec);
ovs_mutex_unlock(&rule->mutex);
rule->ofproto->ofproto_class->rule_get_stats(rule, &fr.packet_count,
&fr.byte_count, &used);
ovs_mutex_unlock(&rule->mutex);
rule->ofproto->ofproto_class->rule_get_stats(rule, &fr.packet_count,
&fr.byte_count, &used);
connmgr_send_flow_removed(rule->ofproto->connmgr, &fr);
connmgr_send_flow_removed(rule->ofproto->connmgr, &fr);
+ ovs_mutex_unlock(&ofproto_mutex);
}
/* Sends an OpenFlow "flow removed" message with the given 'reason' (either
}
/* Sends an OpenFlow "flow removed" message with the given 'reason' (either