X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fclassifier.c;h=8e5c1a657f2929b7179a913fe6eae5c67c2a6999;hb=refs%2Fheads%2Flts-1.0;hp=11223a8155d918de3f5ca13e3ddd0b0da7bc3fe6;hpb=064af42167bf4fc9aaea2702d80ce08074b889c0;p=sliver-openvswitch.git diff --git a/lib/classifier.c b/lib/classifier.c index 11223a815..8e5c1a657 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -1,17 +1,17 @@ /* - * Copyright (c) 2009 Nicira Networks. + * Copyright (c) 2009, 2010 Nicira Networks. * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * 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: * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * 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 @@ -19,6 +19,7 @@ #include #include #include +#include "dynamic-string.h" #include "flow.h" #include "hash.h" @@ -48,14 +49,16 @@ static struct cls_rule *search_exact_table(const struct classifier *, size_t hash, const flow_t *); static bool rules_match_1wild(const struct cls_rule *fixed, const struct cls_rule *wild, int field_idx); +static bool rules_match_2wild(const struct cls_rule *wild1, + const struct cls_rule *wild2, int field_idx); /* Converts the flow in 'flow' into a cls_rule in 'rule', with the given * 'wildcards' and 'priority'.*/ void -cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow, - uint32_t wildcards, unsigned int priority) +cls_rule_from_flow(const flow_t *flow, uint32_t wildcards, + unsigned int priority, struct cls_rule *rule) { - assert(flow->reserved == 0); + assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]); rule->flow = *flow; flow_wildcards_init(&rule->wc, wildcards); rule->priority = priority; @@ -63,18 +66,32 @@ cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow, } /* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given - * 'priority'. */ + * 'priority'. If 'tun_id_from_cookie' is set then the upper 32 bits of + * 'cookie' are stored in the rule as the tunnel ID. */ void -cls_rule_from_match(struct cls_rule *rule, const struct ofp_match *match, - unsigned int priority) +cls_rule_from_match(const struct ofp_match *match, unsigned int priority, + bool tun_id_from_cookie, uint64_t cookie, + struct cls_rule *rule) { uint32_t wildcards; - flow_from_match(&rule->flow, &wildcards, match); + flow_from_match(match, tun_id_from_cookie, cookie, &rule->flow, &wildcards); flow_wildcards_init(&rule->wc, wildcards); rule->priority = rule->wc.wildcards ? priority : UINT16_MAX; rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards); } +/* Converts 'rule' to a string and returns the string. The caller must free + * the string (with free()). */ +char * +cls_rule_to_string(const struct cls_rule *rule) +{ + struct ds s = DS_EMPTY_INITIALIZER; + ds_put_format(&s, "wildcards=%x priority=%u ", + rule->wc.wildcards, rule->priority); + flow_format(&s, &rule->flow); + return ds_cstr(&s); +} + /* Prints cls_rule 'rule', for debugging. * * (The output could be improved and expanded, but this was good enough to @@ -102,7 +119,8 @@ cls_rule_moved(struct classifier *cls, struct cls_rule *old, if (new->wc.wildcards) { list_moved(&new->node.list); } else { - hmap_moved(&cls->exact_table, &old->node.hmap, &new->node.hmap); + hmap_node_moved(&cls->exact_table, + &old->node.hmap, &new->node.hmap); } } } @@ -289,7 +307,7 @@ classifier_lookup_wild(const struct classifier *cls, const flow_t *flow) struct cls_rule target; int i; - cls_rule_from_flow(&target, flow, 0, 0); + cls_rule_from_flow(flow, 0, 0, &target); for (i = 0; i < CLS_N_FIELDS; i++) { struct cls_rule *rule = search_table(&cls->tables[i], i, &target); if (rule && (!best || rule->priority > best->priority)) { @@ -314,7 +332,7 @@ classifier_find_rule_exactly(const struct classifier *cls, return search_exact_table(cls, flow_hash(target, 0), target); } - assert(wildcards == (wildcards & OFPFW_ALL)); + assert(wildcards == (wildcards & OVSFW_ALL)); table_idx = table_idx_from_wildcards(wildcards); hash = hash_fields(target, table_idx); HMAP_FOR_EACH_WITH_HASH (bucket, struct cls_bucket, hmap_node, hash, @@ -335,6 +353,43 @@ classifier_find_rule_exactly(const struct classifier *cls, return NULL; } +/* Checks if the flow defined by 'target' with 'wildcards' at 'priority' + * overlaps with any other rule at the same priority in the classifier. + * Two rules are considered overlapping if a packet could match both. */ +bool +classifier_rule_overlaps(const struct classifier *cls, + const flow_t *target, uint32_t wildcards, + unsigned int priority) +{ + struct cls_rule target_rule; + const struct hmap *tbl; + + if (!wildcards) { + return search_exact_table(cls, flow_hash(target, 0), target) ? + true : false; + } + + cls_rule_from_flow(target, wildcards, priority, &target_rule); + + for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) { + struct cls_bucket *bucket; + + HMAP_FOR_EACH (bucket, struct cls_bucket, hmap_node, tbl) { + struct cls_rule *rule; + + LIST_FOR_EACH (rule, struct cls_rule, node.list, + &bucket->rules) { + if (rule->priority == priority + && rules_match_2wild(rule, &target_rule, 0)) { + return true; + } + } + } + } + + return false; +} + /* Ignores target->priority. * * 'callback' is allowed to delete the rule that is passed as its argument, but @@ -410,7 +465,10 @@ classifier_for_each_match(const struct classifier *cls, * it must not delete (or move) any other rules in 'cls' that are in the same * table as the argument rule. Two rules are in the same table if their * cls_rule structs have the same table_idx; as a special case, a rule with - * wildcards and an exact-match rule will never be in the same table. */ + * wildcards and an exact-match rule will never be in the same table. + * + * If 'include' is CLS_INC_EXACT then CLASSIFIER_FOR_EACH_EXACT_RULE(_SAFE) is + * probably easier to use. */ void classifier_for_each(const struct classifier *cls, int include, void (*callback)(struct cls_rule *, void *aux), @@ -587,14 +645,14 @@ bucket_insert(struct cls_bucket *bucket, struct cls_rule *rule) { struct cls_rule *pos; LIST_FOR_EACH (pos, struct cls_rule, node.list, &bucket->rules) { - if (pos->priority <= rule->priority) { - if (pos->priority == rule->priority - && pos->wc.wildcards == rule->wc.wildcards + if (pos->priority == rule->priority) { + if (pos->wc.wildcards == rule->wc.wildcards && rules_match_1wild(pos, rule, rule->table_idx)) { list_replace(&rule->node.list, &pos->node.list); return pos; } + } else if (pos->priority < rule->priority) { break; } } @@ -763,6 +821,23 @@ rules_match_1wild(const struct cls_rule *fixed, const struct cls_rule *wild, wild->wc.nw_dst_mask, field_idx); } +/* Returns true if 'wild1' and 'wild2' match, that is, if their fields + * are equal modulo wildcards in 'wild1' or 'wild2'. + * + * 'field_idx' is the index of the first field to be compared; fields before + * 'field_idx' are assumed to match. Always returns true if 'field_idx' is + * CLS_N_FIELDS. */ +static bool +rules_match_2wild(const struct cls_rule *wild1, const struct cls_rule *wild2, + int field_idx) +{ + return rules_match(wild1, wild2, + wild1->wc.wildcards | wild2->wc.wildcards, + wild1->wc.nw_src_mask & wild2->wc.nw_src_mask, + wild1->wc.nw_dst_mask & wild2->wc.nw_dst_mask, + field_idx); +} + /* Searches 'bucket' for a rule that matches 'target'. Returns the * highest-priority match, if one is found, or a null pointer if there is no * match.