#include "list.h"
#include "odp-util.h"
#include "ofp-util.h"
-#include "ovs-thread.h"
#include "packets.h"
-#include "pvector.h"
#include "tag.h"
#include "util.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(classifier);
-struct trie_node;
struct trie_ctx;
/* Ports trie depends on both ports sharing the same ovs_be32. */
#define TP_PORTS_OFS32 (offsetof(struct flow, tp_src) / 4)
BUILD_ASSERT_DECL(TP_PORTS_OFS32 == offsetof(struct flow, tp_dst) / 4);
-typedef OVSRCU_TYPE(struct trie_node *) rcu_trie_ptr;
-
-/* Prefix trie for a 'field' */
-struct cls_trie {
- const struct mf_field *field; /* Trie field, or NULL. */
- rcu_trie_ptr root; /* NULL if none. */
-};
-
-enum {
- CLS_MAX_INDICES = 3 /* Maximum number of lookup indices per subtable. */
-};
-
-struct cls_classifier {
- struct ovs_mutex mutex;
- int n_rules OVS_GUARDED; /* Total number of rules. */
- uint8_t n_flow_segments;
- uint8_t flow_segments[CLS_MAX_INDICES]; /* Flow segment boundaries to use
- * for staged lookup. */
- struct cmap subtables_map; /* Contains "struct cls_subtable"s. */
- struct pvector subtables;
- struct cmap partitions; /* Contains "struct cls_partition"s. */
- struct cls_trie tries[CLS_MAX_TRIES]; /* Prefix tries. */
- unsigned int n_tries;
-};
-
/* A set of rules that all have the same fields wildcarded. */
struct cls_subtable {
/* The fields are only used by writers and iterators. */
- struct cmap_node cmap_node; /* Within struct cls_classifier
- * 'subtables_map'. */
+ struct cmap_node cmap_node; /* Within struct classifier 'subtables_map'. */
/* The fields are only used by writers. */
int n_rules OVS_GUARDED; /* Number of rules, including
* field) with tags for the "cls_subtable"s that contain rules that match that
* metadata value. */
struct cls_partition {
- struct cmap_node cmap_node; /* In struct cls_classifier's 'partitions'
- * map. */
+ struct cmap_node cmap_node; /* In struct classifier's 'partitions' map. */
ovs_be64 metadata; /* metadata value for this partition. */
tag_type tags; /* OR of each flow's cls_subtable tag. */
struct tag_tracker tracker OVS_GUARDED; /* Tracks the bits in 'tags'. */
return cls_match;
}
-static struct cls_subtable *find_subtable(const struct cls_classifier *cls,
+static struct cls_subtable *find_subtable(const struct classifier *cls,
const struct minimask *)
OVS_REQUIRES(cls->mutex);
-static struct cls_subtable *insert_subtable(struct cls_classifier *cls,
+static struct cls_subtable *insert_subtable(struct classifier *cls,
const struct minimask *)
OVS_REQUIRES(cls->mutex);
-static void destroy_subtable(struct cls_classifier *cls, struct cls_subtable *)
+static void destroy_subtable(struct classifier *cls, struct cls_subtable *)
OVS_REQUIRES(cls->mutex);
-static struct cls_match *insert_rule(struct cls_classifier *cls,
+static struct cls_match *insert_rule(struct classifier *cls,
struct cls_subtable *, struct cls_rule *)
OVS_REQUIRES(cls->mutex);
static unsigned int minimask_get_prefix_len(const struct minimask *,
const struct mf_field *);
-static void trie_init(struct cls_classifier *cls, int trie_idx,
+static void trie_init(struct classifier *cls, int trie_idx,
const struct mf_field *)
OVS_REQUIRES(cls->mutex);
static unsigned int trie_lookup(const struct cls_trie *, const struct flow *,
/* Initializes 'cls' as a classifier that initially contains no classification
* rules. */
void
-classifier_init(struct classifier *cls_, const uint8_t *flow_segments)
- OVS_EXCLUDED(cls_->cls->mutex)
+classifier_init(struct classifier *cls, const uint8_t *flow_segments)
+ OVS_EXCLUDED(cls->mutex)
{
- struct cls_classifier *cls = xmalloc(sizeof *cls);
-
ovs_mutex_init(&cls->mutex);
-
ovs_mutex_lock(&cls->mutex);
- cls_->cls = cls;
-
cls->n_rules = 0;
cmap_init(&cls->subtables_map);
pvector_init(&cls->subtables);
* caller's responsibility.
* May only be called after all the readers have been terminated. */
void
-classifier_destroy(struct classifier *cls_)
- OVS_EXCLUDED(cls_->cls->mutex)
+classifier_destroy(struct classifier *cls)
+ OVS_EXCLUDED(cls->mutex)
{
- if (cls_) {
- struct cls_classifier *cls = cls_->cls;
+ if (cls) {
struct cls_partition *partition, *next_partition;
struct cls_subtable *subtable, *next_subtable;
int i;
- if (!cls) {
- return;
- }
-
ovs_mutex_lock(&cls->mutex);
for (i = 0; i < cls->n_tries; i++) {
trie_destroy(&cls->tries[i].root);
pvector_destroy(&cls->subtables);
ovs_mutex_unlock(&cls->mutex);
ovs_mutex_destroy(&cls->mutex);
- free(cls);
}
}
/* Set the fields for which prefix lookup should be performed. */
bool
-classifier_set_prefix_fields(struct classifier *cls_,
+classifier_set_prefix_fields(struct classifier *cls,
const enum mf_field_id *trie_fields,
unsigned int n_fields)
- OVS_EXCLUDED(cls_->cls->mutex)
+ OVS_EXCLUDED(cls->mutex)
{
- struct cls_classifier *cls = cls_->cls;
uint64_t fields = 0;
const struct mf_field * new_fields[CLS_MAX_TRIES];
int i, n_tries = 0;
}
static void
-trie_init(struct cls_classifier *cls, int trie_idx,
- const struct mf_field *field)
+trie_init(struct classifier *cls, int trie_idx, const struct mf_field *field)
OVS_REQUIRES(cls->mutex)
{
struct cls_trie *trie = &cls->tries[trie_idx];
bool
classifier_is_empty(const struct classifier *cls)
{
- return cmap_is_empty(&cls->cls->subtables_map);
+ return cmap_is_empty(&cls->subtables_map);
}
/* Returns the number of rules in 'cls'. */
{
/* n_rules is an int, so in the presence of concurrent writers this will
* return either the old or a new value. */
- return cls->cls->n_rules;
+ return cls->n_rules;
}
static uint32_t
}
static struct cls_partition *
-find_partition(const struct cls_classifier *cls, ovs_be64 metadata,
- uint32_t hash)
+find_partition(const struct classifier *cls, ovs_be64 metadata, uint32_t hash)
{
struct cls_partition *partition;
}
static struct cls_partition *
-create_partition(struct cls_classifier *cls, struct cls_subtable *subtable,
+create_partition(struct classifier *cls, struct cls_subtable *subtable,
ovs_be64 metadata)
OVS_REQUIRES(cls->mutex)
{
* rule, even rules that cannot have any effect because the new rule matches a
* superset of their flows and has higher priority. */
struct cls_rule *
-classifier_replace(struct classifier *cls_, struct cls_rule *rule)
- OVS_EXCLUDED(cls_->cls->mutex)
+classifier_replace(struct classifier *cls, struct cls_rule *rule)
+ OVS_EXCLUDED(cls->mutex)
{
- struct cls_classifier *cls = cls_->cls;
struct cls_match *old_rule;
struct cls_subtable *subtable;
struct cls_rule *old_cls_rule = NULL;
* 'rule' with cls_rule_destroy(), freeing the memory block in which 'rule'
* resides, etc., as necessary. */
void
-classifier_remove(struct classifier *cls_, struct cls_rule *rule)
- OVS_EXCLUDED(cls_->cls->mutex)
+classifier_remove(struct classifier *cls, struct cls_rule *rule)
+ OVS_EXCLUDED(cls->mutex)
{
- struct cls_classifier *cls = cls_->cls;
struct cls_partition *partition;
struct cls_match *cls_match = rule->cls_match;
struct cls_match *head;
* earlier, 'wc' should have been initialized (e.g., by
* flow_wildcards_init_catchall()). */
struct cls_rule *
-classifier_lookup(const struct classifier *cls_, const struct flow *flow,
+classifier_lookup(const struct classifier *cls, const struct flow *flow,
struct flow_wildcards *wc)
{
- struct cls_classifier *cls = cls_->cls;
const struct cls_partition *partition;
tag_type tags;
int64_t best_priority = -1;
* classifier_lookup() function. Specifically, it does not implement
* priorities, instead returning any rule which matches the flow. */
void
-classifier_lookup_miniflow_batch(const struct classifier *cls_,
+classifier_lookup_miniflow_batch(const struct classifier *cls,
const struct miniflow **flows,
struct cls_rule **rules, size_t len)
{
- struct cls_classifier *cls = cls_->cls;
struct cls_subtable *subtable;
size_t i, begin = 0;
* matching criteria as 'target'. Returns a null pointer if 'cls' doesn't
* contain an exact match. */
struct cls_rule *
-classifier_find_rule_exactly(const struct classifier *cls_,
+classifier_find_rule_exactly(const struct classifier *cls,
const struct cls_rule *target)
- OVS_EXCLUDED(cls_->cls->mutex)
+ OVS_EXCLUDED(cls->mutex)
{
- struct cls_classifier *cls = cls_->cls;
struct cls_match *head, *rule;
struct cls_subtable *subtable;
* considered to overlap if both rules have the same priority and a packet
* could match both. */
bool
-classifier_rule_overlaps(const struct classifier *cls_,
+classifier_rule_overlaps(const struct classifier *cls,
const struct cls_rule *target)
- OVS_EXCLUDED(cls_->cls->mutex)
+ OVS_EXCLUDED(cls->mutex)
{
- struct cls_classifier *cls = cls_->cls;
struct cls_subtable *subtable;
int64_t stop_at_priority = (int64_t)target->priority - 1;
struct cls_rule *cls_rule = NULL;
cursor.safe = safe;
- cursor.cls = cls->cls;
+ cursor.cls = cls;
cursor.target = target && !cls_rule_is_catchall(target) ? target : NULL;
/* Find first rule. */
}
\f
static struct cls_subtable *
-find_subtable(const struct cls_classifier *cls, const struct minimask *mask)
+find_subtable(const struct classifier *cls, const struct minimask *mask)
OVS_REQUIRES(cls->mutex)
{
struct cls_subtable *subtable;
/* The new subtable will be visible to the readers only after this. */
static struct cls_subtable *
-insert_subtable(struct cls_classifier *cls, const struct minimask *mask)
+insert_subtable(struct classifier *cls, const struct minimask *mask)
OVS_REQUIRES(cls->mutex)
{
uint32_t hash = minimask_hash(mask, 0);
}
static void
-destroy_subtable(struct cls_classifier *cls, struct cls_subtable *subtable)
+destroy_subtable(struct classifier *cls, struct cls_subtable *subtable)
OVS_REQUIRES(cls->mutex)
{
int i;
* the subtable until they see the updated partitions.
*/
static struct cls_match *
-insert_rule(struct cls_classifier *cls, struct cls_subtable *subtable,
+insert_rule(struct classifier *cls, struct cls_subtable *subtable,
struct cls_rule *new_rule)
OVS_REQUIRES(cls->mutex)
{
return new_node;
}
-/* May only be called while holding the cls_classifier mutex. */
+/* May only be called while holding the classifier mutex. */
static void
trie_destroy(rcu_trie_ptr *trie)
{
flow.nw_tos = nw_dscp_values[get_value(&x, N_NW_DSCP_VALUES)];
/* This assertion is here to suppress a GCC 4.9 array-bounds warning */
- ovs_assert(cls->cls->n_tries <= CLS_MAX_TRIES);
+ ovs_assert(cls->n_tries <= CLS_MAX_TRIES);
cr0 = classifier_lookup(cls, &flow, &wc);
cr1 = tcls_lookup(tcls, &flow);
}
static void
-pvector_verify(struct pvector *pvec)
+pvector_verify(const struct pvector *pvec)
{
void *ptr OVS_UNUSED;
unsigned int priority, prev_priority = UINT_MAX;
}
static void
-verify_tries(struct classifier *cls_)
+verify_tries(struct classifier *cls)
{
- struct cls_classifier *cls = cls_->cls;
unsigned int n_rules = 0;
int i;
int found_dups = 0;
int found_rules2 = 0;
- pvector_verify(&cls->cls->subtables);
- CMAP_FOR_EACH (table, cmap_node, &cls->cls->subtables_map) {
+ pvector_verify(&cls->subtables);
+ CMAP_FOR_EACH (table, cmap_node, &cls->subtables_map) {
const struct cls_match *head;
unsigned int max_priority = 0;
unsigned int max_count = 0;
const struct cls_subtable *iter;
/* Locate the subtable from 'subtables'. */
- PVECTOR_FOR_EACH (iter, &cls->cls->subtables) {
+ PVECTOR_FOR_EACH (iter, &cls->subtables) {
if (iter == table) {
if (found) {
VLOG_ABORT("Subtable %p duplicated in 'subtables'.",
assert(!cmap_is_empty(&table->rules));
- ovs_mutex_lock(&cls->cls->mutex);
+ ovs_mutex_lock(&cls->mutex);
assert(trie_verify(&table->ports_trie, 0, table->ports_mask_len)
== (table->ports_mask_len ? table->n_rules : 0));
- ovs_mutex_unlock(&cls->cls->mutex);
+ ovs_mutex_unlock(&cls->mutex);
found_tables++;
CMAP_FOR_EACH (head, cmap_node, &table->rules) {
}
found_rules++;
- ovs_mutex_lock(&cls->cls->mutex);
+ ovs_mutex_lock(&cls->mutex);
LIST_FOR_EACH (rule, list, &head->list) {
assert(rule->priority < prev_priority);
assert(rule->priority <= table->max_priority);
prev_priority = rule->priority;
found_rules++;
found_dups++;
- ovs_mutex_unlock(&cls->cls->mutex);
+ ovs_mutex_unlock(&cls->mutex);
assert(classifier_find_rule_exactly(cls, rule->cls_rule)
== rule->cls_rule);
- ovs_mutex_lock(&cls->cls->mutex);
+ ovs_mutex_lock(&cls->mutex);
}
- ovs_mutex_unlock(&cls->cls->mutex);
+ ovs_mutex_unlock(&cls->mutex);
}
- ovs_mutex_lock(&cls->cls->mutex);
+ ovs_mutex_lock(&cls->mutex);
assert(table->max_priority == max_priority);
assert(table->max_count == max_count);
- ovs_mutex_unlock(&cls->cls->mutex);
+ ovs_mutex_unlock(&cls->mutex);
}
- assert(found_tables == cmap_count(&cls->cls->subtables_map));
- assert(found_tables == pvector_count(&cls->cls->subtables));
- assert(n_tables == -1 || n_tables == cmap_count(&cls->cls->subtables_map));
+ assert(found_tables == cmap_count(&cls->subtables_map));
+ assert(found_tables == pvector_count(&cls->subtables));
+ assert(n_tables == -1 || n_tables == cmap_count(&cls->subtables_map));
assert(n_rules == -1 || found_rules == n_rules);
assert(n_dups == -1 || found_dups == n_dups);