]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
50f96b10 | 2 | * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
064af421 | 7 | * |
a14bc59f BP |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
064af421 BP |
15 | */ |
16 | ||
17 | #ifndef CLASSIFIER_H | |
18 | #define CLASSIFIER_H 1 | |
19 | ||
20 | /* Flow classifier. | |
21 | * | |
c906cedf BP |
22 | * |
23 | * What? | |
24 | * ===== | |
25 | * | |
26 | * A flow classifier holds any number of "rules", each of which specifies | |
13751fd8 JR |
27 | * values to match for some fields or subfields and a priority. Each OpenFlow |
28 | * table is implemented as a flow classifier. | |
c906cedf | 29 | * |
13751fd8 JR |
30 | * The classifier has two primary design goals. The first is obvious: given a |
31 | * set of packet headers, as quickly as possible find the highest-priority rule | |
32 | * that matches those headers. The following section describes the second | |
33 | * goal. | |
c906cedf BP |
34 | * |
35 | * | |
13751fd8 JR |
36 | * "Un-wildcarding" |
37 | * ================ | |
38 | * | |
39 | * A primary goal of the flow classifier is to produce, as a side effect of a | |
40 | * packet lookup, a wildcard mask that indicates which bits of the packet | |
41 | * headers were essential to the classification result. Ideally, a 1-bit in | |
42 | * any position of this mask means that, if the corresponding bit in the packet | |
43 | * header were flipped, then the classification result might change. A 0-bit | |
44 | * means that changing the packet header bit would have no effect. Thus, the | |
45 | * wildcarded bits are the ones that played no role in the classification | |
46 | * decision. | |
47 | * | |
48 | * Such a wildcard mask is useful with datapaths that support installing flows | |
49 | * that wildcard fields or subfields. If an OpenFlow lookup for a TCP flow | |
50 | * does not actually look at the TCP source or destination ports, for example, | |
51 | * then the switch may install into the datapath a flow that wildcards the port | |
52 | * numbers, which in turn allows the datapath to handle packets that arrive for | |
53 | * other TCP source or destination ports without additional help from | |
54 | * ovs-vswitchd. This is useful for the Open vSwitch software and, | |
55 | * potentially, for ASIC-based switches as well. | |
56 | * | |
57 | * Some properties of the wildcard mask: | |
58 | * | |
59 | * - "False 1-bits" are acceptable, that is, setting a bit in the wildcard | |
60 | * mask to 1 will never cause a packet to be forwarded the wrong way. | |
61 | * As a corollary, a wildcard mask composed of all 1-bits will always | |
62 | * yield correct (but often needlessly inefficient) behavior. | |
63 | * | |
64 | * - "False 0-bits" can cause problems, so they must be avoided. In the | |
65 | * extreme case, a mask of all 0-bits is only correct if the classifier | |
66 | * contains only a single flow that matches all packets. | |
67 | * | |
68 | * - 0-bits are desirable because they allow the datapath to act more | |
69 | * autonomously, relying less on ovs-vswitchd to process flow setups, | |
70 | * thereby improving performance. | |
71 | * | |
72 | * - We don't know a good way to generate wildcard masks with the maximum | |
73 | * (correct) number of 0-bits. We use various approximations, described | |
74 | * in later sections. | |
75 | * | |
76 | * - Wildcard masks for lookups in a given classifier yield a | |
77 | * non-overlapping set of rules. More specifically: | |
78 | * | |
79 | * Consider an classifier C1 filled with an arbitrary collection of rules | |
80 | * and an empty classifier C2. Now take a set of packet headers H and | |
81 | * look it up in C1, yielding a highest-priority matching rule R1 and | |
82 | * wildcard mask M. Form a new classifier rule R2 out of packet headers | |
83 | * H and mask M, and add R2 to C2 with a fixed priority. If one were to | |
84 | * do this for every possible set of packet headers H, then this | |
85 | * process would not attempt to add any overlapping rules to C2, that is, | |
86 | * any packet lookup using the rules generated by this process matches at | |
87 | * most one rule in C2. | |
88 | * | |
89 | * During the lookup process, the classifier starts out with a wildcard mask | |
90 | * that is all 0-bits, that is, fully wildcarded. As lookup proceeds, each | |
91 | * step tends to add constraints to the wildcard mask, that is, change | |
92 | * wildcarded 0-bits into exact-match 1-bits. We call this "un-wildcarding". | |
93 | * A lookup step that examines a particular field must un-wildcard that field. | |
94 | * In general, un-wildcarding is necessary for correctness but undesirable for | |
95 | * performance. | |
96 | * | |
97 | * | |
98 | * Basic Classifier Design | |
99 | * ======================= | |
c906cedf BP |
100 | * |
101 | * Suppose that all the rules in a classifier had the same form. For example, | |
102 | * suppose that they all matched on the source and destination Ethernet address | |
103 | * and wildcarded all the other fields. Then the obvious way to implement a | |
104 | * classifier would be a hash table on the source and destination Ethernet | |
105 | * addresses. If new classification rules came along with a different form, | |
106 | * you could add a second hash table that hashed on the fields matched in those | |
107 | * rules. With two hash tables, you look up a given flow in each hash table. | |
108 | * If there are no matches, the classifier didn't contain a match; if you find | |
109 | * a match in one of them, that's the result; if you find a match in both of | |
110 | * them, then the result is the rule with the higher priority. | |
111 | * | |
112 | * This is how the classifier works. In a "struct classifier", each form of | |
113 | * "struct cls_rule" present (based on its ->match.mask) goes into a separate | |
03868246 JR |
114 | * "struct cls_subtable". A lookup does a hash lookup in every "struct |
115 | * cls_subtable" in the classifier and tracks the highest-priority match that | |
116 | * it finds. The subtables are kept in a descending priority order according | |
117 | * to the highest priority rule in each subtable, which allows lookup to skip | |
13751fd8 JR |
118 | * over subtables that can't possibly have a higher-priority match than already |
119 | * found. Eliminating lookups through priority ordering aids both classifier | |
120 | * primary design goals: skipping lookups saves time and avoids un-wildcarding | |
121 | * fields that those lookups would have examined. | |
c906cedf BP |
122 | * |
123 | * One detail: a classifier can contain multiple rules that are identical other | |
124 | * than their priority. When this happens, only the highest priority rule out | |
125 | * of a group of otherwise identical rules is stored directly in the "struct | |
03868246 JR |
126 | * cls_subtable", with the other almost-identical rules chained off a linked |
127 | * list inside that highest-priority rule. | |
c906cedf | 128 | * |
186120da JR |
129 | * The following sub-sections describe various optimizations over this simple |
130 | * approach. | |
131 | * | |
c906cedf | 132 | * |
13751fd8 | 133 | * Staged Lookup (Wildcard Optimization) |
186120da | 134 | * ------------------------------------- |
476f36e8 JR |
135 | * |
136 | * Subtable lookup is performed in ranges defined for struct flow, starting | |
137 | * from metadata (registers, in_port, etc.), then L2 header, L3, and finally | |
138 | * L4 ports. Whenever it is found that there are no matches in the current | |
13751fd8 JR |
139 | * subtable, the rest of the subtable can be skipped. |
140 | * | |
141 | * Staged lookup does not reduce lookup time, and it may increase it, because | |
142 | * it changes a single hash table lookup into multiple hash table lookups. | |
143 | * It reduces un-wildcarding significantly in important use cases. | |
476f36e8 JR |
144 | * |
145 | * | |
13751fd8 | 146 | * Prefix Tracking (Wildcard Optimization) |
186120da | 147 | * --------------------------------------- |
13751fd8 JR |
148 | * |
149 | * Classifier uses prefix trees ("tries") for tracking the used | |
150 | * address space, enabling skipping classifier tables containing | |
151 | * longer masks than necessary for the given address. This reduces | |
152 | * un-wildcarding for datapath flows in parts of the address space | |
153 | * without host routes, but consulting extra data structures (the | |
154 | * tries) may slightly increase lookup time. | |
155 | * | |
156 | * Trie lookup is interwoven with staged lookup, so that a trie is | |
157 | * searched only when the configured trie field becomes relevant for | |
158 | * the lookup. The trie lookup results are retained so that each trie | |
159 | * is checked at most once for each classifier lookup. | |
160 | * | |
161 | * This implementation tracks the number of rules at each address | |
162 | * prefix for the whole classifier. More aggressive table skipping | |
163 | * would be possible by maintaining lists of tables that have prefixes | |
164 | * at the lengths encountered on tree traversal, or by maintaining | |
165 | * separate tries for subsets of rules separated by metadata fields. | |
166 | * | |
167 | * Prefix tracking is configured via OVSDB "Flow_Table" table, | |
168 | * "fieldspec" column. "fieldspec" is a string map where a "prefix" | |
169 | * key tells which fields should be used for prefix tracking. The | |
170 | * value of the "prefix" key is a comma separated list of field names. | |
171 | * | |
172 | * There is a maximum number of fields that can be enabled for any one | |
173 | * flow table. Currently this limit is 3. | |
174 | * | |
175 | * | |
176 | * Partitioning (Lookup Time and Wildcard Optimization) | |
186120da | 177 | * ---------------------------------------------------- |
c906cedf BP |
178 | * |
179 | * Suppose that a given classifier is being used to handle multiple stages in a | |
180 | * pipeline using "resubmit", with metadata (that is, the OpenFlow 1.1+ field | |
181 | * named "metadata") distinguishing between the different stages. For example, | |
182 | * metadata value 1 might identify ingress rules, metadata value 2 might | |
183 | * identify ACLs, and metadata value 3 might identify egress rules. Such a | |
184 | * classifier is essentially partitioned into multiple sub-classifiers on the | |
185 | * basis of the metadata value. | |
186 | * | |
187 | * The classifier has a special optimization to speed up matching in this | |
188 | * scenario: | |
189 | * | |
03868246 JR |
190 | * - Each cls_subtable that matches on metadata gets a tag derived from the |
191 | * subtable's mask, so that it is likely that each subtable has a unique | |
192 | * tag. (Duplicate tags have a performance cost but do not affect | |
c906cedf BP |
193 | * correctness.) |
194 | * | |
195 | * - For each metadata value matched by any cls_rule, the classifier | |
196 | * constructs a "struct cls_partition" indexed by the metadata value. | |
197 | * The cls_partition has a 'tags' member whose value is the bitwise-OR of | |
03868246 JR |
198 | * the tags of each cls_subtable that contains any rule that matches on |
199 | * the cls_partition's metadata value. In other words, struct | |
200 | * cls_partition associates metadata values with subtables that need to | |
201 | * be checked with flows with that specific metadata value. | |
c906cedf BP |
202 | * |
203 | * Thus, a flow lookup can start by looking up the partition associated with | |
03868246 JR |
204 | * the flow's metadata, and then skip over any cls_subtable whose 'tag' does |
205 | * not intersect the partition's 'tags'. (The flow must also be looked up in | |
206 | * any cls_subtable that doesn't match on metadata. We handle that by giving | |
207 | * any such cls_subtable TAG_ALL as its 'tags' so that it matches any tag.) | |
c906cedf | 208 | * |
13751fd8 JR |
209 | * Partitioning saves lookup time by reducing the number of subtable lookups. |
210 | * Each eliminated subtable lookup also reduces the amount of un-wildcarding. | |
211 | * | |
0b4f2078 | 212 | * |
2b7b1427 JR |
213 | * Classifier Versioning |
214 | * ===================== | |
215 | * | |
216 | * Classifier lookups are always done in a specific classifier version, where | |
217 | * a version is defined to be a natural number. | |
218 | * | |
219 | * When a new rule is added to a classifier, it is set to become visible in a | |
220 | * specific version. If the version number used at insert time is larger than | |
221 | * any version number currently used in lookups, the new rule is said to be | |
222 | * invisible to lookups. This means that lookups won't find the rule, but the | |
223 | * rule is immediately available to classifier iterations. | |
224 | * | |
18721c4a JR |
225 | * Similarly, a rule can be marked as to be deleted in a future version. To |
226 | * delete a rule in a way to not remove the rule before all ongoing lookups are | |
227 | * finished, the rule should be made invisible in a specific version number. | |
2b7b1427 | 228 | * Then, when all the lookups use a later version number, the rule can be |
18721c4a | 229 | * actually removed from the classifier. |
186120da JR |
230 | * |
231 | * Classifiers can hold duplicate rules (rules with the same match criteria and | |
18721c4a JR |
232 | * priority) when at most one of these duplicates is visible in any given |
233 | * lookup version. The caller responsible for classifier modifications must | |
234 | * maintain this invariant. | |
2b7b1427 JR |
235 | * |
236 | * The classifier supports versioning for two reasons: | |
237 | * | |
238 | * 1. Support for versioned modifications makes it possible to perform an | |
239 | * arbitraty series of classifier changes as one atomic transaction, | |
240 | * where intermediate versions of the classifier are not visible to any | |
241 | * lookups. Also, when a rule is added for a future version, or marked | |
242 | * for removal after the current version, such modifications can be | |
243 | * reverted without any visible effects to any of the current lookups. | |
244 | * | |
245 | * 2. Performance: Adding (or deleting) a large set of rules can, in | |
246 | * pathological cases, have a cost proportional to the number of rules | |
247 | * already in the classifier. When multiple rules are being added (or | |
248 | * deleted) in one go, though, this pathological case cost can be | |
249 | * typically avoided, as long as it is OK for any new rules to be | |
250 | * invisible until the batch change is complete. | |
251 | * | |
252 | * Note that the classifier_replace() function replaces a rule immediately, and | |
253 | * is therefore not safe to use with versioning. It is still available for the | |
254 | * users that do not use versioning. | |
255 | * | |
256 | * | |
257 | * Deferred Publication | |
258 | * ==================== | |
259 | * | |
260 | * Removing large number of rules from classifier can be costly, as the | |
261 | * supporting data structures are teared down, in many cases just to be | |
262 | * re-instantiated right after. In the worst case, as when each rule has a | |
263 | * different match pattern (mask), the maintenance of the match patterns can | |
264 | * have cost O(N^2), where N is the number of different match patterns. To | |
265 | * alleviate this, the classifier supports a "deferred mode", in which changes | |
266 | * in internal data structures needed for future version lookups may not be | |
267 | * fully computed yet. The computation is finalized when the deferred mode is | |
268 | * turned off. | |
269 | * | |
270 | * This feature can be used with versioning such that all changes to future | |
271 | * versions are made in the deferred mode. Then, right before making the new | |
272 | * version visible to lookups, the deferred mode is turned off so that all the | |
273 | * data structures are ready for lookups with the new version number. | |
186120da JR |
274 | * |
275 | * To use deferred publication, first call classifier_defer(). Then, modify | |
2b7b1427 JR |
276 | * the classifier via additions (classifier_insert() with a specific, future |
277 | * version number) and deletions (use cls_rule_make_removable_after_version()). | |
278 | * Then call classifier_publish(), and after that, announce the new version | |
279 | * number to be used in lookups. | |
186120da JR |
280 | * |
281 | * | |
0b4f2078 EJ |
282 | * Thread-safety |
283 | * ============= | |
284 | * | |
2b7b1427 JR |
285 | * The classifier may safely be accessed by many reader threads concurrently |
286 | * and by a single writer, or by multiple writers when they guarantee mutually | |
287 | * exlucive access to classifier modifications. | |
288 | * | |
289 | * Since the classifier rules are RCU protected, the rule destruction after | |
290 | * removal from the classifier must be RCU postponed. Also, when versioning is | |
291 | * used, the rule removal itself needs to be typically RCU postponed. In this | |
292 | * case the rule destruction is doubly RCU postponed, i.e., the second | |
293 | * ovsrcu_postpone() call to destruct the rule is called from the first RCU | |
294 | * callback that removes the rule. | |
295 | * | |
296 | * Rules that have never been visible to lookups are an exeption to the above | |
297 | * rule. Such rules can be removed immediately, but their destruction must | |
298 | * still be RCU postponed, as the rule's visibility attribute may be examined | |
299 | * parallel to the rule's removal. */ | |
064af421 | 300 | |
f2c21402 | 301 | #include "cmap.h" |
e29747e4 | 302 | #include "openvswitch/match.h" |
064d7f84 | 303 | #include "openvswitch/meta-flow.h" |
e48eccd1 | 304 | #include "pvector.h" |
de4ad4a2 | 305 | #include "rculist.h" |
ae06a561 | 306 | #include "openvswitch/type-props.h" |
44e0c35d | 307 | #include "versions.h" |
064af421 | 308 | |
43d1478b CB |
309 | #ifdef __cplusplus |
310 | extern "C" { | |
311 | #endif | |
312 | ||
cabd4c43 | 313 | /* Classifier internal data structures. */ |
cabd4c43 | 314 | struct cls_subtable; |
627fb667 JR |
315 | struct cls_match; |
316 | ||
e48eccd1 JR |
317 | struct trie_node; |
318 | typedef OVSRCU_TYPE(struct trie_node *) rcu_trie_ptr; | |
319 | ||
320 | /* Prefix trie for a 'field' */ | |
321 | struct cls_trie { | |
322 | const struct mf_field *field; /* Trie field, or NULL. */ | |
323 | rcu_trie_ptr root; /* NULL if none. */ | |
324 | }; | |
325 | ||
627fb667 | 326 | enum { |
e48eccd1 JR |
327 | CLS_MAX_INDICES = 3, /* Maximum number of lookup indices per subtable. */ |
328 | CLS_MAX_TRIES = 3 /* Maximum number of prefix trees per classifier. */ | |
627fb667 | 329 | }; |
476f36e8 | 330 | |
064af421 BP |
331 | /* A flow classifier. */ |
332 | struct classifier { | |
fccd7c09 | 333 | int n_rules; /* Total number of rules. */ |
e48eccd1 JR |
334 | uint8_t n_flow_segments; |
335 | uint8_t flow_segments[CLS_MAX_INDICES]; /* Flow segment boundaries to use | |
336 | * for staged lookup. */ | |
337 | struct cmap subtables_map; /* Contains "struct cls_subtable"s. */ | |
da9cfca6 | 338 | struct pvector subtables; |
e48eccd1 JR |
339 | struct cmap partitions; /* Contains "struct cls_partition"s. */ |
340 | struct cls_trie tries[CLS_MAX_TRIES]; /* Prefix tries. */ | |
341 | unsigned int n_tries; | |
802f84ff | 342 | bool publish; /* Make changes visible to lookups? */ |
064af421 BP |
343 | }; |
344 | ||
18080541 BP |
345 | struct cls_conjunction { |
346 | uint32_t id; | |
347 | uint8_t clause; | |
348 | uint8_t n_clauses; | |
349 | }; | |
350 | ||
627fb667 | 351 | /* A rule to be inserted to the classifier. */ |
064af421 | 352 | struct cls_rule { |
2b7b1427 JR |
353 | struct rculist node; /* In struct cls_subtable 'rules_list'. */ |
354 | const int priority; /* Larger numbers are higher priorities. */ | |
5e27fe97 JR |
355 | OVSRCU_TYPE(struct cls_match *) cls_match; /* NULL if not in a |
356 | * classifier. */ | |
2b7b1427 | 357 | const struct minimatch match; /* Matching rule. */ |
c906cedf | 358 | }; |
d87091c2 JR |
359 | \f |
360 | /* Constructor/destructor. Must run single-threaded. */ | |
361 | void classifier_init(struct classifier *, const uint8_t *flow_segments); | |
362 | void classifier_destroy(struct classifier *); | |
363 | ||
364 | /* Modifiers. Caller MUST exclude concurrent calls from other threads. */ | |
365 | bool classifier_set_prefix_fields(struct classifier *, | |
366 | const enum mf_field_id *trie_fields, | |
367 | unsigned int n_trie_fields); | |
c906cedf | 368 | |
bd53aa17 | 369 | void cls_rule_init(struct cls_rule *, const struct match *, int priority); |
5cb7a798 | 370 | void cls_rule_init_from_minimatch(struct cls_rule *, const struct minimatch *, |
bd53aa17 | 371 | int priority); |
48d28ac1 | 372 | void cls_rule_clone(struct cls_rule *, const struct cls_rule *); |
b2c1f00b | 373 | void cls_rule_move(struct cls_rule *dst, struct cls_rule *src); |
48d28ac1 | 374 | void cls_rule_destroy(struct cls_rule *); |
18080541 BP |
375 | |
376 | void cls_rule_set_conjunctions(struct cls_rule *, | |
377 | const struct cls_conjunction *, size_t n); | |
2b7b1427 | 378 | void cls_rule_make_invisible_in_version(const struct cls_rule *, |
44e0c35d | 379 | ovs_version_t); |
2b7b1427 | 380 | void cls_rule_restore_visibility(const struct cls_rule *); |
064af421 | 381 | |
18080541 | 382 | void classifier_insert(struct classifier *, const struct cls_rule *, |
44e0c35d | 383 | ovs_version_t, const struct cls_conjunction *, |
bd53aa17 | 384 | size_t n_conjunctions); |
dfea28b3 | 385 | const struct cls_rule *classifier_replace(struct classifier *, |
18080541 | 386 | const struct cls_rule *, |
44e0c35d | 387 | ovs_version_t, |
18080541 BP |
388 | const struct cls_conjunction *, |
389 | size_t n_conjunctions); | |
dfea28b3 JR |
390 | const struct cls_rule *classifier_remove(struct classifier *, |
391 | const struct cls_rule *); | |
802f84ff JR |
392 | static inline void classifier_defer(struct classifier *); |
393 | static inline void classifier_publish(struct classifier *); | |
fccd7c09 JR |
394 | |
395 | /* Lookups. These are RCU protected and may run concurrently with modifiers | |
396 | * and each other. */ | |
dfea28b3 | 397 | const struct cls_rule *classifier_lookup(const struct classifier *, |
44e0c35d | 398 | ovs_version_t, struct flow *, |
dfea28b3 | 399 | struct flow_wildcards *); |
afae68b1 | 400 | bool classifier_rule_overlaps(const struct classifier *, |
44e0c35d | 401 | const struct cls_rule *, ovs_version_t); |
dfea28b3 | 402 | const struct cls_rule *classifier_find_rule_exactly(const struct classifier *, |
bd53aa17 | 403 | const struct cls_rule *, |
44e0c35d | 404 | ovs_version_t); |
dfea28b3 JR |
405 | const struct cls_rule *classifier_find_match_exactly(const struct classifier *, |
406 | const struct match *, | |
2b7b1427 | 407 | int priority, |
44e0c35d | 408 | ovs_version_t); |
fccd7c09 JR |
409 | bool classifier_is_empty(const struct classifier *); |
410 | int classifier_count(const struct classifier *); | |
d87091c2 JR |
411 | |
412 | /* Classifier rule properties. These are RCU protected and may run | |
413 | * concurrently with modifiers and each other. */ | |
414 | bool cls_rule_equal(const struct cls_rule *, const struct cls_rule *); | |
8d8ab6c2 | 415 | void cls_rule_format(const struct cls_rule *, const struct tun_table *, |
50f96b10 | 416 | const struct ofputil_port_map *, struct ds *); |
d87091c2 JR |
417 | bool cls_rule_is_catchall(const struct cls_rule *); |
418 | bool cls_rule_is_loose_match(const struct cls_rule *rule, | |
419 | const struct minimatch *criteria); | |
44e0c35d | 420 | bool cls_rule_visible_in_version(const struct cls_rule *, ovs_version_t); |
5ecc9d81 | 421 | \f |
de4ad4a2 JR |
422 | /* Iteration. |
423 | * | |
424 | * Iteration is lockless and RCU-protected. Concurrent threads may perform all | |
425 | * kinds of concurrent modifications without ruining the iteration. Obviously, | |
426 | * any modifications may or may not be visible to the concurrent iterator, but | |
427 | * all the rules not deleted are visited by the iteration. The iterating | |
428 | * thread may also modify the classifier rules itself. | |
429 | * | |
430 | * 'TARGET' iteration only iterates rules matching the 'TARGET' criteria. | |
431 | * Rather than looping through all the rules and skipping ones that can't | |
432 | * match, 'TARGET' iteration skips whole subtables, if the 'TARGET' happens to | |
433 | * be more specific than the subtable. */ | |
5ecc9d81 | 434 | struct cls_cursor { |
e48eccd1 | 435 | const struct classifier *cls; |
03868246 | 436 | const struct cls_subtable *subtable; |
5ecc9d81 | 437 | const struct cls_rule *target; |
44e0c35d | 438 | ovs_version_t version; /* Version to iterate. */ |
de4ad4a2 | 439 | struct pvector_cursor subtables; |
dfea28b3 | 440 | const struct cls_rule *rule; |
5ecc9d81 BP |
441 | }; |
442 | ||
bd53aa17 JR |
443 | struct cls_cursor cls_cursor_start(const struct classifier *, |
444 | const struct cls_rule *target, | |
44e0c35d | 445 | ovs_version_t); |
78c8df12 | 446 | void cls_cursor_advance(struct cls_cursor *); |
5ecc9d81 | 447 | |
de4ad4a2 | 448 | #define CLS_FOR_EACH(RULE, MEMBER, CLS) \ |
44e0c35d | 449 | CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, NULL, OVS_VERSION_MAX) |
bd53aa17 JR |
450 | #define CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, TARGET, VERSION) \ |
451 | for (struct cls_cursor cursor__ = cls_cursor_start(CLS, TARGET, VERSION); \ | |
78c8df12 | 452 | (cursor__.rule \ |
f17e8ad6 | 453 | ? (INIT_CONTAINER(RULE, cursor__.rule, MEMBER), \ |
78c8df12 BP |
454 | cls_cursor_advance(&cursor__), \ |
455 | true) \ | |
5f0476ce | 456 | : false); \ |
de4ad4a2 | 457 | ) |
5f0476ce | 458 | |
802f84ff JR |
459 | \f |
460 | static inline void | |
461 | classifier_defer(struct classifier *cls) | |
462 | { | |
463 | cls->publish = false; | |
464 | } | |
465 | ||
466 | static inline void | |
467 | classifier_publish(struct classifier *cls) | |
468 | { | |
469 | cls->publish = true; | |
da9cfca6 | 470 | pvector_publish(&cls->subtables); |
802f84ff | 471 | } |
bd53aa17 JR |
472 | |
473 | #ifdef __cplusplus | |
474 | } | |
475 | #endif | |
064af421 | 476 | #endif /* classifier.h */ |