X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fclassifier.c;h=31a0e8b368382224705513d0f681aa8339f76b09;hb=cfc50ae514f805dcd9c14589f21158185424daf6;hp=1675283a9f5008a48e841b3b3d00de4b4c66618c;hpb=13751fd88c4b7464f9453c03659201c10b3b87a0;p=sliver-openvswitch.git diff --git a/lib/classifier.c b/lib/classifier.c index 1675283a9..31a0e8b36 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -176,7 +176,7 @@ classifier_init(struct classifier *cls, const uint8_t *flow_segments) hmap_init(&cls->subtables); list_init(&cls->subtables_priority); hmap_init(&cls->partitions); - ovs_rwlock_init(&cls->rwlock); + fat_rwlock_init(&cls->rwlock); cls->n_flow_segments = 0; if (flow_segments) { while (cls->n_flow_segments < CLS_MAX_INDICES @@ -213,7 +213,7 @@ classifier_destroy(struct classifier *cls) free(partition); } hmap_destroy(&cls->partitions); - ovs_rwlock_destroy(&cls->rwlock); + fat_rwlock_destroy(&cls->rwlock); } } @@ -312,7 +312,7 @@ static uint32_t hash_metadata(ovs_be64 metadata_) { uint64_t metadata = (OVS_FORCE uint64_t) metadata_; - return hash_2words(metadata, metadata >> 32); + return hash_uint64(metadata); } static struct cls_partition * @@ -566,6 +566,68 @@ classifier_lookup(const struct classifier *cls, const struct flow *flow, return best; } +/* Returns true if 'target' satisifies 'match', that is, if each bit for which + * 'match' specifies a particular value has the correct value in 'target'. */ +static bool +minimatch_matches_miniflow(const struct minimatch *match, + const struct miniflow *target) +{ + const uint32_t *flowp = (const uint32_t *)match->flow.values; + const uint32_t *maskp = (const uint32_t *)match->mask.masks.values; + uint32_t target_u32; + + MINIFLOW_FOR_EACH_IN_MAP(target_u32, target, match->mask.masks.map) { + if ((*flowp++ ^ target_u32) & *maskp++) { + return false; + } + } + + return true; +} + +static inline struct cls_rule * +find_match_miniflow(const struct cls_subtable *subtable, + const struct miniflow *flow, + uint32_t hash) +{ + struct cls_rule *rule; + + HMAP_FOR_EACH_WITH_HASH (rule, hmap_node, hash, &subtable->rules) { + if (minimatch_matches_miniflow(&rule->match, flow)) { + return rule; + } + } + + return NULL; +} + +/* Finds and returns the highest-priority rule in 'cls' that matches + * 'miniflow'. Returns a null pointer if no rules in 'cls' match 'flow'. + * If multiple rules of equal priority match 'flow', returns one arbitrarily. + * + * This function is optimized for the userspace datapath, which only ever has + * one priority value for it's flows! + */ +struct cls_rule *classifier_lookup_miniflow_first(const struct classifier *cls, + const struct miniflow *flow) +{ + struct cls_subtable *subtable; + + LIST_FOR_EACH (subtable, list_node, &cls->subtables_priority) { + struct cls_rule *rule; + + rule = find_match_miniflow(subtable, flow, + miniflow_hash_in_minimask(flow, + &subtable->mask, + 0)); + if (rule) { + return rule; + } + } + + return NULL; +} + /* Finds and returns a rule in 'cls' with exactly the same priority and * matching criteria as 'target'. Returns a null pointer if 'cls' doesn't * contain an exact match. */