mirror of
https://github.com/openvswitch/ovs
synced 2025-09-02 07:15:17 +00:00
ofproto: Add global locking around flow table changes.
This makes 'ofproto_mutex' protect the flow table well enough that threads other than the main one can realistically modify flows. I need to look at the interface between ofproto and connmgr: I think that there might need to be some locking there too. Signed-off-by: Ben Pfaff <blp@nicira.com> Acked-by: Ethan Jackson <ethan@nicira.com>
This commit is contained in:
@@ -46,12 +46,15 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Needed only for the lock annotation in struct classifier. */
|
||||
extern struct ovs_mutex ofproto_mutex;
|
||||
|
||||
/* A flow classifier. */
|
||||
struct classifier {
|
||||
int n_rules; /* Total number of rules. */
|
||||
struct hmap tables; /* Contains "struct cls_table"s. */
|
||||
struct list tables_priority; /* Tables in descending priority order */
|
||||
struct ovs_rwlock rwlock;
|
||||
struct ovs_rwlock rwlock OVS_ACQ_AFTER(ofproto_mutex);
|
||||
};
|
||||
|
||||
/* A set of rules that all have the same fields wildcarded. */
|
||||
|
@@ -271,6 +271,7 @@ void
|
||||
connmgr_run(struct connmgr *mgr,
|
||||
bool (*handle_openflow)(struct ofconn *,
|
||||
const struct ofpbuf *ofp_msg))
|
||||
OVS_EXCLUDED(ofproto_mutex)
|
||||
{
|
||||
struct ofconn *ofconn, *next_ofconn;
|
||||
struct ofservice *ofservice;
|
||||
@@ -1667,6 +1668,7 @@ connmgr_has_in_band(struct connmgr *mgr)
|
||||
* In-band control has more sophisticated code that manages flows itself. */
|
||||
void
|
||||
connmgr_flushed(struct connmgr *mgr)
|
||||
OVS_EXCLUDED(ofproto_mutex)
|
||||
{
|
||||
if (mgr->fail_open) {
|
||||
fail_open_flushed(mgr->fail_open);
|
||||
@@ -1833,6 +1835,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
|
||||
enum nx_flow_update_event event,
|
||||
enum ofp_flow_removed_reason reason,
|
||||
const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid)
|
||||
OVS_REQUIRES(ofproto_mutex)
|
||||
{
|
||||
enum nx_flow_monitor_flags update;
|
||||
struct ofconn *ofconn;
|
||||
|
@@ -187,7 +187,8 @@ void ofmonitor_destroy(struct ofmonitor *);
|
||||
|
||||
void ofmonitor_report(struct connmgr *, struct rule *,
|
||||
enum nx_flow_update_event, enum ofp_flow_removed_reason,
|
||||
const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid);
|
||||
const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid)
|
||||
OVS_REQUIRES(ofproto_mutex);
|
||||
void ofmonitor_flush(struct connmgr *);
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
|
||||
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -211,6 +211,7 @@ fail_open_wait(struct fail_open *fo)
|
||||
|
||||
void
|
||||
fail_open_flushed(struct fail_open *fo)
|
||||
OVS_EXCLUDED(ofproto_mutex)
|
||||
{
|
||||
int disconn_secs = connmgr_failure_duration(fo->connmgr);
|
||||
bool open = disconn_secs >= trigger_duration(fo);
|
||||
|
@@ -1419,12 +1419,12 @@ destruct(struct ofproto *ofproto_)
|
||||
OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
|
||||
struct cls_cursor cursor;
|
||||
|
||||
ovs_rwlock_wrlock(&table->cls.rwlock);
|
||||
ovs_rwlock_rdlock(&table->cls.rwlock);
|
||||
cls_cursor_init(&cursor, &table->cls, NULL);
|
||||
ovs_rwlock_unlock(&table->cls.rwlock);
|
||||
CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
|
||||
ofproto_rule_delete(&ofproto->up, &table->cls, &rule->up);
|
||||
}
|
||||
ovs_rwlock_unlock(&table->cls.rwlock);
|
||||
}
|
||||
|
||||
guarded_list_pop_all(&ofproto->flow_mods, &flow_mods);
|
||||
@@ -3587,7 +3587,7 @@ handle_upcalls(struct dpif_backer *backer)
|
||||
|
||||
static int subfacet_max_idle(const struct dpif_backer *);
|
||||
static void update_stats(struct dpif_backer *);
|
||||
static void rule_expire(struct rule_dpif *);
|
||||
static void rule_expire(struct rule_dpif *) OVS_REQUIRES(ofproto_mutex);
|
||||
static void expire_subfacets(struct dpif_backer *, int dp_max_idle);
|
||||
|
||||
/* This function is called periodically by run(). Its job is to collect
|
||||
@@ -3907,30 +3907,31 @@ expire_subfacets(struct dpif_backer *backer, int dp_max_idle)
|
||||
* then delete it entirely. */
|
||||
static void
|
||||
rule_expire(struct rule_dpif *rule)
|
||||
OVS_REQUIRES(ofproto_mutex)
|
||||
{
|
||||
uint16_t idle_timeout, hard_timeout;
|
||||
long long int now;
|
||||
uint8_t reason;
|
||||
long long int now = time_msec();
|
||||
int reason;
|
||||
|
||||
ovs_assert(!rule->up.pending);
|
||||
|
||||
/* Has 'rule' expired? */
|
||||
ovs_mutex_lock(&rule->up.mutex);
|
||||
hard_timeout = rule->up.hard_timeout;
|
||||
idle_timeout = rule->up.idle_timeout;
|
||||
ovs_mutex_unlock(&rule->up.mutex);
|
||||
|
||||
/* Has 'rule' expired? */
|
||||
now = time_msec();
|
||||
if (hard_timeout && now > rule->up.modified + hard_timeout * 1000) {
|
||||
reason = OFPRR_HARD_TIMEOUT;
|
||||
} else if (idle_timeout && now > rule->up.used + idle_timeout * 1000) {
|
||||
reason = OFPRR_IDLE_TIMEOUT;
|
||||
} else {
|
||||
return;
|
||||
reason = -1;
|
||||
}
|
||||
ovs_mutex_unlock(&rule->up.mutex);
|
||||
|
||||
COVERAGE_INC(ofproto_dpif_expired);
|
||||
ofproto_rule_expire(&rule->up, reason);
|
||||
if (reason >= 0) {
|
||||
COVERAGE_INC(ofproto_dpif_expired);
|
||||
ofproto_rule_expire(&rule->up, reason);
|
||||
}
|
||||
}
|
||||
|
||||
/* Facets. */
|
||||
@@ -4122,17 +4123,21 @@ facet_is_controller_flow(struct facet *facet)
|
||||
if (facet) {
|
||||
struct ofproto_dpif *ofproto = facet->ofproto;
|
||||
const struct ofpact *ofpacts;
|
||||
struct rule_actions *actions;
|
||||
struct rule_dpif *rule;
|
||||
size_t ofpacts_len;
|
||||
bool is_controller;
|
||||
|
||||
rule_dpif_lookup(ofproto, &facet->flow, NULL, &rule);
|
||||
ofpacts_len = rule->up.actions->ofpacts_len;
|
||||
ofpacts = rule->up.actions->ofpacts;
|
||||
actions = rule_dpif_get_actions(rule);
|
||||
rule_dpif_unref(rule);
|
||||
|
||||
ofpacts_len = actions->ofpacts_len;
|
||||
ofpacts = actions->ofpacts;
|
||||
is_controller = ofpacts_len > 0
|
||||
&& ofpacts->type == OFPACT_CONTROLLER
|
||||
&& ofpact_next(ofpacts) >= ofpact_end(ofpacts, ofpacts_len);
|
||||
rule_dpif_unref(rule);
|
||||
rule_actions_unref(actions);
|
||||
|
||||
return is_controller;
|
||||
}
|
||||
@@ -4354,7 +4359,10 @@ facet_revalidate(struct facet *facet)
|
||||
facet->xout.nf_output_iface = xout.nf_output_iface;
|
||||
facet->xout.mirrors = xout.mirrors;
|
||||
facet->nf_flow.output_iface = facet->xout.nf_output_iface;
|
||||
|
||||
ovs_mutex_lock(&new_rule->up.mutex);
|
||||
facet->used = MAX(facet->used, new_rule->up.created);
|
||||
ovs_mutex_unlock(&new_rule->up.mutex);
|
||||
|
||||
xlate_out_uninit(&xout);
|
||||
rule_dpif_unref(new_rule);
|
||||
@@ -4474,6 +4482,7 @@ rule_dpif_fail_open(const struct rule_dpif *rule)
|
||||
|
||||
ovs_be64
|
||||
rule_dpif_get_flow_cookie(const struct rule_dpif *rule)
|
||||
OVS_REQUIRES(rule->up.mutex)
|
||||
{
|
||||
return rule->up.flow_cookie;
|
||||
}
|
||||
@@ -4491,14 +4500,7 @@ rule_dpif_reduce_timeouts(struct rule_dpif *rule, uint16_t idle_timeout,
|
||||
struct rule_actions *
|
||||
rule_dpif_get_actions(const struct rule_dpif *rule)
|
||||
{
|
||||
struct rule_actions *actions;
|
||||
|
||||
ovs_mutex_lock(&rule->up.mutex);
|
||||
actions = rule->up.actions;
|
||||
rule_actions_ref(actions);
|
||||
ovs_mutex_unlock(&rule->up.mutex);
|
||||
|
||||
return actions;
|
||||
return rule_get_actions(&rule->up);
|
||||
}
|
||||
|
||||
/* Subfacets. */
|
||||
@@ -4845,6 +4847,7 @@ rule_dpif_unref(struct rule_dpif *rule)
|
||||
|
||||
static void
|
||||
complete_operation(struct rule_dpif *rule)
|
||||
OVS_REQUIRES(ofproto_mutex)
|
||||
{
|
||||
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
|
||||
|
||||
@@ -4885,6 +4888,7 @@ rule_construct(struct rule *rule_)
|
||||
|
||||
static void
|
||||
rule_insert(struct rule *rule_)
|
||||
OVS_REQUIRES(ofproto_mutex)
|
||||
{
|
||||
struct rule_dpif *rule = rule_dpif_cast(rule_);
|
||||
complete_operation(rule);
|
||||
@@ -4892,6 +4896,7 @@ rule_insert(struct rule *rule_)
|
||||
|
||||
static void
|
||||
rule_delete(struct rule *rule_)
|
||||
OVS_REQUIRES(ofproto_mutex)
|
||||
{
|
||||
struct rule_dpif *rule = rule_dpif_cast(rule_);
|
||||
complete_operation(rule);
|
||||
@@ -4956,6 +4961,7 @@ rule_execute(struct rule *rule, const struct flow *flow,
|
||||
|
||||
static void
|
||||
rule_modify_actions(struct rule *rule_, bool reset_counters)
|
||||
OVS_REQUIRES(ofproto_mutex)
|
||||
{
|
||||
struct rule_dpif *rule = rule_dpif_cast(rule_);
|
||||
|
||||
@@ -5270,22 +5276,32 @@ struct trace_ctx {
|
||||
static void
|
||||
trace_format_rule(struct ds *result, int level, const struct rule_dpif *rule)
|
||||
{
|
||||
struct rule_actions *actions;
|
||||
ovs_be64 cookie;
|
||||
|
||||
ds_put_char_multiple(result, '\t', level);
|
||||
if (!rule) {
|
||||
ds_put_cstr(result, "No match\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ovs_mutex_lock(&rule->up.mutex);
|
||||
cookie = rule->up.flow_cookie;
|
||||
ovs_mutex_unlock(&rule->up.mutex);
|
||||
|
||||
ds_put_format(result, "Rule: table=%"PRIu8" cookie=%#"PRIx64" ",
|
||||
rule ? rule->up.table_id : 0, ntohll(rule->up.flow_cookie));
|
||||
rule ? rule->up.table_id : 0, ntohll(cookie));
|
||||
cls_rule_format(&rule->up.cr, result);
|
||||
ds_put_char(result, '\n');
|
||||
|
||||
actions = rule_dpif_get_actions(rule);
|
||||
|
||||
ds_put_char_multiple(result, '\t', level);
|
||||
ds_put_cstr(result, "OpenFlow ");
|
||||
ofpacts_format(rule->up.actions->ofpacts, rule->up.actions->ofpacts_len,
|
||||
result);
|
||||
ofpacts_format(actions->ofpacts, actions->ofpacts_len, result);
|
||||
ds_put_char(result, '\n');
|
||||
|
||||
rule_actions_unref(actions);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -17,7 +17,21 @@
|
||||
#ifndef OFPROTO_OFPROTO_PROVIDER_H
|
||||
#define OFPROTO_OFPROTO_PROVIDER_H 1
|
||||
|
||||
/* Definitions for use within ofproto. */
|
||||
/* Definitions for use within ofproto.
|
||||
*
|
||||
*
|
||||
* Thread-safety
|
||||
* =============
|
||||
*
|
||||
* Lots of ofproto data structures are only accessed from a single thread.
|
||||
* Those data structures are generally not thread-safe.
|
||||
*
|
||||
* The ofproto-dpif ofproto implementation accesses the flow table from
|
||||
* multiple threads, including modifying the flow table from multiple threads
|
||||
* via the "learn" action, so the flow table and various structures that index
|
||||
* it have been made thread-safe. Refer to comments on individual data
|
||||
* structures for details.
|
||||
*/
|
||||
|
||||
#include "cfm.h"
|
||||
#include "classifier.h"
|
||||
@@ -93,11 +107,21 @@ struct ofproto {
|
||||
/* OpenFlow connections. */
|
||||
struct connmgr *connmgr;
|
||||
|
||||
/* Flow table operation tracking. */
|
||||
int state; /* Internal state. */
|
||||
struct list pending; /* List of "struct ofopgroup"s. */
|
||||
unsigned int n_pending; /* list_size(&pending). */
|
||||
struct hmap deletions; /* All OFOPERATION_DELETE "ofoperation"s. */
|
||||
/* Flow table operation tracking.
|
||||
*
|
||||
* 'state' is meaningful only within ofproto.c, one of the enum
|
||||
* ofproto_state constants defined there.
|
||||
*
|
||||
* 'pending' is the list of "struct ofopgroup"s currently pending.
|
||||
*
|
||||
* 'n_pending' is the number of elements in 'pending'.
|
||||
*
|
||||
* 'deletions' contains pending ofoperations of type OFOPERATION_DELETE,
|
||||
* indexed on its rule's flow.*/
|
||||
int state;
|
||||
struct list pending OVS_GUARDED_BY(ofproto_mutex);
|
||||
unsigned int n_pending OVS_GUARDED_BY(ofproto_mutex);
|
||||
struct hmap deletions OVS_GUARDED_BY(ofproto_mutex);
|
||||
|
||||
/* Delayed rule executions.
|
||||
*
|
||||
@@ -105,7 +129,7 @@ struct ofproto {
|
||||
* ofproto_mutex during a flow_mod, because otherwise a "learn" action
|
||||
* triggered by the executing the packet would try to recursively modify
|
||||
* the flow table and reacquire the global lock. */
|
||||
struct guarded_list rule_executes;
|
||||
struct guarded_list rule_executes; /* Contains "struct rule_execute"s. */
|
||||
|
||||
/* Flow table operation logging. */
|
||||
int n_add, n_delete, n_modify; /* Number of unreported ops of each kind. */
|
||||
@@ -181,7 +205,29 @@ enum oftable_flags {
|
||||
OFTABLE_READONLY = 1 << 1 /* Don't allow OpenFlow to change this table. */
|
||||
};
|
||||
|
||||
/* A flow table within a "struct ofproto". */
|
||||
/* A flow table within a "struct ofproto".
|
||||
*
|
||||
*
|
||||
* Thread-safety
|
||||
* =============
|
||||
*
|
||||
* A cls->rwlock read-lock holder prevents rules from being added or deleted.
|
||||
*
|
||||
* Adding or removing rules requires holding ofproto_mutex AND the cls->rwlock
|
||||
* write-lock.
|
||||
*
|
||||
* cls->rwlock should be held only briefly. For extended access to a rule,
|
||||
* increment its ref_count with ofproto_rule_ref(). A rule will not be freed
|
||||
* until its ref_count reaches zero.
|
||||
*
|
||||
* Modifying a rule requires the rule's own mutex. Holding cls->rwlock (for
|
||||
* read or write) does not allow the holder to modify the rule.
|
||||
*
|
||||
* Freeing a rule requires ofproto_mutex and the cls->rwlock write-lock. After
|
||||
* removing the rule from the classifier, release a ref_count from the rule
|
||||
* ('cls''s reference to the rule).
|
||||
*
|
||||
* Refer to the thread-safety notes on struct rule for more information.*/
|
||||
struct oftable {
|
||||
enum oftable_flags flags;
|
||||
struct classifier cls; /* Contains "struct rule"s. */
|
||||
@@ -225,7 +271,59 @@ struct oftable {
|
||||
/* An OpenFlow flow within a "struct ofproto".
|
||||
*
|
||||
* With few exceptions, ofproto implementations may look at these fields but
|
||||
* should not modify them. */
|
||||
* should not modify them.
|
||||
*
|
||||
*
|
||||
* Thread-safety
|
||||
* =============
|
||||
*
|
||||
* Except near the beginning or ending of its lifespan, rule 'rule' belongs to
|
||||
* the classifier rule->ofproto->tables[rule->table_id].cls. The text below
|
||||
* calls this classifier 'cls'.
|
||||
*
|
||||
* Motivation
|
||||
* ----------
|
||||
*
|
||||
* The thread safety rules described here for "struct rule" are motivated by
|
||||
* two goals:
|
||||
*
|
||||
* - Prevent threads that read members of "struct rule" from reading bad
|
||||
* data due to changes by some thread concurrently modifying those
|
||||
* members.
|
||||
*
|
||||
* - Prevent two threads making changes to members of a given "struct rule"
|
||||
* from interfering with each other.
|
||||
*
|
||||
*
|
||||
* Rules
|
||||
* -----
|
||||
*
|
||||
* A rule 'rule' may be accessed without a risk of being freed by code that
|
||||
* holds a read-lock or write-lock on 'cls->rwlock' or that owns a reference to
|
||||
* 'rule->ref_count' (or both). Code that needs to hold onto a rule for a
|
||||
* while should take 'cls->rwlock', find the rule it needs, increment
|
||||
* 'rule->ref_count' with ofproto_rule_ref(), and drop 'cls->rwlock'.
|
||||
*
|
||||
* 'rule->ref_count' protects 'rule' from being freed. It doesn't protect the
|
||||
* rule from being deleted from 'cls' (that's 'cls->rwlock') and it doesn't
|
||||
* protect members of 'rule' from modification (that's 'rule->rwlock').
|
||||
*
|
||||
* 'rule->mutex' protects the members of 'rule' from modification. It doesn't
|
||||
* protect the rule from being deleted from 'cls' (that's 'cls->rwlock') and it
|
||||
* doesn't prevent the rule from being freed (that's 'rule->ref_count').
|
||||
*
|
||||
* Regarding thread safety, the members of a rule fall into the following
|
||||
* categories:
|
||||
*
|
||||
* - Immutable. These members are marked 'const'.
|
||||
*
|
||||
* - Members that may be safely read or written only by code holding
|
||||
* ofproto_mutex. These are marked OVS_GUARDED_BY(ofproto_mutex).
|
||||
*
|
||||
* - Members that may be safely read only by code holding ofproto_mutex or
|
||||
* 'rule->mutex', and safely written only by coding holding ofproto_mutex
|
||||
* AND 'rule->mutex'. These are marked OVS_GUARDED.
|
||||
*/
|
||||
struct rule {
|
||||
/* Where this rule resides in an OpenFlow switch.
|
||||
*
|
||||
@@ -234,48 +332,58 @@ struct rule {
|
||||
const struct cls_rule cr; /* In owning ofproto's classifier. */
|
||||
const uint8_t table_id; /* Index in ofproto's 'tables' array. */
|
||||
|
||||
/* Protects members marked OVS_GUARDED.
|
||||
* Readers only need to hold this mutex.
|
||||
* Writers must hold both this mutex AND ofproto_mutex. */
|
||||
struct ovs_mutex mutex OVS_ACQ_AFTER(ofproto_mutex);
|
||||
|
||||
/* Number of references.
|
||||
* The classifier owns one reference.
|
||||
* Any thread trying to keep a rule from being freed should hold its own
|
||||
* reference. */
|
||||
atomic_uint ref_count;
|
||||
|
||||
struct ofoperation *pending; /* Operation now in progress, if nonnull. */
|
||||
/* Operation now in progress, if nonnull. */
|
||||
struct ofoperation *pending OVS_GUARDED_BY(ofproto_mutex);
|
||||
|
||||
ovs_be64 flow_cookie; /* Controller-issued identifier. Guarded by
|
||||
mutex. */
|
||||
/* A "flow cookie" is the OpenFlow name for a 64-bit value associated with
|
||||
* a flow.. */
|
||||
ovs_be64 flow_cookie OVS_GUARDED;
|
||||
struct hindex_node cookie_node OVS_GUARDED_BY(ofproto_mutex);
|
||||
|
||||
long long int created; /* Creation time. */
|
||||
long long int modified; /* Time of last modification. */
|
||||
long long int used; /* Last use; time created if never used. */
|
||||
enum ofputil_flow_mod_flags flags;
|
||||
/* Times. */
|
||||
long long int created OVS_GUARDED; /* Creation time. */
|
||||
long long int modified OVS_GUARDED; /* Time of last modification. */
|
||||
long long int used OVS_GUARDED; /* Last use; time created if never used. */
|
||||
enum ofputil_flow_mod_flags flags OVS_GUARDED;
|
||||
|
||||
/* Timeouts. */
|
||||
uint16_t hard_timeout OVS_GUARDED; /* In seconds from ->modified. */
|
||||
uint16_t idle_timeout OVS_GUARDED; /* In seconds from ->used. */
|
||||
|
||||
/* Eviction groups. */
|
||||
struct heap_node evg_node; /* In eviction_group's "rules" heap. */
|
||||
struct eviction_group *eviction_group; /* NULL if not in any group. */
|
||||
|
||||
/* The mutex is used to protect those elements in struct rule which are
|
||||
* accessed by multiple threads. The main ofproto code is guaranteed not
|
||||
* to change any of the elements "Guarded by mutex" without holding the
|
||||
* lock.
|
||||
/* Eviction groups (see comment on struct eviction_group for explanation) .
|
||||
*
|
||||
* While maintaining a pointer to struct rule, threads are required to hold
|
||||
* a readlock on the classifier that holds the rule or increment the rule's
|
||||
* ref_count.
|
||||
* 'eviction_group' is this rule's eviction group, or NULL if it is not in
|
||||
* any eviction group. When 'eviction_group' is nonnull, 'evg_node' is in
|
||||
* the ->eviction_group->rules hmap. */
|
||||
struct eviction_group *eviction_group OVS_GUARDED_BY(ofproto_mutex);
|
||||
struct heap_node evg_node OVS_GUARDED_BY(ofproto_mutex);
|
||||
|
||||
/* OpenFlow actions. See struct rule_actions for more thread-safety
|
||||
* notes. */
|
||||
struct rule_actions *actions OVS_GUARDED;
|
||||
|
||||
/* In owning meter's 'rules' list. An empty list if there is no meter. */
|
||||
struct list meter_list_node OVS_GUARDED_BY(ofproto_mutex);
|
||||
|
||||
/* Flow monitors (e.g. for NXST_FLOW_MONITOR, related to struct ofmonitor).
|
||||
*
|
||||
* A rule will not be evicted unless its classifier's write lock is
|
||||
* held. */
|
||||
struct ovs_mutex mutex;
|
||||
|
||||
/* Guarded by mutex. */
|
||||
struct rule_actions *actions;
|
||||
|
||||
struct list meter_list_node; /* In owning meter's 'rules' list. */
|
||||
|
||||
/* Flow monitors. */
|
||||
enum nx_flow_monitor_flags monitor_flags;
|
||||
uint64_t add_seqno; /* Sequence number when added. */
|
||||
uint64_t modify_seqno; /* Sequence number when changed. */
|
||||
* 'add_seqno' is the sequence number when this rule was created.
|
||||
* 'modify_seqno' is the sequence number when this rule was last modified.
|
||||
* See 'monitor_seqno' in connmgr.c for more information. */
|
||||
enum nx_flow_monitor_flags monitor_flags OVS_GUARDED_BY(ofproto_mutex);
|
||||
uint64_t add_seqno OVS_GUARDED_BY(ofproto_mutex);
|
||||
uint64_t modify_seqno OVS_GUARDED_BY(ofproto_mutex);
|
||||
|
||||
/* Optimisation for flow expiry. In ofproto's 'expirable' list if this
|
||||
* rule is expirable, otherwise empty. */
|
||||
@@ -285,6 +393,11 @@ struct rule {
|
||||
void ofproto_rule_ref(struct rule *);
|
||||
void ofproto_rule_unref(struct rule *);
|
||||
|
||||
struct rule_actions *rule_get_actions(const struct rule *rule)
|
||||
OVS_EXCLUDED(rule->mutex);
|
||||
struct rule_actions *rule_get_actions__(const struct rule *rule)
|
||||
OVS_REQUIRES(rule->mutex);
|
||||
|
||||
/* A set of actions within a "struct rule".
|
||||
*
|
||||
*
|
||||
@@ -320,6 +433,8 @@ struct rule_collection {
|
||||
|
||||
void rule_collection_init(struct rule_collection *);
|
||||
void rule_collection_add(struct rule_collection *, struct rule *);
|
||||
void rule_collection_ref(struct rule_collection *) OVS_REQUIRES(ofproto_mutex);
|
||||
void rule_collection_unref(struct rule_collection *);
|
||||
void rule_collection_destroy(struct rule_collection *);
|
||||
|
||||
/* Threshold at which to begin flow table eviction. Only affects the
|
||||
@@ -340,16 +455,19 @@ rule_from_cls_rule(const struct cls_rule *cls_rule)
|
||||
return cls_rule ? CONTAINER_OF(cls_rule, struct rule, cr) : NULL;
|
||||
}
|
||||
|
||||
void ofproto_rule_expire(struct rule *rule, uint8_t reason);
|
||||
void ofproto_rule_expire(struct rule *rule, uint8_t reason)
|
||||
OVS_REQUIRES(ofproto_mutex);
|
||||
void ofproto_rule_delete(struct ofproto *, struct classifier *cls,
|
||||
struct rule *) OVS_REQ_WRLOCK(cls->rwlock);
|
||||
struct rule *)
|
||||
OVS_EXCLUDED(ofproto_mutex);
|
||||
void ofproto_rule_reduce_timeouts(struct rule *rule, uint16_t idle_timeout,
|
||||
uint16_t hard_timeout)
|
||||
OVS_EXCLUDED(ofproto_mutex, rule->mutex);
|
||||
OVS_EXCLUDED(ofproto_mutex);
|
||||
|
||||
void ofoperation_complete(struct ofoperation *, enum ofperr);
|
||||
|
||||
bool ofoperation_has_out_port(const struct ofoperation *, ofp_port_t out_port);
|
||||
bool ofoperation_has_out_port(const struct ofoperation *, ofp_port_t out_port)
|
||||
OVS_REQUIRES(ofproto_mutex);
|
||||
|
||||
/* A group within a "struct ofproto".
|
||||
*
|
||||
@@ -364,7 +482,7 @@ struct ofgroup {
|
||||
* a group is ever write locked only while holding a write lock
|
||||
* on the container, the user's of groups will never face a group
|
||||
* in the write locked state. */
|
||||
struct ovs_rwlock rwlock;
|
||||
struct ovs_rwlock rwlock OVS_ACQ_AFTER(ofproto_mutex);
|
||||
struct hmap_node hmap_node; /* In struct ofproto's "groups" hmap. */
|
||||
struct ofproto *ofproto; /* The ofproto that contains this group. */
|
||||
uint32_t group_id;
|
||||
@@ -1144,9 +1262,10 @@ struct ofproto_class {
|
||||
*
|
||||
* Rule destruction must not fail. */
|
||||
struct rule *(*rule_alloc)(void);
|
||||
enum ofperr (*rule_construct)(struct rule *rule);
|
||||
void (*rule_insert)(struct rule *rule);
|
||||
void (*rule_delete)(struct rule *rule);
|
||||
enum ofperr (*rule_construct)(struct rule *rule)
|
||||
/* OVS_REQUIRES(ofproto_mutex) */;
|
||||
void (*rule_insert)(struct rule *rule) /* OVS_REQUIRES(ofproto_mutex) */;
|
||||
void (*rule_delete)(struct rule *rule) /* OVS_REQUIRES(ofproto_mutex) */;
|
||||
void (*rule_destruct)(struct rule *rule);
|
||||
void (*rule_dealloc)(struct rule *rule);
|
||||
|
||||
@@ -1155,7 +1274,8 @@ struct ofproto_class {
|
||||
* in '*byte_count'. UINT64_MAX indicates that the packet count or byte
|
||||
* count is unknown. */
|
||||
void (*rule_get_stats)(struct rule *rule, uint64_t *packet_count,
|
||||
uint64_t *byte_count);
|
||||
uint64_t *byte_count)
|
||||
/* OVS_EXCLUDED(ofproto_mutex) */;
|
||||
|
||||
/* Applies the actions in 'rule' to 'packet'. (This implements sending
|
||||
* buffered packets for OpenFlow OFPT_FLOW_MOD commands.)
|
||||
@@ -1201,7 +1321,8 @@ struct ofproto_class {
|
||||
*
|
||||
* ->rule_modify_actions() should not modify any base members of struct
|
||||
* rule. */
|
||||
void (*rule_modify_actions)(struct rule *rule, bool reset_counters);
|
||||
void (*rule_modify_actions)(struct rule *rule, bool reset_counters)
|
||||
/* OVS_REQUIRES(ofproto_mutex) */;
|
||||
|
||||
/* Changes the OpenFlow IP fragment handling policy to 'frag_handling',
|
||||
* which takes one of the following values, with the corresponding
|
||||
@@ -1581,12 +1702,15 @@ int ofproto_class_unregister(const struct ofproto_class *);
|
||||
enum { OFPROTO_POSTPONE = 1 << 16 };
|
||||
BUILD_ASSERT_DECL(OFPROTO_POSTPONE < OFPERR_OFS);
|
||||
|
||||
int ofproto_flow_mod(struct ofproto *, struct ofputil_flow_mod *);
|
||||
int ofproto_flow_mod(struct ofproto *, struct ofputil_flow_mod *)
|
||||
OVS_EXCLUDED(ofproto_mutex);
|
||||
void ofproto_add_flow(struct ofproto *, const struct match *,
|
||||
unsigned int priority,
|
||||
const struct ofpact *ofpacts, size_t ofpacts_len);
|
||||
const struct ofpact *ofpacts, size_t ofpacts_len)
|
||||
OVS_EXCLUDED(ofproto_mutex);
|
||||
bool ofproto_delete_flow(struct ofproto *,
|
||||
const struct match *, unsigned int priority);
|
||||
const struct match *, unsigned int priority)
|
||||
OVS_EXCLUDED(ofproto_mutex);
|
||||
void ofproto_flush_flows(struct ofproto *);
|
||||
|
||||
#endif /* ofproto/ofproto-provider.h */
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user