#include "ofp-print.h"
#include "ofp-util.h"
#include "ofpbuf.h"
+#include "ofproto-provider.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
#include "packets.h"
#include "pinsched.h"
#include "pktbuf.h"
#include "poll-loop.h"
-#include "private.h"
#include "shash.h"
#include "sset.h"
#include "timeval.h"
static void ofopgroup_destroy(struct ofopgroup *);
-static int add_flow(struct ofproto *, struct ofconn *, struct flow_mod *,
- const struct ofp_header *);
+static int add_flow(struct ofproto *, struct ofconn *,
+ struct ofputil_flow_mod *, const struct ofp_header *);
/* This return value tells handle_openflow() that processing of the current
* OpenFlow message must be postponed until some ongoing operations have
struct ofproto **ofprotop)
{
const struct ofproto_class *class;
+ struct classifier *table;
struct ofproto *ofproto;
+ int n_tables;
int error;
*ofprotop = NULL;
hmap_insert(&all_ofprotos, &ofproto->hmap_node,
hash_string(ofproto->name, 0));
ofproto->datapath_id = 0;
+ ofproto_set_flow_eviction_threshold(ofproto,
+ OFPROTO_FLOW_EVICTON_THRESHOLD_DEFAULT);
+ ofproto->forward_bpdu = false;
ofproto->fallback_dpid = pick_fallback_dpid();
ofproto->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
ofproto->hw_desc = xstrdup(DEFAULT_HW_DESC);
list_init(&ofproto->pending);
hmap_init(&ofproto->deletions);
- error = ofproto->ofproto_class->construct(ofproto);
+ error = ofproto->ofproto_class->construct(ofproto, &n_tables);
if (error) {
VLOG_ERR("failed to open datapath %s: %s",
datapath_name, strerror(error));
ofproto_destroy__(ofproto);
return error;
}
- assert(ofproto->n_tables > 0);
+
+ assert(n_tables >= 1 && n_tables <= 255);
+ ofproto->n_tables = n_tables;
+ ofproto->tables = xmalloc(n_tables * sizeof *ofproto->tables);
+ OFPROTO_FOR_EACH_TABLE (table, ofproto) {
+ classifier_init(table);
+ }
ofproto->datapath_id = pick_datapath_id(ofproto);
VLOG_INFO("using datapath ID %016"PRIx64, ofproto->datapath_id);
connmgr_set_in_band_queue(ofproto->connmgr, queue_id);
}
+/* Sets the number of flows at which eviction from the kernel flow table
+ * will occur. */
+void
+ofproto_set_flow_eviction_threshold(struct ofproto *ofproto, unsigned threshold)
+{
+ if (threshold < OFPROTO_FLOW_EVICTION_THRESHOLD_MIN) {
+ ofproto->flow_eviction_threshold = OFPROTO_FLOW_EVICTION_THRESHOLD_MIN;
+ } else {
+ ofproto->flow_eviction_threshold = threshold;
+ }
+}
+
+/* If forward_bpdu is true, the NORMAL action will forward frames with
+ * reserved (e.g. STP) destination Ethernet addresses. if forward_bpdu is false,
+ * the NORMAL action will drop these frames. */
+void
+ofproto_set_forward_bpdu(struct ofproto *ofproto, bool forward_bpdu)
+{
+ bool old_val = ofproto->forward_bpdu;
+ ofproto->forward_bpdu = forward_bpdu;
+ if (old_val != ofproto->forward_bpdu) {
+ if (ofproto->ofproto_class->forward_bpdu_changed) {
+ ofproto->ofproto_class->forward_bpdu_changed(ofproto);
+ }
+ }
+}
+
void
ofproto_set_desc(struct ofproto *p,
const char *mfr_desc, const char *hw_desc,
}
group = ofopgroup_create(ofproto);
- for (table = ofproto->tables; table < &ofproto->tables[ofproto->n_tables];
- table++) {
+ OFPROTO_FOR_EACH_TABLE (table, ofproto) {
struct rule *rule, *next_rule;
struct cls_cursor cursor;
static void
ofproto_destroy__(struct ofproto *ofproto)
{
- size_t i;
+ struct classifier *table;
assert(list_is_empty(&ofproto->pending));
hmap_destroy(&ofproto->ports);
shash_destroy(&ofproto->port_by_name);
- for (i = 0; i < ofproto->n_tables; i++) {
- assert(classifier_is_empty(&ofproto->tables[i]));
- classifier_destroy(&ofproto->tables[i]);
+ OFPROTO_FOR_EACH_TABLE (table, ofproto) {
+ assert(classifier_is_empty(table));
+ classifier_destroy(table);
}
free(ofproto->tables);
void
ofproto_free_ofproto_controller_info(struct shash *info)
{
- struct shash_node *node;
-
- SHASH_FOR_EACH (node, info) {
- struct ofproto_controller_info *cinfo = node->data;
- while (cinfo->pairs.n) {
- free((char *) cinfo->pairs.values[--cinfo->pairs.n]);
- }
- free(cinfo);
- }
- shash_destroy(info);
+ connmgr_free_controller_info(info);
}
/* Makes a deep copy of 'old' into 'port'. */
&ofproto->tables[0], cls_rule));
if (!rule || !ofputil_actions_equal(rule->actions, rule->n_actions,
actions, n_actions)) {
- struct flow_mod fm;
+ struct ofputil_flow_mod fm;
memset(&fm, 0, sizeof fm);
fm.cr = *cls_rule;
ofport_open(const struct ofproto_port *ofproto_port, struct ofp_phy_port *opp)
{
uint32_t curr, advertised, supported, peer;
- struct netdev_options netdev_options;
enum netdev_flags flags;
struct netdev *netdev;
int error;
- memset(&netdev_options, 0, sizeof netdev_options);
- netdev_options.name = ofproto_port->name;
- netdev_options.type = ofproto_port->type;
- netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
-
- error = netdev_open(&netdev_options, &netdev);
+ error = netdev_open(ofproto_port->name, ofproto_port->type, &netdev);
if (error) {
VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s "
"cannot be opened (%s)",
/* This function allows an ofproto implementation to destroy any rules that
* remain when its ->destruct() function is called. The caller must have
* already uninitialized any derived members of 'rule' (step 5 described in the
- * large comment in ofproto/private.h titled "Life Cycle"). This function
- * implements steps 6 and 7.
+ * large comment in ofproto/ofproto-provider.h titled "Life Cycle").
+ * This function implements steps 6 and 7.
*
* This function should only be called from an ofproto implementation's
* ->destruct() function. It is not suitable elsewhere. */
rule_has_out_port(const struct rule *rule, uint16_t out_port)
{
const union ofp_action *oa;
- struct actions_iterator i;
+ size_t left;
if (out_port == OFPP_NONE) {
return true;
}
- for (oa = actions_first(&i, rule->actions, rule->n_actions); oa;
- oa = actions_next(&i)) {
+ OFPUTIL_ACTION_FOR_EACH_UNSAFE (oa, left, rule->actions, rule->n_actions) {
if (action_outputs_to_port(oa, htons(out_port))) {
return true;
}
const struct ofp_stats_msg *osm)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- struct flow_stats_request fsr;
+ struct ofputil_flow_stats_request fsr;
struct list replies;
struct list rules;
struct rule *rule;
flow_stats_ds(struct rule *rule, struct ds *results)
{
uint64_t packet_count, byte_count;
- size_t act_len = sizeof *rule->actions * rule->n_actions;
rule->ofproto->ofproto_class->rule_get_stats(rule,
&packet_count, &byte_count);
ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
cls_rule_format(&rule->cr, results);
ds_put_char(results, ',');
- if (act_len > 0) {
- ofp_print_actions(results, &rule->actions->header, act_len);
+ if (rule->n_actions > 0) {
+ ofp_print_actions(results, rule->actions, rule->n_actions);
} else {
ds_put_cstr(results, "drop");
}
{
struct classifier *cls;
- for (cls = &p->tables[0]; cls < &p->tables[p->n_tables]; cls++) {
+ OFPROTO_FOR_EACH_TABLE (cls, p) {
struct cls_cursor cursor;
struct rule *rule;
: -1);
}
+/* Gets the MPIDs of the remote maintenance points broadcasting to 'ofp_port'
+ * within 'ofproto'. Populates 'rmps' with an array of MPIDs owned by
+ * 'ofproto', and 'n_rmps' with the number of MPIDs in 'rmps'. Returns a
+ * number less than 0 if CFM is not enabled on 'ofp_port'. */
+int
+ofproto_port_get_cfm_remote_mpids(const struct ofproto *ofproto,
+ uint16_t ofp_port, const uint64_t **rmps,
+ size_t *n_rmps)
+{
+ struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+
+ *rmps = NULL;
+ *n_rmps = 0;
+ return (ofport && ofproto->ofproto_class->get_cfm_remote_mpids
+ ? ofproto->ofproto_class->get_cfm_remote_mpids(ofport, rmps,
+ n_rmps)
+ : -1);
+}
+
static int
handle_aggregate_stats_request(struct ofconn *ofconn,
const struct ofp_stats_msg *osm)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- struct flow_stats_request request;
+ struct ofputil_flow_stats_request request;
struct ofputil_aggregate_stats stats;
bool unknown_packets, unknown_bytes;
struct ofpbuf *reply;
* 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
* if any. */
static int
-add_flow(struct ofproto *ofproto, struct ofconn *ofconn, struct flow_mod *fm,
- const struct ofp_header *request)
+add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
+ struct ofputil_flow_mod *fm, const struct ofp_header *request)
{
struct classifier *table;
struct ofopgroup *group;
/* Pick table. */
if (fm->table_id == 0xff) {
uint8_t table_id;
- if (ofproto->n_tables > 1) {
+ if (ofproto->ofproto_class->rule_choose_table) {
error = ofproto->ofproto_class->rule_choose_table(ofproto, &fm->cr,
&table_id);
if (error) {
*
* Returns 0 on success, otherwise an OpenFlow error code. */
static int
-modify_flows__(struct ofconn *ofconn, const struct flow_mod *fm,
+modify_flows__(struct ofconn *ofconn, const struct ofputil_flow_mod *fm,
const struct ofp_header *request, struct list *rules)
{
struct ofopgroup *group;
* 'ofconn' is used to retrieve the packet buffer specified in fm->buffer_id,
* if any. */
static int
-modify_flows_loose(struct ofconn *ofconn, struct flow_mod *fm,
+modify_flows_loose(struct ofconn *ofconn, struct ofputil_flow_mod *fm,
const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
* 'ofconn' is used to retrieve the packet buffer specified in fm->buffer_id,
* if any. */
static int
-modify_flow_strict(struct ofconn *ofconn, struct flow_mod *fm,
+modify_flow_strict(struct ofconn *ofconn, struct ofputil_flow_mod *fm,
const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
/* Implements OFPFC_DELETE. */
static int
-delete_flows_loose(struct ofconn *ofconn, const struct flow_mod *fm,
+delete_flows_loose(struct ofconn *ofconn, const struct ofputil_flow_mod *fm,
const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
/* Implements OFPFC_DELETE_STRICT. */
static int
-delete_flow_strict(struct ofconn *ofconn, struct flow_mod *fm,
+delete_flow_strict(struct ofconn *ofconn, struct ofputil_flow_mod *fm,
const struct ofp_header *request)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- struct flow_mod fm;
+ struct ofputil_flow_mod fm;
int error;
error = reject_slave_controller(ofconn, "flow_mod");
* indicate success or an OpenFlow error code (constructed with
* e.g. ofp_mkerr()).
*
- * If 'op' is a "delete flow" operation, 'error' must be 0. That is, flow
- * deletions are not allowed to fail.
+ * If 'error' is 0, indicating success, the operation will be committed
+ * permanently to the flow table. There is one interesting subcase:
+ *
+ * - If 'op' is an "add flow" operation that is replacing an existing rule in
+ * the flow table (the "victim" rule) by a new one, then the caller must
+ * have uninitialized any derived state in the victim rule, as in step 5 in
+ * the "Life Cycle" in ofproto/ofproto-provider.h. ofoperation_complete()
+ * performs steps 6 and 7 for the victim rule, most notably by calling its
+ * ->rule_dealloc() function.
+ *
+ * If 'error' is nonzero, then generally the operation will be rolled back:
+ *
+ * - If 'op' is an "add flow" operation, ofproto removes the new rule or
+ * restores the original rule. The caller must have uninitialized any
+ * derived state in the new rule, as in step 5 of in the "Life Cycle" in
+ * ofproto/ofproto-provider.h. ofoperation_complete() performs steps 6 and
+ * and 7 for the new rule, calling its ->rule_dealloc() function.
+ *
+ * - If 'op' is a "modify flow" operation, ofproto restores the original
+ * actions.
+ *
+ * - 'op' must not be a "delete flow" operation. Removing a rule is not
+ * allowed to fail. It must always succeed.
*
- * Please see the large comment in ofproto/private.h titled "Asynchronous
- * Operation Support" for more information. */
+ * Please see the large comment in ofproto/ofproto-provider.h titled
+ * "Asynchronous Operation Support" for more information. */
void
ofoperation_complete(struct ofoperation *op, int error)
{