blob: 3970e760cbefff9d294343d65c5850cd8855e38b [file] [log] [blame]
Carmelo Cascone1022a4e2017-05-25 00:16:18 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Cascone1022a4e2017-05-25 00:16:18 -04003 *
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
17package org.onosproject.net.flow.criteria;
18
19import com.google.common.annotations.Beta;
20import com.google.common.base.Objects;
Carmelo Cascone32a01b22017-07-18 10:51:07 -040021import com.google.common.collect.ImmutableMap;
Carmelo Cascone87892e22017-11-13 16:01:29 -080022import org.onosproject.net.pi.model.PiMatchFieldId;
Carmelo Cascone32a01b22017-07-18 10:51:07 -040023import org.onosproject.net.pi.runtime.PiExactFieldMatch;
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040024import org.onosproject.net.pi.runtime.PiFieldMatch;
Frank Wangdf383212017-06-23 09:17:41 +080025import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
Daniele Morocdac24f2020-12-18 10:55:57 +010026import org.onosproject.net.pi.runtime.PiOptionalFieldMatch;
Frank Wangdf383212017-06-23 09:17:41 +080027import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
Carmelo Cascone32a01b22017-07-18 10:51:07 -040028import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040029
30import java.util.Collection;
Carmelo Cascone32a01b22017-07-18 10:51:07 -040031import java.util.Optional;
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040032import java.util.StringJoiner;
33
Frank Wangdf383212017-06-23 09:17:41 +080034import static com.google.common.base.Preconditions.checkArgument;
35import static org.onlab.util.ImmutableByteSequence.copyFrom;
36
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040037/**
Carmelo Cascone22619172017-07-13 16:08:17 -040038 * Protocol-independent criterion.
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040039 */
40@Beta
41public final class PiCriterion implements Criterion {
42
Carmelo Cascone87892e22017-11-13 16:01:29 -080043 private final ImmutableMap<PiMatchFieldId, PiFieldMatch> fieldMatchMap;
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040044
45 /**
46 * Creates a new protocol-independent criterion for the given match fields.
47 *
Carmelo Cascone32a01b22017-07-18 10:51:07 -040048 * @param fieldMatchMap field match map
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040049 */
Carmelo Cascone87892e22017-11-13 16:01:29 -080050 private PiCriterion(ImmutableMap<PiMatchFieldId, PiFieldMatch> fieldMatchMap) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -040051 this.fieldMatchMap = fieldMatchMap;
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040052 }
53
54 /**
Carmelo Cascone32a01b22017-07-18 10:51:07 -040055 * Returns all protocol-independent field matches defined by this criterion.
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040056 *
Carmelo Cascone32a01b22017-07-18 10:51:07 -040057 * @return collection of match parameters
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040058 */
59 public Collection<PiFieldMatch> fieldMatches() {
Carmelo Cascone32a01b22017-07-18 10:51:07 -040060 return fieldMatchMap.values();
61 }
62
63 /**
64 * If present, returns the field match associated with the given header field identifier.
65 *
66 * @param fieldId field identifier
67 * @return optional field match
68 */
Carmelo Cascone87892e22017-11-13 16:01:29 -080069 public Optional<PiFieldMatch> fieldMatch(PiMatchFieldId fieldId) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -040070 return Optional.ofNullable(fieldMatchMap.get(fieldId));
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040071 }
72
73 @Override
74 public Type type() {
75 return Type.PROTOCOL_INDEPENDENT;
76 }
77
78 @Override
79 public boolean equals(Object o) {
80 if (this == o) {
81 return true;
82 }
83 if (o == null || getClass() != o.getClass()) {
84 return false;
85 }
86 PiCriterion that = (PiCriterion) o;
Carmelo Cascone32a01b22017-07-18 10:51:07 -040087 return Objects.equal(fieldMatchMap, that.fieldMatchMap);
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040088 }
89
90 @Override
91 public int hashCode() {
Carmelo Cascone32a01b22017-07-18 10:51:07 -040092 return Objects.hashCode(fieldMatchMap);
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040093 }
94
95 @Override
96 public String toString() {
Carmelo Cascone0316b962018-04-11 17:39:07 -070097 StringJoiner stringParams = new StringJoiner(", ");
Carmelo Cascone32a01b22017-07-18 10:51:07 -040098 fieldMatchMap.forEach((key, value) -> stringParams.add(value.toString()));
Carmelo Cascone1022a4e2017-05-25 00:16:18 -040099 return stringParams.toString();
100 }
Frank Wangdf383212017-06-23 09:17:41 +0800101
102 /**
103 * Returns the PiCriterion builder.
104 *
105 * @return PiCriterion builder
106 */
107 public static Builder builder() {
108 return new Builder();
109 }
110
111 /**
pierventre6fa8cd62020-10-08 17:21:49 +0200112 * Returns the PiCriterion builder initialized by the given PiCriterion.
113 *
114 * @param piCriterion the input PiCriterion
115 * @return PiCriterion builder
116 */
117 public static Builder builder(PiCriterion piCriterion) {
118 return new Builder(piCriterion);
119 }
120
121 /**
Frank Wangdf383212017-06-23 09:17:41 +0800122 * PiCriterion Builder.
123 */
124 @Beta
125 public static final class Builder {
126
Carmelo Cascone22619172017-07-13 16:08:17 -0400127 // Use map to guarantee that there's only one field match per field id.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800128 private final ImmutableMap.Builder<PiMatchFieldId, PiFieldMatch> fieldMatchMapBuilder = ImmutableMap.builder();
Frank Wangdf383212017-06-23 09:17:41 +0800129
130 private Builder() {
131 // ban constructor.
132 }
133
pierventre6fa8cd62020-10-08 17:21:49 +0200134 private Builder(PiCriterion piCriterion) {
135 piCriterion.fieldMatchMap.forEach(((piMatchFieldId, piFieldMatch) -> add(piFieldMatch)));
136 }
137
138 /**
139 * Adds a match field to the builder.
140 *
141 * @param field the field value
142 * @return this
143 */
144 public Builder add(PiFieldMatch field) {
145 fieldMatchMapBuilder.put(field.fieldId(), field);
146 return this;
147 }
148
Frank Wangdf383212017-06-23 09:17:41 +0800149 /**
150 * Adds an exact field match for the given fieldId and value.
151 *
152 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400153 * @param value exact match value
Frank Wangdf383212017-06-23 09:17:41 +0800154 * @return this
155 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800156 public Builder matchExact(PiMatchFieldId fieldId, short value) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400157 fieldMatchMapBuilder.put(fieldId, new PiExactFieldMatch(fieldId, copyFrom(value)));
Frank Wangdf383212017-06-23 09:17:41 +0800158 return this;
159 }
160
161 /**
162 * Adds an exact field match for the given fieldId and value.
163 *
164 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400165 * @param value exact match value
Frank Wangdf383212017-06-23 09:17:41 +0800166 * @return this
167 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800168 public Builder matchExact(PiMatchFieldId fieldId, int value) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400169 fieldMatchMapBuilder.put(fieldId, new PiExactFieldMatch(fieldId, copyFrom(value)));
Frank Wangdf383212017-06-23 09:17:41 +0800170 return this;
171 }
172
173 /**
174 * Adds an exact field match for the given fieldId and value.
175 *
176 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400177 * @param value exact match value
Frank Wangdf383212017-06-23 09:17:41 +0800178 * @return this
179 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800180 public Builder matchExact(PiMatchFieldId fieldId, long value) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400181 fieldMatchMapBuilder.put(fieldId, new PiExactFieldMatch(fieldId, copyFrom(value)));
Frank Wangdf383212017-06-23 09:17:41 +0800182 return this;
183 }
184
185 /**
186 * Adds an exact field match for the given fieldId and value.
187 *
188 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400189 * @param value exact match value
Frank Wangdf383212017-06-23 09:17:41 +0800190 * @return this
191 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800192 public Builder matchExact(PiMatchFieldId fieldId, byte[] value) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400193 fieldMatchMapBuilder.put(fieldId, new PiExactFieldMatch(fieldId, copyFrom(value)));
Frank Wangdf383212017-06-23 09:17:41 +0800194 return this;
195 }
196
197 /**
198 * Adds a ternary field match for the given fieldId, value and mask.
199 *
200 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400201 * @param value ternary match value
202 * @param mask ternary match mask
Frank Wangdf383212017-06-23 09:17:41 +0800203 * @return this
204 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800205 public Builder matchTernary(PiMatchFieldId fieldId, short value, short mask) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400206 fieldMatchMapBuilder.put(fieldId, new PiTernaryFieldMatch(fieldId, copyFrom(value), copyFrom(mask)));
Frank Wangdf383212017-06-23 09:17:41 +0800207 return this;
208 }
209
210 /**
211 * Adds a ternary field match for the given fieldId, value and mask.
212 *
213 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400214 * @param value ternary match value
215 * @param mask ternary match mask
Frank Wangdf383212017-06-23 09:17:41 +0800216 * @return this
217 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800218 public Builder matchTernary(PiMatchFieldId fieldId, int value, int mask) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400219 fieldMatchMapBuilder.put(fieldId, new PiTernaryFieldMatch(fieldId, copyFrom(value), copyFrom(mask)));
Frank Wangdf383212017-06-23 09:17:41 +0800220 return this;
221 }
222
223 /**
224 * Adds a ternary field match for the given fieldId, value and mask.
225 *
226 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400227 * @param value ternary match value
228 * @param mask ternary match mask
Frank Wangdf383212017-06-23 09:17:41 +0800229 * @return this
230 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800231 public Builder matchTernary(PiMatchFieldId fieldId, long value, long mask) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400232 fieldMatchMapBuilder.put(fieldId, new PiTernaryFieldMatch(fieldId, copyFrom(value), copyFrom(mask)));
Frank Wangdf383212017-06-23 09:17:41 +0800233 return this;
234 }
235
236 /**
237 * Adds a ternary field match for the given fieldId, value and mask.
238 *
239 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400240 * @param value ternary match value
241 * @param mask ternary match mask
Frank Wangdf383212017-06-23 09:17:41 +0800242 * @return this
243 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800244 public Builder matchTernary(PiMatchFieldId fieldId, byte[] value, byte[] mask) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400245 fieldMatchMapBuilder.put(fieldId, new PiTernaryFieldMatch(fieldId, copyFrom(value), copyFrom(mask)));
Frank Wangdf383212017-06-23 09:17:41 +0800246 return this;
247 }
248
249 /**
250 * Adds a longest-prefix field match for the given fieldId, value and prefix length.
251 *
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400252 * @param fieldId protocol-independent header field Id
253 * @param value lpm match value
Frank Wangdf383212017-06-23 09:17:41 +0800254 * @param prefixLength lpm match prefix length
255 * @return this
256 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800257 public Builder matchLpm(PiMatchFieldId fieldId, short value, int prefixLength) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400258 fieldMatchMapBuilder.put(fieldId, new PiLpmFieldMatch(fieldId, copyFrom(value), prefixLength));
Frank Wangdf383212017-06-23 09:17:41 +0800259 return this;
260 }
261
262 /**
263 * Adds a longest-prefix field match for the given fieldId, value and prefix length.
264 *
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400265 * @param fieldId protocol-independent header field Id
266 * @param value lpm match value
Frank Wangdf383212017-06-23 09:17:41 +0800267 * @param prefixLength lpm match prefix length
268 * @return this
269 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800270 public Builder matchLpm(PiMatchFieldId fieldId, int value, int prefixLength) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400271 fieldMatchMapBuilder.put(fieldId, new PiLpmFieldMatch(fieldId, copyFrom(value), prefixLength));
Frank Wangdf383212017-06-23 09:17:41 +0800272 return this;
273 }
274
275 /**
276 * Adds a longest-prefix field match for the given fieldId, value and prefix length.
277 *
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400278 * @param fieldId protocol-independent header field Id
279 * @param value lpm match value
Frank Wangdf383212017-06-23 09:17:41 +0800280 * @param prefixLength lpm match prefix length
281 * @return this
282 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800283 public Builder matchLpm(PiMatchFieldId fieldId, long value, int prefixLength) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400284 fieldMatchMapBuilder.put(fieldId, new PiLpmFieldMatch(fieldId, copyFrom(value), prefixLength));
Frank Wangdf383212017-06-23 09:17:41 +0800285 return this;
286 }
287
288 /**
289 * Adds a longest-prefix field match for the given fieldId, value and prefix length.
290 *
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400291 * @param fieldId protocol-independent header field Id
292 * @param value lpm match value
Frank Wangdf383212017-06-23 09:17:41 +0800293 * @param prefixLength lpm match prefix length
294 * @return this
295 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800296 public Builder matchLpm(PiMatchFieldId fieldId, byte[] value, int prefixLength) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400297 fieldMatchMapBuilder.put(fieldId, new PiLpmFieldMatch(fieldId, copyFrom(value), prefixLength));
Frank Wangdf383212017-06-23 09:17:41 +0800298 return this;
299 }
300
301 /**
Frank Wangdf383212017-06-23 09:17:41 +0800302 * Adds a range field match for the given fieldId, low and high.
303 *
304 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400305 * @param low range match low value
306 * @param high range match high value
Frank Wangdf383212017-06-23 09:17:41 +0800307 * @return this
308 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800309 public Builder matchRange(PiMatchFieldId fieldId, short low, short high) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400310 fieldMatchMapBuilder.put(fieldId, new PiRangeFieldMatch(fieldId, copyFrom(low), copyFrom(high)));
Frank Wangdf383212017-06-23 09:17:41 +0800311 return this;
312 }
313
314 /**
315 * Adds a range field match for the given fieldId, low and high.
316 *
317 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400318 * @param low range match low value
319 * @param high range match high value
Frank Wangdf383212017-06-23 09:17:41 +0800320 * @return this
321 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800322 public Builder matchRange(PiMatchFieldId fieldId, int low, int high) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400323 fieldMatchMapBuilder.put(fieldId, new PiRangeFieldMatch(fieldId, copyFrom(low), copyFrom(high)));
Frank Wangdf383212017-06-23 09:17:41 +0800324 return this;
325 }
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400326
Frank Wangdf383212017-06-23 09:17:41 +0800327 /**
328 * Adds a range field match for the given fieldId, low and high.
329 *
330 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400331 * @param low range match low value
332 * @param high range match high value
Frank Wangdf383212017-06-23 09:17:41 +0800333 * @return this
334 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800335 public Builder matchRange(PiMatchFieldId fieldId, long low, long high) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400336 fieldMatchMapBuilder.put(fieldId, new PiRangeFieldMatch(fieldId, copyFrom(low), copyFrom(high)));
Frank Wangdf383212017-06-23 09:17:41 +0800337 return this;
338 }
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400339
Frank Wangdf383212017-06-23 09:17:41 +0800340 /**
341 * Adds a range field match for the given fieldId, low and high.
342 *
343 * @param fieldId protocol-independent header field Id
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400344 * @param low range match low value
345 * @param high range match high value
Frank Wangdf383212017-06-23 09:17:41 +0800346 * @return this
347 */
Carmelo Cascone87892e22017-11-13 16:01:29 -0800348 public Builder matchRange(PiMatchFieldId fieldId, byte[] low, byte[] high) {
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400349 fieldMatchMapBuilder.put(fieldId, new PiRangeFieldMatch(fieldId, copyFrom(low), copyFrom(high)));
Frank Wangdf383212017-06-23 09:17:41 +0800350 return this;
351 }
352
353 /**
Daniele Morocdac24f2020-12-18 10:55:57 +0100354 * Adds an optional field match for the given fieldId and value.
355 *
356 * @param fieldId protocol-independent header field Id
357 * @param value optional match value
358 * @return this
359 */
360 public Builder matchOptional(PiMatchFieldId fieldId, short value) {
361 fieldMatchMapBuilder.put(fieldId, new PiOptionalFieldMatch(fieldId, copyFrom(value)));
362 return this;
363 }
364
365 /**
366 * Adds an optional field match for the given fieldId and value.
367 *
368 * @param fieldId protocol-independent header field Id
369 * @param value optional match value
370 * @return this
371 */
372 public Builder matchOptional(PiMatchFieldId fieldId, int value) {
373 fieldMatchMapBuilder.put(fieldId, new PiOptionalFieldMatch(fieldId, copyFrom(value)));
374 return this;
375 }
376
377 /**
378 * Adds an optional field match for the given fieldId and value.
379 *
380 * @param fieldId protocol-independent header field Id
381 * @param value optional match value
382 * @return this
383 */
384 public Builder matchOptional(PiMatchFieldId fieldId, long value) {
385 fieldMatchMapBuilder.put(fieldId, new PiOptionalFieldMatch(fieldId, copyFrom(value)));
386 return this;
387 }
388
389 /**
390 * Adds an optional field match for the given fieldId and value.
391 *
392 * @param fieldId protocol-independent header field Id
393 * @param value optional match value
394 * @return this
395 */
396 public Builder matchOptional(PiMatchFieldId fieldId, byte[] value) {
397 fieldMatchMapBuilder.put(fieldId, new PiOptionalFieldMatch(fieldId, copyFrom(value)));
398 return this;
399 }
400
401 /**
Frank Wangdf383212017-06-23 09:17:41 +0800402 * Builds a PiCriterion.
403 *
404 * @return PiCriterion
405 */
Carmelo Cascone770507f2017-09-14 20:58:04 +0200406 public PiCriterion build() {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800407 ImmutableMap<PiMatchFieldId, PiFieldMatch> fieldMatchMap = fieldMatchMapBuilder.build();
Carmelo Cascone32a01b22017-07-18 10:51:07 -0400408 checkArgument(fieldMatchMap.size() > 0, "Cannot build PI criterion with 0 field matches");
409 return new PiCriterion(fieldMatchMap);
Frank Wangdf383212017-06-23 09:17:41 +0800410 }
411 }
Carmelo Cascone87892e22017-11-13 16:01:29 -0800412}