]> git.proxmox.com Git - ovs.git/blob - lib/classifier-private.h
classifier: Simplify versioning.
[ovs.git] / lib / classifier-private.h
1 /*
2 * Copyright (c) 2014, 2015 Nicira, Inc.
3 *
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:
7 *
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.
15 */
16
17 #ifndef CLASSIFIER_PRIVATE_H
18 #define CLASSIFIER_PRIVATE_H 1
19
20 #include "cmap.h"
21 #include "flow.h"
22 #include "hash.h"
23 #include "rculist.h"
24 #include "tag.h"
25
26 /* Classifier internal definitions, subject to change at any time. */
27
28 /* A set of rules that all have the same fields wildcarded. */
29 struct cls_subtable {
30 struct cmap_node cmap_node; /* Within classifier's 'subtables_map'. */
31
32 /* These fields are only used by writers. */
33 int max_priority; /* Max priority of any rule in subtable. */
34 unsigned int max_count; /* Count of max_priority rules. */
35
36 /* Accessed by iterators. */
37 struct rculist rules_list; /* Unordered. */
38
39 /* Identical, but lower priority rules are not inserted to any of the
40 * following data structures. */
41
42 /* These fields are accessed by readers who care about wildcarding. */
43 const tag_type tag; /* Tag generated from mask for partitioning. */
44 const uint8_t n_indices; /* How many indices to use. */
45 const uint8_t index_ofs[CLS_MAX_INDICES]; /* u64 segment boundaries. */
46 unsigned int trie_plen[CLS_MAX_TRIES]; /* Trie prefix length in 'mask'
47 * (runtime configurable). */
48 const int ports_mask_len;
49 struct cmap indices[CLS_MAX_INDICES]; /* Staged lookup indices. */
50 rcu_trie_ptr ports_trie; /* NULL if none. */
51
52 /* These fields are accessed by all readers. */
53 struct cmap rules; /* Contains 'cls_match'es. */
54 const struct minimask mask; /* Wildcards for fields. */
55 /* 'mask' must be the last field. */
56 };
57
58 /* Associates a metadata value (that is, a value of the OpenFlow 1.1+ metadata
59 * field) with tags for the "cls_subtable"s that contain rules that match that
60 * metadata value. */
61 struct cls_partition {
62 struct cmap_node cmap_node; /* In struct classifier's 'partitions' map. */
63 ovs_be64 metadata; /* metadata value for this partition. */
64 tag_type tags; /* OR of each flow's cls_subtable tag. */
65 struct tag_tracker tracker; /* Tracks the bits in 'tags'. */
66 };
67
68 /* Internal representation of a rule in a "struct cls_subtable".
69 *
70 * The 'next' member is an element in a singly linked, null-terminated list.
71 * This list links together identical "cls_match"es in order of decreasing
72 * priority. The classifier code maintains the invariant that at most one rule
73 * of a given priority is visible for any given lookup version.
74 */
75 struct cls_match {
76 /* Accessed by everybody. */
77 OVSRCU_TYPE(struct cls_match *) next; /* Equal, lower-priority matches. */
78 OVSRCU_TYPE(struct cls_conjunction_set *) conj_set;
79
80 /* Accessed only by writers. */
81 struct cls_partition *partition;
82
83 /* Accessed by readers interested in wildcarding. */
84 const int priority; /* Larger numbers are higher priorities. */
85 struct cmap_node index_nodes[CLS_MAX_INDICES]; /* Within subtable's
86 * 'indices'. */
87 /* Accessed by all readers. */
88 struct cmap_node cmap_node; /* Within struct cls_subtable 'rules'. */
89
90 /* Rule versioning.
91 *
92 * CLS_NOT_REMOVED_VERSION has a special meaning for 'remove_version',
93 * meaningthat the rule has been added but not yet removed.
94 */
95 const cls_version_t add_version; /* Version rule was added in. */
96 ATOMIC(cls_version_t) remove_version; /* Version rule is removed in. */
97
98 const struct cls_rule *cls_rule;
99 const struct miniflow flow; /* Matching rule. Mask is in the subtable. */
100 /* 'flow' must be the last field. */
101 };
102
103 /* Must be RCU postponed. */
104 void cls_match_free_cb(struct cls_match *);
105
106 static inline void
107 cls_match_set_remove_version(struct cls_match *rule, cls_version_t version)
108 {
109 atomic_store_relaxed(&rule->remove_version, version);
110 }
111
112 static inline bool
113 cls_match_visible_in_version(const struct cls_match *rule,
114 cls_version_t version)
115 {
116 cls_version_t remove_version;
117
118 /* C11 does not want to access an atomic via a const object pointer. */
119 atomic_read_relaxed(&CONST_CAST(struct cls_match *, rule)->remove_version,
120 &remove_version);
121
122 return rule->add_version <= version && version < remove_version;
123 }
124
125 static inline bool
126 cls_match_is_eventually_invisible(const struct cls_match *rule)
127 {
128 cls_version_t remove_version;
129
130 /* C11 does not want to access an atomic via a const object pointer. */
131 atomic_read_relaxed(&CONST_CAST(struct cls_match *, rule)->remove_version,
132 &remove_version);
133
134 return remove_version <= CLS_MAX_VERSION;
135 }
136
137 \f
138 /* cls_match 'next' */
139
140 static inline const struct cls_match *
141 cls_match_next(const struct cls_match *rule)
142 {
143 return ovsrcu_get(struct cls_match *, &rule->next);
144 }
145
146 static inline struct cls_match *
147 cls_match_next_protected(const struct cls_match *rule)
148 {
149 return ovsrcu_get_protected(struct cls_match *, &rule->next);
150 }
151
152 /* Puts 'rule' in the position between 'prev' and 'next'. If 'prev' == NULL,
153 * then the 'rule' is the new list head, and if 'next' == NULL, the rule is the
154 * new list tail.
155 * If there are any nodes between 'prev' and 'next', they are dropped from the
156 * list. */
157 static inline void
158 cls_match_insert(struct cls_match *prev, struct cls_match *next,
159 struct cls_match *rule)
160 {
161 ovsrcu_set_hidden(&rule->next, next);
162
163 if (prev) {
164 ovsrcu_set(&prev->next, rule);
165 }
166 }
167
168 /* Puts 'new_rule' in the position of 'old_rule', which is the next node after
169 * 'prev'. If 'prev' == NULL, then the 'new_rule' is the new list head.
170 *
171 * The replaced cls_match still links to the later rules, and may still be
172 * referenced by other threads until all other threads quiesce. The replaced
173 * rule may not be re-inserted, re-initialized, or deleted until after all
174 * other threads have quiesced (use ovsrcu_postpone). */
175 static inline void
176 cls_match_replace(struct cls_match *prev,
177 struct cls_match *old_rule, struct cls_match *new_rule)
178 {
179 cls_match_insert(prev, cls_match_next_protected(old_rule), new_rule);
180 }
181
182 /* Removes 'rule' following 'prev' from the list. If 'prev' is NULL, then the
183 * 'rule' is a list head, and the caller is responsible for maintaining its
184 * list head pointer (if any).
185 *
186 * Afterward, the removed rule is not linked to any more, but still links to
187 * the following rules, and may still be referenced by other threads until all
188 * other threads quiesce. The removed rule may not be re-inserted,
189 * re-initialized, or deleted until after all other threads have quiesced (use
190 * ovsrcu_postpone).
191 */
192 static inline void
193 cls_match_remove(struct cls_match *prev, struct cls_match *rule)
194 {
195 if (prev) {
196 ovsrcu_set(&prev->next, cls_match_next_protected(rule));
197 }
198 }
199
200 #define CLS_MATCH_FOR_EACH(ITER, HEAD) \
201 for ((ITER) = (HEAD); (ITER); (ITER) = cls_match_next(ITER))
202
203 #define CLS_MATCH_FOR_EACH_AFTER_HEAD(ITER, HEAD) \
204 CLS_MATCH_FOR_EACH(ITER, cls_match_next(HEAD))
205
206 /* Iterate cls_matches keeping the previous pointer for modifications. */
207 #define FOR_EACH_RULE_IN_LIST_PROTECTED(ITER, PREV, HEAD) \
208 for ((PREV) = NULL, (ITER) = (HEAD); \
209 (ITER); \
210 (PREV) = (ITER), (ITER) = cls_match_next_protected(ITER))
211
212 \f
213 /* A longest-prefix match tree. */
214 struct trie_node {
215 uint32_t prefix; /* Prefix bits for this node, MSB first. */
216 uint8_t n_bits; /* Never zero, except for the root node. */
217 unsigned int n_rules; /* Number of rules that have this prefix. */
218 rcu_trie_ptr edges[2]; /* Both NULL if leaf. */
219 };
220
221 /* Max bits per node. Must fit in struct trie_node's 'prefix'.
222 * Also tested with 16, 8, and 5 to stress the implementation. */
223 #define TRIE_PREFIX_BITS 32
224 \f
225 /* flow/miniflow/minimask/minimatch utilities.
226 * These are only used by the classifier, so place them here to allow
227 * for better optimization. */
228
229 static inline uint64_t
230 miniflow_get_map_in_range(const struct miniflow *miniflow,
231 uint8_t start, uint8_t end, unsigned int *offset)
232 {
233 uint64_t map = miniflow->map;
234 *offset = 0;
235
236 if (start > 0) {
237 uint64_t msk = (UINT64_C(1) << start) - 1; /* 'start' LSBs set */
238 *offset = count_1bits(map & msk);
239 map &= ~msk;
240 }
241 if (end < FLOW_U64S) {
242 uint64_t msk = (UINT64_C(1) << end) - 1; /* 'end' LSBs set */
243 map &= msk;
244 }
245 return map;
246 }
247
248 /* Returns a hash value for the bits of 'flow' where there are 1-bits in
249 * 'mask', given 'basis'.
250 *
251 * The hash values returned by this function are the same as those returned by
252 * miniflow_hash_in_minimask(), only the form of the arguments differ. */
253 static inline uint32_t
254 flow_hash_in_minimask(const struct flow *flow, const struct minimask *mask,
255 uint32_t basis)
256 {
257 const uint64_t *mask_values = miniflow_get_values(&mask->masks);
258 const uint64_t *flow_u64 = (const uint64_t *)flow;
259 const uint64_t *p = mask_values;
260 uint32_t hash;
261 int idx;
262
263 hash = basis;
264 MAP_FOR_EACH_INDEX(idx, mask->masks.map) {
265 hash = hash_add64(hash, flow_u64[idx] & *p++);
266 }
267
268 return hash_finish(hash, (p - mask_values) * 8);
269 }
270
271 /* Returns a hash value for the bits of 'flow' where there are 1-bits in
272 * 'mask', given 'basis'.
273 *
274 * The hash values returned by this function are the same as those returned by
275 * flow_hash_in_minimask(), only the form of the arguments differ. */
276 static inline uint32_t
277 miniflow_hash_in_minimask(const struct miniflow *flow,
278 const struct minimask *mask, uint32_t basis)
279 {
280 const uint64_t *mask_values = miniflow_get_values(&mask->masks);
281 const uint64_t *p = mask_values;
282 uint32_t hash = basis;
283 uint64_t flow_u64;
284
285 MINIFLOW_FOR_EACH_IN_MAP(flow_u64, flow, mask->masks.map) {
286 hash = hash_add64(hash, flow_u64 & *p++);
287 }
288
289 return hash_finish(hash, (p - mask_values) * 8);
290 }
291
292 /* Returns a hash value for the bits of range [start, end) in 'flow',
293 * where there are 1-bits in 'mask', given 'hash'.
294 *
295 * The hash values returned by this function are the same as those returned by
296 * minimatch_hash_range(), only the form of the arguments differ. */
297 static inline uint32_t
298 flow_hash_in_minimask_range(const struct flow *flow,
299 const struct minimask *mask,
300 uint8_t start, uint8_t end, uint32_t *basis)
301 {
302 const uint64_t *mask_values = miniflow_get_values(&mask->masks);
303 const uint64_t *flow_u64 = (const uint64_t *)flow;
304 unsigned int offset;
305 uint64_t map;
306 const uint64_t *p;
307 uint32_t hash = *basis;
308 int idx;
309
310 map = miniflow_get_map_in_range(&mask->masks, start, end, &offset);
311 p = mask_values + offset;
312 MAP_FOR_EACH_INDEX(idx, map) {
313 hash = hash_add64(hash, flow_u64[idx] & *p++);
314 }
315
316 *basis = hash; /* Allow continuation from the unfinished value. */
317 return hash_finish(hash, (p - mask_values) * 8);
318 }
319
320 /* Fold minimask 'mask''s wildcard mask into 'wc's wildcard mask. */
321 static inline void
322 flow_wildcards_fold_minimask(struct flow_wildcards *wc,
323 const struct minimask *mask)
324 {
325 flow_union_with_miniflow(&wc->masks, &mask->masks);
326 }
327
328 /* Fold minimask 'mask''s wildcard mask into 'wc's wildcard mask
329 * in range [start, end). */
330 static inline void
331 flow_wildcards_fold_minimask_range(struct flow_wildcards *wc,
332 const struct minimask *mask,
333 uint8_t start, uint8_t end)
334 {
335 uint64_t *dst_u64 = (uint64_t *)&wc->masks;
336 unsigned int offset;
337 uint64_t map;
338 const uint64_t *p;
339 int idx;
340
341 map = miniflow_get_map_in_range(&mask->masks, start, end, &offset);
342 p = miniflow_get_values(&mask->masks) + offset;
343 MAP_FOR_EACH_INDEX(idx, map) {
344 dst_u64[idx] |= *p++;
345 }
346 }
347
348 /* Returns a hash value for 'flow', given 'basis'. */
349 static inline uint32_t
350 miniflow_hash(const struct miniflow *flow, uint32_t basis)
351 {
352 const uint64_t *values = miniflow_get_values(flow);
353 const uint64_t *p = values;
354 uint32_t hash = basis;
355 uint64_t hash_map = 0;
356 uint64_t map;
357
358 for (map = flow->map; map; map = zero_rightmost_1bit(map)) {
359 if (*p) {
360 hash = hash_add64(hash, *p);
361 hash_map |= rightmost_1bit(map);
362 }
363 p++;
364 }
365 hash = hash_add64(hash, hash_map);
366
367 return hash_finish(hash, p - values);
368 }
369
370 /* Returns a hash value for 'mask', given 'basis'. */
371 static inline uint32_t
372 minimask_hash(const struct minimask *mask, uint32_t basis)
373 {
374 return miniflow_hash(&mask->masks, basis);
375 }
376
377 /* Returns a hash value for 'match', given 'basis'. */
378 static inline uint32_t
379 minimatch_hash(const struct minimatch *match, uint32_t basis)
380 {
381 return miniflow_hash(&match->flow, minimask_hash(&match->mask, basis));
382 }
383
384 /* Returns a hash value for the bits of range [start, end) in 'minimatch',
385 * given 'basis'.
386 *
387 * The hash values returned by this function are the same as those returned by
388 * flow_hash_in_minimask_range(), only the form of the arguments differ. */
389 static inline uint32_t
390 minimatch_hash_range(const struct minimatch *match, uint8_t start, uint8_t end,
391 uint32_t *basis)
392 {
393 unsigned int offset;
394 const uint64_t *p, *q;
395 uint32_t hash = *basis;
396 int n, i;
397
398 n = count_1bits(miniflow_get_map_in_range(&match->mask.masks, start, end,
399 &offset));
400 q = miniflow_get_values(&match->mask.masks) + offset;
401 p = miniflow_get_values(&match->flow) + offset;
402
403 for (i = 0; i < n; i++) {
404 hash = hash_add64(hash, p[i] & q[i]);
405 }
406 *basis = hash; /* Allow continuation from the unfinished value. */
407 return hash_finish(hash, (offset + n) * 8);
408 }
409
410 #endif