/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
* Copyright (c) 2010 Jean Tourrilhes - HP-Labs.
*
* Licensed under the Apache License, Version 2.0 (the "License");
ovs_rwlock_init(&ofproto->groups_rwlock);
hmap_init(&ofproto->groups);
ovs_mutex_unlock(&ofproto_mutex);
+ ofproto->ogf.types = 0xf;
ofproto->ogf.capabilities = OFPGFC_CHAINING | OFPGFC_SELECT_LIVENESS |
OFPGFC_SELECT_WEIGHT;
ofproto->ogf.max_groups[OFPGT11_ALL] = OFPG_MAX;
}
}
-/* Populates 'status' with the status of BFD on 'ofport'. Returns 0 on
- * success. Returns a negative number if there is no status change since
- * last update. Returns a positive errno otherwise. Has no effect if
- * 'ofp_port' is not an OpenFlow port in 'ofproto'.
+/* Populates 'status' with the status of BFD on 'ofport'. If 'force' is set to
+ * true, status will be returned even if there is no status change since last
+ * update.
+ *
+ * Returns 0 on success. Returns a negative number if there is no status change
+ * since last update and 'force' is set to false. Returns a positive errno
+ * otherwise. Has no effect if 'ofp_port' is not an OpenFlow port in 'ofproto'.
*
* The caller must provide and own '*status'. */
int
ofproto_port_get_bfd_status(struct ofproto *ofproto, ofp_port_t ofp_port,
- struct smap *status)
+ bool force, struct smap *status)
{
struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
return (ofport && ofproto->ofproto_class->get_bfd_status
- ? ofproto->ofproto_class->get_bfd_status(ofport, status)
+ ? ofproto->ofproto_class->get_bfd_status(ofport, force, status)
: EOPNOTSUPP);
}
hmap_destroy(&ofproto->deletions);
+ ovs_assert(hindex_is_empty(&ofproto->cookies));
+ hindex_destroy(&ofproto->cookies);
+
free(ofproto->vlan_bitmap);
ofproto->ofproto_class->dealloc(ofproto);
ovs_mutex_lock(&ofproto_mutex);
fat_rwlock_rdlock(&table->cls.rwlock);
+
+ if (classifier_count(&table->cls) > 100000) {
+ static struct vlog_rate_limit count_rl =
+ VLOG_RATE_LIMIT_INIT(1, 1);
+ VLOG_WARN_RL(&count_rl, "Table %"PRIuSIZE" has an excessive"
+ " number of rules: %d", i,
+ classifier_count(&table->cls));
+ }
+
cls_cursor_init(&cursor, &table->cls, NULL);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
if (rule->idle_timeout || rule->hard_timeout) {
return handle_flow_mod__(ofproto, NULL, fm, NULL);
}
-/* Resets the modified time for 'rule' or an equivalent rule. If 'rule' is not
- * in the classifier, but an equivalent rule is, unref 'rule' and ref the new
- * rule. Otherwise if 'rule' is no longer installed in the classifier,
- * reinstall it.
- *
- * Returns the rule whose modified time has been reset. */
-struct rule *
-ofproto_refresh_rule(struct rule *rule)
-{
- const struct oftable *table = &rule->ofproto->tables[rule->table_id];
- const struct cls_rule *cr = &rule->cr;
- struct rule *r;
-
- /* do_add_flow() requires that the rule is not installed. We lock the
- * ofproto_mutex here so that another thread cannot add the flow before
- * we get a chance to add it.*/
- ovs_mutex_lock(&ofproto_mutex);
-
- fat_rwlock_rdlock(&table->cls.rwlock);
- r = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls, cr));
- if (r != rule) {
- ofproto_rule_ref(r);
- }
- fat_rwlock_unlock(&table->cls.rwlock);
-
- if (!r) {
- do_add_flow(rule->ofproto, NULL, NULL, 0, rule);
- } else if (r != rule) {
- ofproto_rule_unref(rule);
- rule = r;
- }
- ovs_mutex_unlock(&ofproto_mutex);
-
- /* Refresh the modified time for the rule. */
- ovs_mutex_lock(&rule->mutex);
- rule->modified = MAX(rule->modified, time_msec());
- ovs_mutex_unlock(&rule->mutex);
-
- return rule;
-}
-
/* Searches for a rule with matching criteria exactly equal to 'target' in
* ofproto's table 0 and, if it finds one, deletes it.
*
ofproto->ofproto_class->get_netflow_ids(ofproto, engine_type, engine_id);
}
-/* Checks the status of CFM configured on 'ofp_port' within 'ofproto'.
- * Returns 0 if the port's CFM status was successfully stored into
- * '*status'. Returns positive errno if the port did not have CFM
- * configured. Returns negative number if there is no status change
- * since last update.
+/* Checks the status of CFM configured on 'ofp_port' within 'ofproto' and stores
+ * the port's CFM status in '*status'. If 'force' is set to true, status will
+ * be returned even if there is no status change since last update.
+ *
+ * Returns 0 on success. Returns a negative number if there is no status
+ * change since last update and 'force' is set to false. Returns positive errno
+ * if the port did not have CFM configured.
*
* The caller must provide and own '*status', and must free 'status->rmps'.
* '*status' is indeterminate if the return value is non-zero. */
int
ofproto_port_get_cfm_status(const struct ofproto *ofproto, ofp_port_t ofp_port,
- struct ofproto_cfm_status *status)
+ bool force, struct ofproto_cfm_status *status)
{
struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
return (ofport && ofproto->ofproto_class->get_cfm_status
- ? ofproto->ofproto_class->get_cfm_status(ofport, status)
+ ? ofproto->ofproto_class->get_cfm_status(ofport, force, status)
: EOPNOTSUPP);
}
* Returns 0 on success, otherwise an OpenFlow error code. */
static enum ofperr
delete_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
+ enum ofputil_flow_mod_flags flags,
const struct ofp_header *request,
const struct rule_collection *rules,
enum ofp_flow_removed_reason reason)
OVS_REQUIRES(ofproto_mutex)
{
struct ofopgroup *group;
+ enum ofperr error;
size_t i;
+ error = OFPERR_OFPBRC_EPERM;
group = ofopgroup_create(ofproto, ofconn, request, UINT32_MAX);
for (i = 0; i < rules->n; i++) {
- delete_flow__(rules->rules[i], group, reason);
+ struct rule *rule = rules->rules[i];
+
+ if (rule_is_modifiable(rule, flags)) {
+ /* At least one rule is modifiable, don't report EPERM error. */
+ error = 0;
+ delete_flow__(rule, group, reason);
+ }
}
ofopgroup_submit(group);
- return 0;
+ return error;
}
/* Implements OFPFC_DELETE. */
rule_criteria_destroy(&criteria);
if (!error && rules.n > 0) {
- error = delete_flows__(ofproto, ofconn, request, &rules, OFPRR_DELETE);
+ error = delete_flows__(ofproto, ofconn, fm->flags, request,
+ &rules, OFPRR_DELETE);
}
rule_collection_destroy(&rules);
rule_criteria_destroy(&criteria);
if (!error && rules.n > 0) {
- error = delete_flows__(ofproto, ofconn, request, &rules, OFPRR_DELETE);
+ error = delete_flows__(ofproto, ofconn, fm->flags, request,
+ &rules, OFPRR_DELETE);
}
rule_collection_destroy(&rules);
}
}
if (rules.n > 0) {
- delete_flows__(ofproto, ofconn, oh, &rules, OFPRR_METER_DELETE);
+ delete_flows__(ofproto, ofconn, OFPUTIL_FF_NO_READONLY,
+ oh, &rules, OFPRR_METER_DELETE);
}
/* Delete the meters. */
if (!(op->error
|| ofproto_rule_is_hidden(rule)
|| (op->type == OFOPERATION_MODIFY
- && op->actions
+ && !op->actions
&& rule->flow_cookie == op->flow_cookie))) {
/* Check that we can just cast from ofoperation_type to
* nx_flow_update_event. */