#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 "ofproto/ofproto.h"
#include "cfm.h"
#include "classifier.h"
+#include "guarded-list.h"
#include "heap.h"
+#include "hindex.h"
#include "list.h"
#include "ofp-errors.h"
#include "ofp-util.h"
+#include "ofproto/ofproto.h"
+#include "ovs-atomic.h"
+#include "ovs-thread.h"
#include "shash.h"
#include "simap.h"
#include "timeval.h"
struct ofpact;
struct ofputil_flow_mod;
struct bfd_cfg;
+struct meter;
+
+extern struct ovs_mutex ofproto_mutex;
/* An OpenFlow switch.
*
/* Settings. */
uint64_t fallback_dpid; /* Datapath ID if no better choice found. */
uint64_t datapath_id; /* Datapath ID. */
- unsigned flow_eviction_threshold; /* Threshold at which to begin flow
- * table eviction. Only affects the
- * ofproto-dpif implementation */
bool forward_bpdu; /* Option to allow forwarding of BPDU frames
* when NORMAL action is invoked. */
char *mfr_desc; /* Manufacturer (NULL for default)b. */
/* Datapath. */
struct hmap ports; /* Contains "struct ofport"s. */
struct shash port_by_name;
- unsigned long *ofp_port_ids;/* Bitmap of used OpenFlow port numbers. */
struct simap ofp_requests; /* OpenFlow port number requests. */
uint16_t alloc_port_no; /* Last allocated OpenFlow port number. */
uint16_t max_ports; /* Max possible OpenFlow port num, plus one. */
+ struct hmap ofport_usage; /* Map ofport to last used time. */
+ uint64_t change_seq; /* Change sequence for netdev status. */
/* Flow tables. */
+ long long int eviction_group_timer; /* For rate limited reheapification. */
struct oftable *tables;
int n_tables;
- /* Optimisation for flow expiry.
- * These flows should all be present in tables. */
- struct list expirable; /* Expirable 'struct rule"s in all tables. */
+ /* Rules indexed on their cookie values, in all flow tables. */
+ struct hindex cookies OVS_GUARDED_BY(ofproto_mutex);
+
+ /* List of expirable flows, in all flow tables. */
+ struct list expirable OVS_GUARDED_BY(ofproto_mutex);
+
+ /* Meter table.
+ * OpenFlow meters start at 1. To avoid confusion we leave the first
+ * pointer in the array un-used, and index directly with the OpenFlow
+ * meter_id. */
+ struct ofputil_meter_features meter_features;
+ struct meter **meters; /* 'meter_features.max_meter' + 1 pointers. */
/* 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.
+ *
+ * We delay calls to ->ofproto_class->rule_execute() past releasing
+ * 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; /* Contains "struct rule_execute"s. */
/* Flow table operation logging. */
int n_add, n_delete, n_modify; /* Number of unreported ops of each kind. */
unsigned long int *vlan_bitmap; /* 4096-bit bitmap of in-use VLANs. */
bool vlans_changed; /* True if new VLANs are in use. */
int min_mtu; /* Current MTU of non-internal ports. */
+
+ /* Groups. */
+ struct ovs_rwlock groups_rwlock;
+ struct hmap groups OVS_GUARDED; /* Contains "struct ofgroup"s. */
+ uint32_t n_groups[4] OVS_GUARDED; /* # of existing groups of each type. */
+ struct ofputil_group_features ogf;
};
void ofproto_init_tables(struct ofproto *, int n_tables);
void ofproto_init_max_ports(struct ofproto *, uint16_t max_ports);
struct ofproto *ofproto_lookup(const char *name);
-struct ofport *ofproto_get_port(const struct ofproto *, uint16_t ofp_port);
+struct ofport *ofproto_get_port(const struct ofproto *, ofp_port_t ofp_port);
/* An OpenFlow port within a "struct ofproto".
+ *
+ * The port's name is netdev_get_name(port->netdev).
*
* With few exceptions, ofproto implementations may look at these fields but
* should not modify them. */
struct ofproto *ofproto; /* The ofproto that contains this port. */
struct netdev *netdev;
struct ofputil_phy_port pp;
- uint16_t ofp_port; /* OpenFlow port number. */
- unsigned int change_seq;
+ ofp_port_t ofp_port; /* OpenFlow port number. */
long long int created; /* Time created, in msec. */
int mtu;
};
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. */
/* 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->mutex').
+ *
+ * '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 {
- struct list ofproto_node; /* Owned by ofproto base code. */
- struct ofproto *ofproto; /* The ofproto that contains this rule. */
- struct cls_rule cr; /* In owning ofproto's classifier. */
-
- struct ofoperation *pending; /* Operation now in progress, if nonnull. */
-
- ovs_be64 flow_cookie; /* Controller-issued identifier. */
-
- 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. */
- uint16_t hard_timeout; /* In seconds from ->modified. */
- uint16_t idle_timeout; /* In seconds from ->used. */
- uint8_t table_id; /* Index in ofproto's 'tables' array. */
- bool send_flow_removed; /* Send a flow removed message? */
-
- /* Eviction groups. */
- bool evictable; /* If false, prevents eviction. */
- struct heap_node evg_node; /* In eviction_group's "rules" heap. */
- struct eviction_group *eviction_group; /* NULL if not in any group. */
-
- struct ofpact *ofpacts; /* Sequence of "struct ofpacts". */
- unsigned int ofpacts_len; /* Size of 'ofpacts', in bytes. */
-
- /* 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. */
-
- /* Optimisation for flow expiry. */
- struct list expirable; /* In ofproto's 'expirable' list if this rule
- * is expirable, otherwise empty. */
+ /* Where this rule resides in an OpenFlow switch.
+ *
+ * These are immutable once the rule is constructed, hence 'const'. */
+ struct ofproto *const ofproto; /* The ofproto that contains this 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;
+
+ /* Operation now in progress, if nonnull. */
+ struct ofoperation *pending OVS_GUARDED_BY(ofproto_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);
+
+ /* 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 (see comment on struct eviction_group for explanation) .
+ *
+ * '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).
+ *
+ * '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. */
+ struct list expirable OVS_GUARDED_BY(ofproto_mutex);
+};
+
+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);
+
+/* Returns true if 'rule' is an OpenFlow 1.3 "table-miss" rule, false
+ * otherwise.
+ *
+ * ("Table-miss" rules are special because a packet_in generated through one
+ * uses OFPR_NO_MATCH as its reason, whereas packet_ins generated by any other
+ * rule use OFPR_ACTION.) */
+static inline bool
+rule_is_table_miss(const struct rule *rule)
+{
+ return rule->cr.priority == 0 && cls_rule_is_catchall(&rule->cr);
+}
+
+/* A set of actions within a "struct rule".
+ *
+ *
+ * Thread-safety
+ * =============
+ *
+ * A struct rule_actions 'actions' may be accessed without a risk of being
+ * freed by code that holds a read-lock or write-lock on 'rule->mutex' (where
+ * 'rule' is the rule for which 'rule->actions == actions') or that owns a
+ * reference to 'actions->ref_count' (or both). */
+struct rule_actions {
+ atomic_uint ref_count;
+
+ /* These members are immutable: they do not change during the struct's
+ * lifetime. */
+ struct ofpact *ofpacts; /* Sequence of "struct ofpacts". */
+ unsigned int ofpacts_len; /* Size of 'ofpacts', in bytes. */
+ uint32_t provider_meter_id; /* Datapath meter_id, or UINT32_MAX. */
};
+struct rule_actions *rule_actions_create(const struct ofproto *,
+ const struct ofpact *, size_t);
+void rule_actions_ref(struct rule_actions *);
+void rule_actions_unref(struct rule_actions *);
+
+/* A set of rules to which an OpenFlow operation applies. */
+struct rule_collection {
+ struct rule **rules; /* The rules. */
+ size_t n; /* Number of rules collected. */
+
+ size_t capacity; /* Number of rules that will fit in 'rules'. */
+ struct rule *stub[64]; /* Preallocated rules to avoid malloc(). */
+};
+
+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
+ * ofproto-dpif implementation */
+extern unsigned flow_eviction_threshold;
+
+/* Number of upcall handler threads. Only affects the ofproto-dpif
+ * implementation. */
+extern size_t n_handlers;
+
+/* Determines which model to use for handling misses in the ofproto-dpif
+ * implementation */
+extern enum ofproto_flow_miss_model flow_miss_model;
+
static inline struct rule *
rule_from_cls_rule(const struct cls_rule *cls_rule)
{
return cls_rule ? CONTAINER_OF(cls_rule, struct rule, cr) : NULL;
}
-void ofproto_rule_update_used(struct rule *, long long int used);
-void ofproto_rule_expire(struct rule *, uint8_t reason);
-void ofproto_rule_destroy(struct rule *);
-
-bool ofproto_rule_has_out_port(const struct rule *, uint16_t out_port);
+void ofproto_rule_expire(struct rule *rule, uint8_t reason)
+ OVS_REQUIRES(ofproto_mutex);
+void ofproto_rule_delete(struct ofproto *, 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);
void ofoperation_complete(struct ofoperation *, enum ofperr);
-struct rule *ofoperation_get_victim(struct ofoperation *);
-bool ofoperation_has_out_port(const struct ofoperation *, uint16_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".
+ *
+ * With few exceptions, ofproto implementations may look at these fields but
+ * should not modify them. */
+struct ofgroup {
+ /* The rwlock is used to prevent groups from being deleted while child
+ * threads are using them to xlate flows. A read lock means the
+ * group is currently being used. A write lock means the group is
+ * in the process of being deleted or updated. Note that since
+ * a read lock on the groups container is held while searching, and
+ * 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 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;
+ enum ofp11_group_type type; /* One of OFPGT_*. */
+
+ long long int created; /* Creation time. */
+ long long int modified; /* Time of last modification. */
+
+ struct list buckets; /* Contains "struct ofputil_bucket"s. */
+ uint32_t n_buckets;
+};
+
+bool ofproto_group_lookup(const struct ofproto *ofproto, uint32_t group_id,
+ struct ofgroup **group)
+ OVS_TRY_RDLOCK(true, (*group)->rwlock);
-bool ofproto_rule_is_hidden(const struct rule *);
+void ofproto_group_release(struct ofgroup *group)
+ OVS_RELEASES(group->rwlock);
/* ofproto class structure, to be defined by each ofproto implementation.
*
* Data Structures
* ===============
*
- * These functions work primarily with three different kinds of data
+ * These functions work primarily with four different kinds of data
* structures:
*
* - "struct ofproto", which represents an OpenFlow switch.
*
* - "struct rule", which represents an OpenFlow flow within an ofproto.
*
+ * - "struct ofgroup", which represents an OpenFlow 1.1+ group within an
+ * ofproto.
+ *
* Each of these data structures contains all of the implementation-independent
* generic state for the respective concept, called the "base" state. None of
* them contains any extra space for ofproto implementations to use. Instead,
* ofproto ->alloc ->construct ->destruct ->dealloc
* ofport ->port_alloc ->port_construct ->port_destruct ->port_dealloc
* rule ->rule_alloc ->rule_construct ->rule_destruct ->rule_dealloc
+ * group ->group_alloc ->group_construct ->group_destruct ->group_dealloc
+ *
+ * "ofproto", "ofport", and "group" have this exact life cycle. The "rule"
+ * data structure also follow this life cycle with some additional elaborations
+ * described under "Rule Life Cycle" below.
*
* Any instance of a given data structure goes through the following life
* cycle:
* Returns 0 if successful, otherwise a positive errno value. */
int (*type_run)(const char *type);
- /* Performs periodic activity required on ofprotos of type 'type'
- * that needs to be done with the least possible latency.
- *
- * This is run multiple times per main loop. An ofproto provider may
- * implement it or not, according to whether it provides a performance
- * boost for that ofproto implementation.
- *
- * Returns 0 if successful, otherwise a positive errno value. */
- int (*type_run_fast)(const char *type);
-
/* Causes the poll loop to wake up when a type 'type''s 'run'
* function needs to be called, e.g. by calling the timer or fd
* waiting functions in poll-loop.h.
* must complete all of them by calling ofoperation_complete().
*
* ->destruct() must also destroy all remaining rules in the ofproto's
- * tables, by passing each remaining rule to ofproto_rule_destroy(). The
- * client will destroy the flow tables themselves after ->destruct()
+ * tables, by passing each remaining rule to ofproto_rule_delete(), and
+ * then complete each of those deletions in turn by calling
+ * ofoperation_complete().
+ *
+ * (Thus, there is a multi-step process for any rule currently being
+ * inserted or modified at the beginning of destruction: first
+ * ofoperation_complete() that operation, then ofproto_rule_delete() the
+ * rule, then ofoperation_complete() the deletion operation.)
+ *
+ * The client will destroy the flow tables themselves after ->destruct()
* returns.
*/
struct ofproto *(*alloc)(void);
* Returns 0 if successful, otherwise a positive errno value. */
int (*run)(struct ofproto *ofproto);
- /* Performs periodic activity required by 'ofproto' that needs to be done
- * with the least possible latency.
- *
- * This is run multiple times per main loop. An ofproto provider may
- * implement it or not, according to whether it provides a performance
- * boost for that ofproto implementation. */
- int (*run_fast)(struct ofproto *ofproto);
-
/* Causes the poll loop to wake up when 'ofproto''s 'run' function needs to
* be called, e.g. by calling the timer or fd waiting functions in
* poll-loop.h. */
void (*get_memory_usage)(const struct ofproto *ofproto,
struct simap *usage);
+ /* Adds some memory usage statistics for the implementation of 'type'
+ * into 'usage', for use with memory_report().
+ *
+ * This function is optional. */
+ void (*type_get_memory_usage)(const char *type, struct simap *usage);
+
/* Every "struct rule" in 'ofproto' is about to be deleted, one by one.
* This function may prepare for that, for example by clearing state in
* advance. It should *not* actually delete any "struct rule"s from
* It doesn't matter whether the new port will be returned by a later call
* to ->port_poll(); the implementation may do whatever is more
* convenient. */
- int (*port_del)(struct ofproto *ofproto, uint16_t ofp_port);
+ int (*port_del)(struct ofproto *ofproto, ofp_port_t ofp_port);
/* Get port stats */
int (*port_get_stats)(const struct ofport *port,
const struct match *match,
uint8_t *table_idp);
- /* Life-cycle functions for a "struct rule" (see "Life Cycle" above).
+ /* Life-cycle functions for a "struct rule".
+ *
+ *
+ * Rule Life Cycle
+ * ===============
+ *
+ * The life cycle of a struct rule is an elaboration of the basic life
+ * cycle described above under "Life Cycle".
+ *
+ * After a rule is successfully constructed, it is then inserted. If
+ * insertion completes successfully, then before it is later destructed, it
+ * is deleted.
+ *
+ * You can think of a rule as having the following extra steps inserted
+ * between "Life Cycle" steps 4 and 5:
+ *
+ * 4.1. The client inserts the rule into the flow table, making it
+ * visible in flow table lookups.
+ *
+ * 4.2. The client calls "rule_insert". Immediately or eventually, the
+ * implementation calls ofoperation_complete() to indicate that the
+ * insertion completed. If the operation failed, skip to step 5.
+ *
+ * 4.3. The rule is now installed in the flow table. Eventually it will
+ * be deleted.
+ *
+ * 4.4. The client removes the rule from the flow table. It is no longer
+ * visible in flow table lookups.
+ *
+ * 4.5. The client calls "rule_delete". Immediately or eventually, the
+ * implementation calls ofoperation_complete() to indicate that the
+ * deletion completed. Deletion is not allowed to fail, so it must
+ * be successful.
*
*
* Asynchronous Operation Support
* ==============================
*
- * The life-cycle operations on rules can operate asynchronously, meaning
- * that ->rule_construct() and ->rule_destruct() only need to initiate
- * their respective operations and do not need to wait for them to complete
- * before they return. ->rule_modify_actions() also operates
- * asynchronously.
+ * The "insert" and "delete" life-cycle operations on rules can operate
+ * asynchronously, meaning that ->rule_insert() and ->rule_delete() only
+ * need to initiate their respective operations and do not need to wait for
+ * them to complete before they return. ->rule_modify_actions() also
+ * operates asynchronously.
*
* An ofproto implementation reports the success or failure of an
* asynchronous operation on a rule using the rule's 'pending' member,
* which points to a opaque "struct ofoperation" that represents the
- * ongoing opreation. When the operation completes, the ofproto
+ * ongoing operation. When the operation completes, the ofproto
* implementation calls ofoperation_complete(), passing the ofoperation and
* an error indication.
*
* Only the following contexts may call ofoperation_complete():
*
- * - The function called to initiate the operation,
- * e.g. ->rule_construct() or ->rule_destruct(). This is the best
- * choice if the operation completes quickly.
+ * - The function called to initiate the operation, e.g. ->rule_insert()
+ * or ->rule_delete(). This is the best choice if the operation
+ * completes quickly.
*
* - The implementation's ->run() function.
*
* The ofproto base code updates the flow table optimistically, assuming
* that the operation will probably succeed:
*
- * - ofproto adds or replaces the rule in the flow table before calling
- * ->rule_construct().
+ * - ofproto adds the rule in the flow table before calling
+ * ->rule_insert().
*
- * - ofproto updates the rule's actions before calling
- * ->rule_modify_actions().
+ * - ofproto updates the rule's actions and other properties before
+ * calling ->rule_modify_actions().
*
- * - ofproto removes the rule before calling ->rule_destruct().
+ * - ofproto removes the rule before calling ->rule_delete().
*
* With one exception, when an asynchronous operation completes with an
* error, ofoperation_complete() backs out the already applied changes:
*
- * - If adding or replacing a rule in the flow table fails, ofproto
- * removes the new rule or restores the original rule.
+ * - If adding a rule in the flow table fails, ofproto removes the new
+ * rule.
*
- * - If modifying a rule's actions fails, ofproto restores the original
- * actions.
+ * - If modifying a rule fails, ofproto restores the original actions
+ * (and other properties).
*
* - Removing a rule is not allowed to fail. It must always succeed.
*
* Construction
* ============
*
- * When ->rule_construct() is called, the caller has already inserted
- * 'rule' into 'rule->ofproto''s flow table numbered 'rule->table_id'.
- * There are two cases:
+ * When ->rule_construct() is called, 'rule' is a new rule that is not yet
+ * inserted into a flow table. ->rule_construct() should initialize enough
+ * of the rule's derived state for 'rule' to be suitable for inserting into
+ * a flow table. ->rule_construct() should not modify any base members of
+ * struct rule.
*
- * - 'rule' is a new rule in its flow table. In this case,
- * ofoperation_get_victim(rule) returns NULL.
+ * If ->rule_construct() fails (as indicated by returning a nonzero
+ * OpenFlow error code), the ofproto base code will uninitialize and
+ * deallocate 'rule'. See "Rule Life Cycle" above for more details.
*
- * - 'rule' is replacing an existing rule in its flow table that had the
- * same matching criteria and priority. In this case,
- * ofoperation_get_victim(rule) returns the rule being replaced (the
- * "victim" rule).
+ * ->rule_construct() may also:
*
- * ->rule_construct() should set the following in motion:
- *
- * - Validate that the matching rule in 'rule->cr' is supported by the
+ * - Validate that the datapath supports the matching rule in 'rule->cr'
* datapath. For example, if the rule's table does not support
* registers, then it is an error if 'rule->cr' does not wildcard all
* registers.
*
* - Validate that the datapath can correctly implement 'rule->ofpacts'.
*
- * - If the rule is valid, update the datapath flow table, adding the new
- * rule or replacing the existing one.
+ * Some implementations might need to defer these tasks to ->rule_insert(),
+ * which is also acceptable.
+ *
+ *
+ * Insertion
+ * =========
*
- * - If 'rule' is replacing an existing rule, uninitialize any derived
- * state for the victim rule, as in step 5 in the "Life Cycle"
- * described above.
+ * Following successful construction, the ofproto base case inserts 'rule'
+ * into its flow table, then it calls ->rule_insert(). ->rule_insert()
+ * should set in motion adding the new rule to the datapath flow table. It
+ * must act as follows:
*
- * (On failure, the ofproto code will roll back the insertion from the flow
- * table, either removing 'rule' or replacing it by the victim rule if
- * there is one.)
+ * - If it completes insertion, either by succeeding or failing, it must
+ * call ofoperation_complete()
*
- * ->rule_construct() must act in one of the following ways:
+ * - If insertion is only partially complete, then it must return without
+ * calling ofoperation_complete(). Later, when the insertion is
+ * complete, the ->run() or ->destruct() function must call
+ * ofoperation_complete() to report success or failure.
*
- * - If it succeeds, it must call ofoperation_complete() and return 0.
+ * If ->rule_insert() fails, the ofproto base code will remove 'rule' from
+ * the flow table, destruct, uninitialize, and deallocate 'rule'. See
+ * "Rule Life Cycle" above for more details.
*
- * - If it fails, it must act in one of the following ways:
*
- * * Call ofoperation_complete() and return 0.
+ * Deletion
+ * ========
*
- * * Return an OpenFlow error code. (Do not call
- * ofoperation_complete() in this case.)
+ * The ofproto base code removes 'rule' from its flow table before it calls
+ * ->rule_delete(). ->rule_delete() should set in motion removing 'rule'
+ * from the datapath flow table. It must act as follows:
*
- * Either way, ->rule_destruct() will not be called for 'rule', but
- * ->rule_dealloc() will be.
+ * - If it completes deletion, it must call ofoperation_complete().
*
- * - If the operation is only partially complete, then it must return 0.
- * Later, when the operation is complete, the ->run() or ->destruct()
- * function must call ofoperation_complete() to report success or
- * failure.
+ * - If deletion is only partially complete, then it must return without
+ * calling ofoperation_complete(). Later, when the deletion is
+ * complete, the ->run() or ->destruct() function must call
+ * ofoperation_complete().
*
- * ->rule_construct() should not modify any base members of struct rule.
+ * Rule deletion must not fail.
*
*
* Destruction
* ===========
*
- * When ->rule_destruct() is called, the caller has already removed 'rule'
- * from 'rule->ofproto''s flow table. ->rule_destruct() should set in
- * motion removing 'rule' from the datapath flow table. If removal
- * completes synchronously, it should call ofoperation_complete().
- * Otherwise, the ->run() or ->destruct() function must later call
- * ofoperation_complete() after the operation completes.
+ * ->rule_destruct() must uninitialize derived state.
*
* Rule destruction must not fail. */
struct rule *(*rule_alloc)(void);
- enum ofperr (*rule_construct)(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);
* 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.)
* flow->tunnel and flow->in_port, which are assigned the correct values
* for the incoming packet. The register values are zeroed. 'packet''s
* header pointers (e.g. packet->l3) are appropriately initialized.
+ * packet->l3 is aligned on a 32-bit boundary.
*
* The implementation should add the statistics for 'packet' into 'rule'.
*
*
* - Update the datapath flow table with the new actions.
*
+ * - Only if 'reset_counters' is true, reset any packet or byte counters
+ * associated with the rule to zero, so that rule_get_stats() will not
+ * longer count those packets or bytes.
+ *
* If the operation synchronously completes, ->rule_modify_actions() may
* call ofoperation_complete() before it returns. Otherwise, ->run()
* should call ofoperation_complete() later, after the operation does
*
* ->rule_modify_actions() should not modify any base members of struct
* rule. */
- void (*rule_modify_actions)(struct rule *rule);
+ 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
int (*get_stp_port_status)(struct ofport *ofport,
struct ofproto_port_stp_status *s);
+ /* Retrieves spanning tree protocol (STP) port statistics of 'ofport'.
+ *
+ * Stores STP state for 'ofport' in 's'. If the 'enabled' member is
+ * false, the other member values are not meaningful.
+ *
+ * EOPNOTSUPP as a return value indicates that this ofproto_class does not
+ * support STP, as does a null pointer. */
+ int (*get_stp_port_stats)(struct ofport *ofport,
+ struct ofproto_port_stp_stats *s);
+
/* Registers meta-data associated with the 'n_qdscp' Qualities of Service
* 'queues' attached to 'ofport'. This data is not intended to be
* sufficient to implement QoS. Instead, providers may use this
* If 'realdev_ofp_port' is zero, then this function deconfigures 'ofport'
* as a VLAN splinter port.
*
- * This function should be NULL if a an implementation does not support
- * it. */
+ * This function should be NULL if an implementation does not support it.
+ */
int (*set_realdev)(struct ofport *ofport,
- uint16_t realdev_ofp_port, int vid);
+ ofp_port_t realdev_ofp_port, int vid);
+
+/* ## ------------------------ ## */
+/* ## OpenFlow meter functions ## */
+/* ## ------------------------ ## */
+
+ /* These functions should be NULL if an implementation does not support
+ * them. They must be all null or all non-null.. */
+
+ /* Initializes 'features' to describe the metering features supported by
+ * 'ofproto'. */
+ void (*meter_get_features)(const struct ofproto *ofproto,
+ struct ofputil_meter_features *features);
+
+ /* If '*id' is UINT32_MAX, adds a new meter with the given 'config'. On
+ * success the function must store a provider meter ID other than
+ * UINT32_MAX in '*id'. All further references to the meter will be made
+ * with the returned provider meter id rather than the OpenFlow meter id.
+ * The caller does not try to interpret the provider meter id, giving the
+ * implementation the freedom to either use the OpenFlow meter_id value
+ * provided in the meter configuration, or any other value suitable for the
+ * implementation.
+ *
+ * If '*id' is a value other than UINT32_MAX, modifies the existing meter
+ * with that meter provider ID to have configuration 'config', while
+ * leaving '*id' unchanged. On failure, the existing meter configuration
+ * is left intact. */
+ enum ofperr (*meter_set)(struct ofproto *ofproto, ofproto_meter_id *id,
+ const struct ofputil_meter_config *config);
+
+ /* Gets the meter and meter band packet and byte counts for maximum of
+ * 'stats->n_bands' bands for the meter with provider ID 'id' within
+ * 'ofproto'. The caller fills in the other stats values. The band stats
+ * are copied to memory at 'stats->bands' provided by the caller. The
+ * number of returned band stats is returned in 'stats->n_bands'. */
+ enum ofperr (*meter_get)(const struct ofproto *ofproto,
+ ofproto_meter_id id,
+ struct ofputil_meter_stats *stats);
+
+ /* Deletes a meter, making the 'ofproto_meter_id' invalid for any
+ * further calls. */
+ void (*meter_del)(struct ofproto *, ofproto_meter_id);
+
+
+/* ## -------------------- ## */
+/* ## OpenFlow 1.1+ groups ## */
+/* ## -------------------- ## */
+
+ struct ofgroup *(*group_alloc)(void);
+ enum ofperr (*group_construct)(struct ofgroup *);
+ void (*group_destruct)(struct ofgroup *);
+ void (*group_dealloc)(struct ofgroup *);
+
+ enum ofperr (*group_modify)(struct ofgroup *, struct ofgroup *victim);
+
+ enum ofperr (*group_get_stats)(const struct ofgroup *,
+ struct ofputil_group_stats *);
};
extern const struct ofproto_class ofproto_dpif_class;
enum { OFPROTO_POSTPONE = 1 << 16 };
BUILD_ASSERT_DECL(OFPROTO_POSTPONE < OFPERR_OFS);
-int ofproto_flow_mod(struct ofproto *, const 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 */