--- /dev/null
+/*
+ * Copyright (c) 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "object-collection.h"
+#include "util.h"
+
+void
+object_collection_init(struct object_collection *coll)
+{
+ coll->objs = coll->stub;
+ coll->n = 0;
+ coll->capacity = ARRAY_SIZE(coll->stub);
+}
+
+void
+object_collection_add(struct object_collection *coll, void *obj)
+{
+ if (coll->n >= coll->capacity) {
+ size_t old_size, new_size;
+
+ old_size = coll->capacity * sizeof *coll->objs;
+ coll->capacity *= 2;
+ new_size = coll->capacity * sizeof *coll->objs;
+
+ if (coll->objs == coll->stub) {
+ coll->objs = xmalloc(new_size);
+ memcpy(coll->objs, coll->stub, old_size);
+ } else {
+ coll->objs = xrealloc(coll->objs, new_size);
+ }
+ }
+
+ coll->objs[coll->n++] = obj;
+}
+
+void
+object_collection_remove(struct object_collection *coll, void *obj)
+{
+ size_t i;
+
+ for (i = 0; i < coll->n; i++) {
+ if (coll->objs[i] == obj) {
+ break;
+ }
+ }
+ if (i == coll->n) {
+ return;
+ }
+
+ coll->n--;
+ /* Swap the last item in if needed. */
+ if (i != coll->n) {
+ coll->objs[i] = coll->objs[coll->n];
+ }
+
+ /* Shrink? Watermark at '/ 4' to get hysteresis and leave spare
+ * capacity. */
+ if (coll->objs != coll->stub && coll->n <= coll->capacity / 4) {
+ size_t actual_size, new_size;
+
+ actual_size = coll->n * sizeof *coll->objs;
+ coll->capacity /= 2;
+ new_size = coll->capacity * sizeof *coll->objs;
+
+ if (new_size <= sizeof(coll->stub)) {
+ memcpy(coll->stub, coll->objs, actual_size);
+ free(coll->objs);
+ coll->objs = coll->stub;
+ } else {
+ coll->objs = xrealloc(coll->objs, new_size);
+ }
+ }
+}
+
+void
+object_collection_move(struct object_collection *to,
+ struct object_collection *from)
+{
+ ovs_assert(to->n == 0);
+
+ *to = *from;
+ if (from->objs == from->stub) {
+ to->objs = to->stub;
+ }
+ object_collection_init(from);
+}
+
+/* Returns a NULL-terminated array of object pointers,
+ * destroys 'rules'. */
+void *
+object_collection_detach(struct object_collection *coll)
+{
+ void **array;
+
+ object_collection_add(coll, NULL);
+
+ if (coll->objs == coll->stub) {
+ coll->objs = xmemdup(coll->objs, coll->n * sizeof *coll->objs);
+ }
+
+ array = coll->objs;
+ object_collection_init(coll);
+
+ return array;
+}
+
+void
+object_collection_destroy(struct object_collection *coll)
+{
+ if (coll->objs != coll->stub) {
+ free(coll->objs);
+ }
+
+ /* Make repeated destruction harmless. */
+ object_collection_init(coll);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBJECT_COLLECTION_H
+#define OBJECT_COLLECTION_H 1
+
+#include <limits.h>
+#include <stdlib.h>
+
+/* A set of object pointers. */
+struct object_collection {
+ void **objs; /* Objects. */
+ size_t n; /* Number of objects collected. */
+ size_t capacity; /* Number of objects that fit in 'objs'. */
+ void *stub[5]; /* Preallocated array to avoid malloc(). */
+};
+
+void object_collection_init(struct object_collection *);
+void object_collection_add(struct object_collection *, void *);
+void object_collection_remove(struct object_collection *, void *);
+void object_collection_move(struct object_collection *to,
+ struct object_collection *from);
+void *object_collection_detach(struct object_collection *);
+void object_collection_destroy(struct object_collection *);
+
+/* Macro for declaring type-safe pointer collections. 'TYPE' is the pointer
+ * type which are collected, 'NAME' is the name for the type to be used in the
+ * function names. */
+
+#define DECL_OBJECT_COLLECTION(TYPE, NAME) \
+struct NAME##_collection { \
+ struct object_collection collection; \
+}; \
+ \
+static inline void NAME##_collection_init(struct NAME##_collection *coll) \
+{ \
+ object_collection_init(&coll->collection); \
+} \
+ \
+static inline void NAME##_collection_add(struct NAME##_collection *coll, \
+ TYPE obj) \
+{ \
+ object_collection_add(&coll->collection, obj); \
+} \
+ \
+static inline void NAME##_collection_remove(struct NAME##_collection *coll, \
+ TYPE obj) \
+{ \
+ object_collection_remove(&coll->collection, obj); \
+} \
+ \
+static inline void NAME##_collection_move(struct NAME##_collection *to, \
+ struct NAME##_collection *from) \
+{ \
+ object_collection_move(&to->collection, &from->collection); \
+} \
+ \
+static inline void NAME##_collection_destroy(struct NAME##_collection *coll) \
+{ \
+ object_collection_destroy(&coll->collection); \
+} \
+ \
+static inline TYPE* NAME##_collection_##NAME##s(const struct NAME##_collection *coll) \
+{ \
+ return (TYPE*)coll->collection.objs; \
+} \
+ \
+static inline TYPE* NAME##_collection_stub(struct NAME##_collection *coll) \
+{ \
+ return (TYPE*)coll->collection.stub; \
+} \
+ \
+static inline size_t NAME##_collection_n(const struct NAME##_collection *coll) \
+{ \
+ return coll->collection.n; \
+} \
+ \
+static inline TYPE* NAME##_collection_detach(struct NAME##_collection *coll) \
+{ \
+ return (TYPE*)object_collection_detach(&coll->collection); \
+}
+
+#endif /* object-collection.h */
OVS_NO_THREAD_SAFETY_ANALYSIS
{
if (group && ovs_refcount_unref_relaxed(&group->ref_count) == 1) {
- ovs_assert(group->rules.n == 0);
+ ovs_assert(rule_collection_n(&group->rules) == 0);
ovsrcu_postpone(group_destroy_cb, group);
}
}
cls_rule_destroy(&criteria->cr);
}
-void
-rule_collection_init(struct rule_collection *rules)
-{
- rules->rules = rules->stub;
- rules->n = 0;
- rules->capacity = ARRAY_SIZE(rules->stub);
-}
-
-void
-rule_collection_add(struct rule_collection *rules, struct rule *rule)
-{
- if (rules->n >= rules->capacity) {
- size_t old_size, new_size;
-
- old_size = rules->capacity * sizeof *rules->rules;
- rules->capacity *= 2;
- new_size = rules->capacity * sizeof *rules->rules;
-
- if (rules->rules == rules->stub) {
- rules->rules = xmalloc(new_size);
- memcpy(rules->rules, rules->stub, old_size);
- } else {
- rules->rules = xrealloc(rules->rules, new_size);
- }
- }
-
- rules->rules[rules->n++] = rule;
-}
-
-void
-rule_collection_remove(struct rule_collection *rules, struct rule *rule)
-{
- size_t i;
-
- for (i = 0; i < rules->n; i++) {
- if (rules->rules[i] == rule) {
- break;
- }
- }
- if (i == rules->n) {
- return;
- }
-
- rules->n--;
- /* Swap the last item in if needed. */
- if (i != rules->n) {
- rules->rules[i] = rules->rules[rules->n];
- }
-
- /* Shrink? Watermark at '/ 4' to get hysteresis and leave spare
- * capacity. */
- if (rules->rules != rules->stub && rules->n <= rules->capacity / 4) {
- size_t actual_size, new_size;
-
- actual_size = rules->n * sizeof *rules->rules;
- rules->capacity /= 2;
- new_size = rules->capacity * sizeof *rules->rules;
-
- if (new_size <= sizeof(rules->stub)) {
- memcpy(rules->stub, rules->rules, actual_size);
- free(rules->rules);
- rules->rules = rules->stub;
- } else {
- rules->rules = xrealloc(rules->rules, new_size);
- }
- }
-}
-
-void
-rule_collection_move(struct rule_collection *to, struct rule_collection *from)
-{
- ovs_assert(to->n == 0);
-
- *to = *from;
- if (from->rules == from->stub) {
- to->rules = to->stub;
- }
- rule_collection_init(from);
-}
-
-void
-rule_collection_ref(struct rule_collection *rules)
- OVS_REQUIRES(ofproto_mutex)
-{
- size_t i;
-
- for (i = 0; i < rules->n; i++) {
- ofproto_rule_ref(rules->rules[i]);
- }
-}
-
-void
-rule_collection_unref(struct rule_collection *rules)
-{
- size_t i;
-
- for (i = 0; i < rules->n; i++) {
- ofproto_rule_unref(rules->rules[i]);
- }
-}
-
-/* Returns a NULL-terminated array of rule pointers,
- * destroys 'rules'. */
-static struct rule **
-rule_collection_detach(struct rule_collection *rules)
-{
- struct rule **rule_array;
-
- rule_collection_add(rules, NULL);
-
- if (rules->rules == rules->stub) {
- rules->rules = xmemdup(rules->rules, rules->n * sizeof *rules->rules);
- }
-
- rule_array = rules->rules;
- rule_collection_init(rules);
-
- return rule_array;
-}
-
-void
-rule_collection_destroy(struct rule_collection *rules)
-{
- if (rules->rules != rules->stub) {
- free(rules->rules);
- }
-
- /* Make repeated destruction harmless. */
- rule_collection_init(rules);
-}
-
/* Schedules postponed removal of rules, destroys 'rules'. */
static void
remove_rules_postponed(struct rule_collection *rules)
OVS_REQUIRES(ofproto_mutex)
{
- if (rules->n > 0) {
- if (rules->n == 1) {
- ovsrcu_postpone(remove_rule_rcu, rules->rules[0]);
- rules->n = 0;
+ if (rule_collection_n(rules) > 0) {
+ if (rule_collection_n(rules) == 1) {
+ ovsrcu_postpone(remove_rule_rcu, rule_collection_rules(rules)[0]);
+ rule_collection_init(rules);
} else {
ovsrcu_postpone(remove_rules_rcu, rule_collection_detach(rules));
}
}
exit:
- if (!error && !rules->n && n_readonly) {
+ if (!error && !rule_collection_n(rules) && n_readonly) {
/* We didn't find any rules to modify. We did find some read-only
* rules that we're not allowed to modify, so report that. */
error = OFPERR_OFPBRC_EPERM;
}
exit:
- if (!error && !rules->n && n_readonly) {
+ if (!error && !rule_collection_n(rules) && n_readonly) {
/* We didn't find any rules to modify. We did find some read-only
* rules that we're not allowed to modify, so report that. */
error = OFPERR_OFPBRC_EPERM;
struct rule_collection rules;
struct ovs_list replies;
enum ofperr error;
- size_t i;
error = ofputil_decode_flow_stats_request(&fsr, request);
if (error) {
}
ofpmp_init(&replies, request);
- for (i = 0; i < rules.n; i++) {
- struct rule *rule = rules.rules[i];
+ struct rule *rule;
+ RULE_COLLECTION_FOR_EACH (rule, &rules) {
long long int now = time_msec();
struct ofputil_flow_stats fs;
long long int created, used, modified;
struct rule_collection rules;
struct ofpbuf *reply;
enum ofperr error;
- size_t i;
error = ofputil_decode_flow_stats_request(&request, oh);
if (error) {
memset(&stats, 0, sizeof stats);
unknown_packets = unknown_bytes = false;
- for (i = 0; i < rules.n; i++) {
- struct rule *rule = rules.rules[i];
+
+ struct rule *rule;
+ RULE_COLLECTION_FOR_EACH (rule, &rules) {
uint64_t packet_count;
uint64_t byte_count;
long long int used;
OVS_REQUIRES(ofproto_mutex)
{
struct ofputil_flow_mod *fm = &ofm->fm;
- struct rule **old_rule = &ofm->old_rules.stub[0];
- struct rule **new_rule = &ofm->new_rules.stub[0];
+ struct rule **old_rule = rule_collection_stub(&ofm->old_rules);
+ struct rule **new_rule = rule_collection_stub(&ofm->new_rules);
struct oftable *table;
struct cls_rule cr;
struct rule *rule;
OVS_REQUIRES(ofproto_mutex)
{
struct ofputil_flow_mod *fm = &ofm->fm;
- struct rule *old_rule = ofm->old_rules.stub[0];
- struct rule *new_rule = ofm->new_rules.stub[0];
+ struct rule *old_rule = rule_collection_stub(&ofm->old_rules)[0];
+ struct rule *new_rule = rule_collection_stub(&ofm->new_rules)[0];
if (old_rule && fm->delete_reason == OFPRR_EVICTION) {
/* Revert the eviction. */
OVS_REQUIRES(ofproto_mutex)
{
struct ofputil_flow_mod *fm = &ofm->fm;
- struct rule *old_rule = ofm->old_rules.stub[0];
- struct rule *new_rule = ofm->new_rules.stub[0];
+ struct rule *old_rule = rule_collection_stub(&ofm->old_rules)[0];
+ struct rule *new_rule = rule_collection_stub(&ofm->new_rules)[0];
struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);
replace_rule_finish(ofproto, fm, req, old_rule, new_rule, &dead_cookies);
rule_collection_init(new_rules);
- if (old_rules->n > 0) {
+ if (rule_collection_n(old_rules) > 0) {
struct cls_conjunction *conjs;
size_t n_conjs;
- size_t i;
/* Create a new 'modified' rule for each old rule. */
- for (i = 0; i < old_rules->n; i++) {
- struct rule *old_rule = old_rules->rules[i];
+ struct rule *old_rule;
+ RULE_COLLECTION_FOR_EACH (old_rule, old_rules) {
struct rule *new_rule;
struct cls_rule cr;
return error;
}
}
- ovs_assert(new_rules->n == old_rules->n);
+ ovs_assert(rule_collection_n(new_rules)
+ == rule_collection_n(old_rules));
get_conjunctions(fm, &conjs, &n_conjs);
- for (i = 0; i < old_rules->n; i++) {
- replace_rule_start(ofproto, ofm->version, old_rules->rules[i],
- new_rules->rules[i], conjs, n_conjs);
+ struct rule *new_rule;
+ RULE_COLLECTIONS_FOR_EACH (old_rule, new_rule, old_rules, new_rules) {
+ replace_rule_start(ofproto, ofm->version, old_rule, new_rule,
+ conjs, n_conjs);
}
free(conjs);
} else if (!(fm->cookie_mask != htonll(0)
error = add_flow_start(ofproto, ofm);
if (!error) {
ovs_assert(fm->delete_reason == OFPRR_EVICTION
- || !old_rules->rules[0]);
+ || !rule_collection_rules(old_rules)[0]);
}
- new_rules->n = 1;
+ new_rules->collection.n = 1;
} else {
error = 0;
}
struct rule_collection *new_rules = &ofm->new_rules;
/* Old rules were not changed yet, only need to revert new rules. */
- if (old_rules->n == 0 && new_rules->n == 1) {
+ if (rule_collection_n(old_rules) == 0
+ && rule_collection_n(new_rules) == 1) {
add_flow_revert(ofproto, ofm);
- } else if (old_rules->n > 0) {
- for (size_t i = 0; i < old_rules->n; i++) {
- replace_rule_revert(ofproto, old_rules->rules[i],
- new_rules->rules[i]);
+ } else if (rule_collection_n(old_rules) > 0) {
+ struct rule *old_rule, *new_rule;
+ RULE_COLLECTIONS_FOR_EACH (old_rule, new_rule, old_rules, new_rules) {
+ replace_rule_revert(ofproto, old_rule, new_rule);
}
rule_collection_destroy(new_rules);
rule_collection_destroy(old_rules);
struct rule_collection *old_rules = &ofm->old_rules;
struct rule_collection *new_rules = &ofm->new_rules;
- if (old_rules->n == 0 && new_rules->n == 1) {
+ if (rule_collection_n(old_rules) == 0
+ && rule_collection_n(new_rules) == 1) {
add_flow_finish(ofproto, ofm, req);
- } else if (old_rules->n > 0) {
+ } else if (rule_collection_n(old_rules) > 0) {
struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);
- ovs_assert(new_rules->n == old_rules->n);
+ ovs_assert(rule_collection_n(new_rules)
+ == rule_collection_n(old_rules));
- for (size_t i = 0; i < old_rules->n; i++) {
- replace_rule_finish(ofproto, fm, req, old_rules->rules[i],
- new_rules->rules[i], &dead_cookies);
+ struct rule *old_rule, *new_rule;
+ RULE_COLLECTIONS_FOR_EACH (old_rule, new_rule, old_rules, new_rules) {
+ replace_rule_finish(ofproto, fm, req, old_rule, new_rule,
+ &dead_cookies);
}
learned_cookies_flush(ofproto, &dead_cookies);
remove_rules_postponed(old_rules);
- send_buffered_packet(req, fm->buffer_id, new_rules->rules[0]);
+ send_buffered_packet(req, fm->buffer_id,
+ rule_collection_rules(new_rules)[0]);
rule_collection_destroy(new_rules);
}
}
const struct rule_collection *rules)
OVS_REQUIRES(ofproto_mutex)
{
- for (size_t i = 0; i < rules->n; i++) {
- struct rule *rule = rules->rules[i];
+ struct rule *rule;
+
+ RULE_COLLECTION_FOR_EACH (rule, rules) {
struct oftable *table = &ofproto->tables[rule->table_id];
table->n_flows--;
const struct flow_mod_requester *req)
OVS_REQUIRES(ofproto_mutex)
{
- if (rules->n) {
+ if (rule_collection_n(rules)) {
struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);
+ struct rule *rule;
- for (size_t i = 0; i < rules->n; i++) {
- struct rule *rule = rules->rules[i];
-
+ RULE_COLLECTION_FOR_EACH (rule, rules) {
/* This value will be used to send the flow removed message right
* before the rule is actually destroyed. */
rule->removed_reason = reason;
const struct flow_mod_requester *req)
OVS_REQUIRES(ofproto_mutex)
{
- if (rules->n) {
- struct ofproto *ofproto = rules->rules[0]->ofproto;
+ if (rule_collection_n(rules)) {
+ struct ofproto *ofproto = rule_collection_rules(rules)[0]->ofproto;
delete_flows_start__(ofproto, ofproto->tables_version + 1, rules);
ofproto_bump_tables_version(ofproto);
OVS_REQUIRES(ofproto_mutex)
{
struct rule_collection *rules = &ofm->old_rules;
+ struct rule *rule;
- for (size_t i = 0; i < rules->n; i++) {
- struct rule *rule = rules->rules[i];
+ RULE_COLLECTION_FOR_EACH (rule, rules) {
struct oftable *table = &ofproto->tables[rule->table_id];
/* Add rule back to ofproto data structures. */
{
struct rule_collection rules;
- rules.rules = rules.stub;
- rules.n = 1;
- rules.stub[0] = rule;
+ rule_collection_init(&rules);
+ rule_collection_add(&rules, rule);
delete_flows__(&rules, reason, NULL);
}
struct ovs_list *msgs)
OVS_REQUIRES(ofproto_mutex)
{
- size_t i;
+ struct rule *rule;
- for (i = 0; i < rules->n; i++) {
- struct rule *rule = rules->rules[i];
+ RULE_COLLECTION_FOR_EACH (rule, rules) {
enum nx_flow_monitor_flags flags = rule->monitor_flags;
rule->monitor_flags = 0;
ogs.bucket_stats = xmalloc(group->n_buckets * sizeof *ogs.bucket_stats);
/* Provider sets the packet and byte counts, we do the rest. */
- ogs.ref_count = group->rules.n;
+ ogs.ref_count = rule_collection_n(&group->rules);
ogs.n_buckets = group->n_buckets;
error = (ofproto->ofproto_class->group_get_stats