/*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 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.
/* Definitions for use within ofproto. */
-#include "ofproto/ofproto.h"
#include "cfm.h"
#include "classifier.h"
#include "heap.h"
+#include "hindex.h"
#include "list.h"
#include "ofp-errors.h"
#include "ofp-util.h"
+#include "ofproto/ofproto.h"
+#include "ovs-thread.h"
#include "shash.h"
#include "simap.h"
#include "timeval.h"
struct match;
struct ofpact;
struct ofputil_flow_mod;
+struct bfd_cfg;
+struct meter;
/* 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. */
struct oftable *tables;
int n_tables;
+ struct hindex cookies; /* Rules indexed on their cookie values. */
+
+ /* Optimisation for flow expiry.
+ * These flows should all be present in tables. */
+ struct ovs_mutex expirable_mutex;
+ struct list expirable OVS_GUARDED; /* Expirable 'struct rule"s in all
+ tables. */
+
+ /* 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;
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".
*
struct ofproto *ofproto; /* The ofproto that contains this port. */
struct netdev *netdev;
struct ofputil_phy_port pp;
- uint16_t ofp_port; /* OpenFlow port number. */
+ ofp_port_t ofp_port; /* OpenFlow port number. */
unsigned int change_seq;
+ long long int created; /* Time created, in msec. */
int mtu;
};
struct ofoperation *pending; /* Operation now in progress, if nonnull. */
ovs_be64 flow_cookie; /* Controller-issued identifier. */
+ struct hindex_node cookie_node; /* In owning ofproto's 'cookies' index. */
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? */
+ struct ovs_mutex timeout_mutex;
+ uint16_t hard_timeout OVS_GUARDED; /* In seconds from ->modified. */
+ uint16_t idle_timeout OVS_GUARDED; /* In seconds from ->used. */
+
/* 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. */
+ /* The evict lock is used to prevent rules from being evicted while child
+ * threads are using them to xlate flows. A read lock means the rule is
+ * currently being used. A write lock means the rule is in the process of
+ * being evicted and should be considered gone. A rule will not be evicted
+ * unless both its own and its classifiers write locks are held.
+ * Therefore, while holding a classifier readlock, one can be assured that
+ * even write locked rules are safe. */
+ struct ovs_rwlock evict;
+
struct ofpact *ofpacts; /* Sequence of "struct ofpacts". */
unsigned int ofpacts_len; /* Size of 'ofpacts', in bytes. */
+ uint32_t meter_id; /* Non-zero OF meter_id, or zero. */
+ 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. */
+
+ /* Optimisation for flow expiry. */
+ struct list expirable; /* In ofproto's 'expirable' list if this rule
+ * is expirable, otherwise empty. */
};
+/* 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 unsigned n_handler_threads;
+
+/* 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)
{
}
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 *);
+void ofproto_rule_expire(struct rule *rule, uint8_t reason);
+void ofproto_rule_delete(struct ofproto *, struct classifier *cls,
+ struct rule *) OVS_REQ_WRLOCK(cls->rwlock);
+void ofproto_rule_reduce_timeouts(struct rule *rule, uint16_t idle_timeout,
+ uint16_t hard_timeout)
+ OVS_EXCLUDED(rule->ofproto->expirable_mutex, rule->timeout_mutex);
-bool ofproto_rule_has_out_port(const struct rule *, uint16_t out_port);
+bool ofproto_rule_has_out_port(const struct rule *, ofp_port_t out_port);
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);
bool ofproto_rule_is_hidden(const struct rule *);
* ofport ->port_alloc ->port_construct ->port_destruct ->port_dealloc
* rule ->rule_alloc ->rule_construct ->rule_destruct ->rule_dealloc
*
+ * "ofproto" and "ofport" 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:
*
* 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);
* 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);
+ void (*rule_insert)(struct rule *rule);
+ void (*rule_delete)(struct rule *rule);
void (*rule_destruct)(struct rule *rule);
void (*rule_dealloc)(struct rule *rule);
* 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);
/* Changes the OpenFlow IP fragment handling policy to 'frag_handling',
* which takes one of the following values, with the corresponding
int (*set_sflow)(struct ofproto *ofproto,
const struct ofproto_sflow_options *sflow_options);
+ /* Configures IPFIX on 'ofproto' according to the options in
+ * 'bridge_exporter_options' and the 'flow_exporters_options'
+ * array, or turns off IPFIX if 'bridge_exporter_options' and
+ * 'flow_exporters_options' is NULL.
+ *
+ * EOPNOTSUPP as a return value indicates that 'ofproto' does not support
+ * IPFIX, as does a null pointer. */
+ int (*set_ipfix)(
+ struct ofproto *ofproto,
+ const struct ofproto_ipfix_bridge_exporter_options
+ *bridge_exporter_options,
+ const struct ofproto_ipfix_flow_exporter_options
+ *flow_exporters_options, size_t n_flow_exporters_options);
+
/* Configures connectivity fault management on 'ofport'.
*
* If 'cfm_settings' is nonnull, configures CFM according to its members.
* support CFM, as does a null pointer. */
int (*set_cfm)(struct ofport *ofport, const struct cfm_settings *s);
- /* Checks the fault status of CFM configured on 'ofport'. Returns a
- * bitmask of 'cfm_fault_reason's to indicate a CFM fault (generally
- * indicating a connectivity problem). Returns zero if CFM is not faulted,
- * and -1 if CFM is not enabled on 'port'.
+ /* Checks the status of CFM configured on 'ofport'. Returns true if the
+ * port's CFM status was successfully stored into '*status'. Returns false
+ * if the port did not have CFM configured, in which case '*status' is
+ * indeterminate.
*
- * This function may be a null pointer if the ofproto implementation does
- * not support CFM. */
- int (*get_cfm_fault)(const struct ofport *ofport);
+ * The caller must provide and owns '*status', but it does not own and must
+ * not modify or free the array returned in 'status->rmps'. */
+ bool (*get_cfm_status)(const struct ofport *ofport,
+ struct ofproto_cfm_status *status);
- /* Check the operational status reported by the remote CFM endpoint of
- * 'ofp_port' Returns 1 if operationally up, 0 if operationally down, and
- * -1 if CFM is not enabled on 'ofp_port' or does not support operational
- * status.
+ /* Configures BFD on 'ofport'.
*
- * This function may be a null pointer if the ofproto implementation does
- * not support CFM. */
- int (*get_cfm_opup)(const struct ofport *ofport);
-
- /* Gets the MPIDs of the remote maintenance points broadcasting to
- * 'ofport'. Populates 'rmps' with a provider owned array of MPIDs, and
- * 'n_rmps' with the number of MPIDs in 'rmps'. Returns a number less than
- * 0 if CFM is not enabled of 'ofport'.
+ * If 'cfg' is NULL, or 'cfg' does not contain the key value pair
+ * "enable=true", removes BFD from 'ofport'. Otherwise, configures BFD
+ * according to 'cfg'.
*
- * This function may be a null pointer if the ofproto implementation does
- * not support CFM. */
- int (*get_cfm_remote_mpids)(const struct ofport *ofport,
- const uint64_t **rmps, size_t *n_rmps);
+ * EOPNOTSUPP as a return value indicates that this ofproto_class does not
+ * support BFD, as does a null pointer. */
+ int (*set_bfd)(struct ofport *ofport, const struct smap *cfg);
- /* Checks the health of CFM configured on 'ofport'. Returns an integer
- * to indicate the health percentage of the 'ofport' which is an average of
- * the health of all the remote_mps. Returns an integer between 0 and 100
- * where 0 means that the 'ofport' is very unhealthy and 100 means the
- * 'ofport' is perfectly healthy. Returns -1 if CFM is not enabled on
- * 'port' or if the number of remote_mpids is > 1.
- *
- * This function may be a null pointer if the ofproto implementation does
- * not support CFM. */
- int (*get_cfm_health)(const struct ofport *ofport);
+ /* Populates 'smap' with the status of BFD on 'ofport'. Returns 0 on
+ * success, or a positive errno. EOPNOTSUPP as a return value indicates
+ * that this ofproto_class does not support BFD, as does a null pointer. */
+ int (*get_bfd_status)(struct ofport *ofport, struct smap *smap);
/* Configures spanning tree protocol (STP) on 'ofproto' using the
* settings defined in 's'.
* 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'. On failure,
+ * the existing meter configuration is left intact. Regardless of success,
+ * any change to '*id' updates the provider meter id used for this
+ * meter. */
+ 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);
};
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 *);
void ofproto_add_flow(struct ofproto *, const struct match *,
unsigned int priority,
const struct ofpact *ofpacts, size_t ofpacts_len);