OVS Classifier - Rules

Keywords: Linux less

In the ovs classifier, rules can be divided into simple rules and associated matching rules in terms of complexity.Simple rules exist independently, association rules exist simultaneously.Association rules need to be hit at the same time to be hit eventually.Association rules have a large impact on performance.

Simple Rules

In the classifier, rules are organized using the struct cls_rule structure.A rule has a mask domain and a value domain.

struct cls_rule

/* A rule to be inserted to the classifier. */
/* A rule is inserted into the classifier */
struct cls_rule {
    struct rculist node;          /* In struct cls_subtable 'rules_list'. Double-linked list, joined to the corresponding sub-table */
    const int priority;           /* Larger numbers are higher priorities.The larger the value, the higher its priority */
    OVSRCU_TYPE(struct cls_match *) cls_match;  /* NULL if not in a
                                                 * classifier. */
    const struct minimatch match; /* Matching rule. A matcher consisting of two miniflow s, a bitmask and a value */
};

/* Internal representation of a rule in a "struct cls_subtable".
 *
 * The 'next' member is an element in a singly linked, null-terminated list.
 * This list links together identical "cls_match"es in order of decreasing
 * priority.  The classifier code maintains the invariant that at most one rule
 * of a given priority is visible for any given lookup version.
 * Rule representation in a subtable.next members form a single-chain list that represents different rules for the same matching domain.By Priority
 * Arrange in high and low order.
 */
struct cls_match {
    /* Accessed by everybody. */
    OVSRCU_TYPE(struct cls_match *) next; /* Equal, lower-priority matches. Same matching criteria, sorted by priority */
    OVSRCU_TYPE(struct cls_conjunction_set *) conj_set;

    /* Accessed by readers interested in wildcarding. */
    /* With precedence, the higher the value, the higher the priority */
    const int priority;         /* Larger numbers are higher priorities. */

    /* Accessed by all readers. */
    struct cmap_node cmap_node; /* Within struct cls_subtable 'rules'. h Hang to rules chain of child tables */

    /* Rule versioning. */
    /* Rule Version Number */
    struct versions versions;

    const struct cls_rule *cls_rule;/* Rules that point to which they belong */
    const struct miniflow flow; /* Matching rule. Mask is in the subtable. Match field whose mask is in subtable */
    /* 'flow' must be the last field. */
};

Association Matching Rules

Association matching is when multiple rules hit at the same time before the hit rule is calculated, which is called Association matching.One rule in hit Association matching is called soft-match. When all rules of association matching are soft-match, the whole rule is hit and is converted from soft-match to hard-match.

For example:

Association matching is when multiple rules hit at the same time before the hit rule is calculated, which is called Association matching.One rule in hit Association matching is called soft-match. When all rules of association matching are soft-match, the whole rule is hit and is converted from soft-match to hard-match.

For example:

conj_id=1234 actions=controller
ip,ip_src=10.0.0.1 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.4 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.6 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.7 actions=conjunction(1234, 1/2)
ip,ip_dst=10.0.0.2 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.5 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.7 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.8 actions=conjunction(1234, 2/2)

The above rule defines an association rule, and when the association rule is hit, the message is sent to the controller:

conj_id=1234 actions=controller

Association rules have two dimensions, 1 and 2.The rules in Dimension 1 are:

ip,ip_src=10.0.0.1 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.4 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.6 actions=conjunction(1234, 1/2)
ip,ip_src=10.0.0.7 actions=conjunction(1234, 1/2)

The rules in Dimension 2 are:

ip,ip_dst=10.0.0.2 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.5 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.7 actions=conjunction(1234, 2/2)
ip,ip_dst=10.0.0.8 actions=conjunction(1234, 2/2)

The relationship between a rule in a dimension is or is a relationship, and if one of the rules is hit, the dimension is considered hit. The relationship between a dimension and a dimension is a relationship of a relationship. When all dimensions are hit, the association rule is hard-match.

data structure

/* A collection of "struct cls_conjunction"s currently embedded into a
 * cls_match.A cls_conjunction collection for embedding in cls_match 
 * An association rule that can associate multiple association IDS
 */
struct cls_conjunction_set {
    /* Link back to the cls_match.
     *
     * cls_conjunction_set is mostly used during classifier lookup, and, in
     * turn, during classifier lookup the most used member of
     * cls_conjunction_set is the rule's priority, so we cache it here for fast
     * access. Reverse to the matcher to which it belongs */
    struct cls_match *match;
    int priority;               /* Cached copy of match->priority.Cache the priority of the matcher to which it belongs */

    /* Conjunction information.
     * Connection Point Information
     * 'min_n_clauses' allows some optimization during classifier lookup. */
    unsigned int n;             /* Number of elements in 'conj'. Number of Association Rules*/
    unsigned int min_n_clauses; /* Smallest 'n' among elements of 'conj'.The smallest n in the associated set array */
    struct cls_conjunction conj[];/* Associated Rule Array */
};

struct cls_conjunction {
    uint32_t id;/* Associated action id */
    uint8_t clause;/* The bit position of the stream, the associated dimension, starting at 0 */
    uint8_t n_clauses;/* Number of associated streams, how many dimensions */
};

//Association ID structure, one association id, clauses dimensions
//This structure is an internal structure used to temporarily store association matches and convert to hard-match when all dimensions are hit.
struct conjunctive_match {
    struct hmap_node hmap_node;/* Used to connect to hash tables, typically in temporary table matches */
    uint32_t id;/* Associated id */
    uint64_t clauses;/* Corresponding stream epitope mask, 64 bit s, that is, ovs supports 64 dimensions */
};

correlation function

/* Traverse hash bucket, find item with same associated id in temporary hash table, return NULL not found */
static struct conjunctive_match *
find_conjunctive_match__(struct hmap *matches, uint64_t id, uint32_t hash)
{
    struct conjunctive_match *m;

    HMAP_FOR_EACH_IN_BUCKET (m, hmap_node, hash, matches) {/* Matching in a hash table */
        if (m->id == id) {/* Traverse each element of the hash bucket to compare IDs to be equal */
            return m;
        }
    }
    return NULL;
}

/* Find Association Match */
static bool
find_conjunctive_match(const struct cls_conjunction_set *set, /* The set of associated IDS corresponding to this rule */
                       unsigned int max_n_clauses, /* Number of rule preferences for the set hit by this table */
                       struct hmap *matches, /* Associated id temporary hash table*/
                       /* conjunctive_match Local array to avoid dynamic memory allocation */
                       struct conjunctive_match *cm_stubs, size_t n_cm_stubs,
                       uint32_t *idp)//Return hit Association id
{
    const struct cls_conjunction *c;

    if (max_n_clauses < set->min_n_clauses) {/* The number of rules hitting the corresponding priority is less than the dimension of all associated IDs of the rule */
        return false;/* Return directly, no hits possible */
    }

    /* Traverse through each associated id corresponding to the rule */
    for (c = set->conj; c < &set->conj[set->n]; c++) {/* Traverse through each association match */
        struct conjunctive_match *cm;/* Association Matching */
        uint32_t hash;
        /* If the dimension of the association rule is greater than that of the corresponding priority hit rule, it is not possible to hit, skip directly */
        if (c->n_clauses > max_n_clauses) {
            continue;
        }
       
        hash = hash_int(c->id, 0);/* hash the id and use it to find association matches based on the association id */
        /* matches For a temporary table, the c of the first process of the same associated id is added to the hash table */ 
        cm = find_conjunctive_match__(matches, c->id, hash);
        if (!cm) {/* Not found, instructions need to be added */
            /* Calculate the number of associated IDs that have been temporarily stored, and if it is larger than our local array, you will need to dynamically allocate memory for temporary hash tables */
            size_t n = hmap_count(matches);
            cm = n < n_cm_stubs ? &cm_stubs[n] : xmalloc(sizeof *cm);
            hmap_insert(matches, &cm->hmap_node, hash);/* Insert the new cm into the hash table */
            cm->id = c->id;/* Record id */
            /* Several dimensions move 0xffffffffffffffff ff to the left how many bits, zero the rightmost bits, and then hit,
            ** Hitting a dimension places the bit at 1. Once cm->clauses == 0xffffffffffff, the association match hits.
            */
            cm->clauses = UINT64_MAX << (c->n_clauses & 63);
        }
        /* Set the bit bit bit corresponding to the matching dimension of this association */
        cm->clauses |= UINT64_C(1) << c->clause;
        if (cm->clauses == UINT64_MAX) {/* Once equal to full ff, Association matching hits all */
            *idp = cm->id;/* Returns the association matching id, indicating that two association IDS cannot be set at the same priority */
            return true;
        }
    }
    return false;
}

/* Release memory associated with matches, which releases the temporary table matches in two parts, one part being that the contents of cm_stubs do not need to be released here
** What needs to be freed is dynamically requested memory
*/
static void
free_conjunctive_matches(struct hmap *matches,
                         struct conjunctive_match *cm_stubs, size_t n_cm_stubs)
{
    if (hmap_count(matches) > n_cm_stubs) {/* Memory release is required only if it is larger than our local array */
        struct conjunctive_match *cm, *next;

        HMAP_FOR_EACH_SAFE (cm, next, hmap_node, matches) {
            /* Memory not in the array is dynamically requested for release */
            if (!(cm >= cm_stubs && cm < &cm_stubs[n_cm_stubs])) {
                free(cm);
            }
        }
    }
    hmap_destroy(matches);
}

Posted by CraigRoberts on Sat, 21 Sep 2019 20:04:24 -0700