blob: 0a1af6f585ab7a42a51d2e43ee5136887a00c564 [file] [log] [blame]
Xin Jin313708b2015-07-09 13:43:04 -07001/*
2 * Copyright 2015 Open Networking Laboratory
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 */
16package org.onosproject.net.flowobjective.impl.composition;
17
18import org.onlab.packet.IpPrefix;
19import org.onosproject.net.flow.DefaultTrafficSelector;
20import org.onosproject.net.flow.DefaultTrafficTreatment;
21import org.onosproject.net.flow.TrafficSelector;
22import org.onosproject.net.flow.TrafficTreatment;
23import org.onosproject.net.flow.criteria.Criterion;
24import org.onosproject.net.flow.criteria.LambdaCriterion;
25import org.onosproject.net.flow.criteria.OchSignalCriterion;
26import org.onosproject.net.flow.criteria.EthCriterion;
27import org.onosproject.net.flow.criteria.VlanIdCriterion;
28import org.onosproject.net.flow.criteria.VlanPcpCriterion;
29import org.onosproject.net.flow.criteria.MplsCriterion;
30import org.onosproject.net.flow.criteria.IPCriterion;
HIGUCHI Yutad275afd2015-09-09 09:57:34 +090031import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion;
Yafit Hadar5796d972015-10-15 13:16:11 +030032import org.onosproject.net.flow.criteria.OduSignalIdCriterion;
Xin Jin313708b2015-07-09 13:43:04 -070033import org.onosproject.net.flow.criteria.Criteria;
34import org.onosproject.net.flow.instructions.Instruction;
35import org.onosproject.net.flow.instructions.L0ModificationInstruction;
Yafit Hadar5796d972015-10-15 13:16:11 +030036import org.onosproject.net.flow.instructions.L1ModificationInstruction;
Xin Jin313708b2015-07-09 13:43:04 -070037import org.onosproject.net.flow.instructions.L2ModificationInstruction;
38import org.onosproject.net.flow.instructions.L3ModificationInstruction;
39import org.onosproject.net.flowobjective.DefaultForwardingObjective;
40import org.onosproject.net.flowobjective.ForwardingObjective;
41
42import java.util.ArrayList;
43import java.util.Collection;
44import java.util.HashMap;
45import java.util.HashSet;
46import java.util.List;
47import java.util.Map;
48import java.util.Set;
49import java.util.Stack;
50
51/**
52 * Provide util functions for FlowObjectiveComposition.
53 */
54public final class FlowObjectiveCompositionUtil {
55
56 private FlowObjectiveCompositionUtil() {}
57
58 // only work with VERSATILE
59 public static ForwardingObjective composeParallel(ForwardingObjective fo1, ForwardingObjective fo2) {
60
61 TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), fo2.selector());
62 if (trafficSelector == null) {
63 return null;
64 }
65
66 TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
67
68 return DefaultForwardingObjective.builder()
69 .fromApp(fo1.appId())
70 .makePermanent()
71 .withFlag(ForwardingObjective.Flag.VERSATILE)
72 .withPriority(fo1.priority() + fo2.priority())
73 .withSelector(trafficSelector)
74 .withTreatment(trafficTreatment)
75 .add();
76 }
77
78 public static ForwardingObjective composeSequential(ForwardingObjective fo1,
79 ForwardingObjective fo2,
80 int priorityMultiplier) {
81
82 TrafficSelector revertTrafficSelector = revertTreatmentSelector(fo1.treatment(), fo2.selector());
83 if (revertTrafficSelector == null) {
84 return null;
85 }
86
87 TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), revertTrafficSelector);
88 if (trafficSelector == null) {
89 return null;
90 }
91
92 TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
93
94 return DefaultForwardingObjective.builder()
95 .fromApp(fo1.appId())
96 .makePermanent()
97 .withFlag(ForwardingObjective.Flag.VERSATILE)
98 .withPriority(fo1.priority() * priorityMultiplier + fo2.priority())
99 .withSelector(trafficSelector)
100 .withTreatment(trafficTreatment)
101 .add();
102 }
103
104 public static ForwardingObjective composeOverride(ForwardingObjective fo, int priorityAddend) {
105 return DefaultForwardingObjective.builder()
106 .fromApp(fo.appId())
107 .makePermanent()
108 .withFlag(fo.flag())
109 .withPriority(fo.priority() + priorityAddend)
110 .withSelector(fo.selector())
111 .withTreatment(fo.treatment())
112 .add();
113 }
114
115 public static TrafficSelector intersectTrafficSelector(TrafficSelector ts1, TrafficSelector ts2) {
116
117 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
118
119 Set<Criterion.Type> ts1IntersectTs2 = getTypeSet(ts1);
120 ts1IntersectTs2.retainAll(getTypeSet(ts2));
121 for (Criterion.Type type : ts1IntersectTs2) {
122 Criterion criterion = intersectCriterion(ts1.getCriterion(type), ts2.getCriterion(type));
123 if (criterion == null) {
124 return null;
125 } else {
126 selectorBuilder.add(criterion);
127 }
128 }
129
130 Set<Criterion.Type> ts1MinusTs2 = getTypeSet(ts1);
131 ts1MinusTs2.removeAll(getTypeSet(ts2));
132 for (Criterion.Type type : ts1MinusTs2) {
133 selectorBuilder.add(ts1.getCriterion(type));
134 }
135
136 Set<Criterion.Type> ts2MinusTs1 = getTypeSet(ts2);
137 ts2MinusTs1.removeAll(getTypeSet(ts1));
138 for (Criterion.Type type : ts2MinusTs1) {
139 selectorBuilder.add(ts2.getCriterion(type));
140 }
141
142 return selectorBuilder.build();
143 }
144
145 public static TrafficTreatment unionTrafficTreatment(TrafficTreatment tt1, TrafficTreatment tt2) {
146
147 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
148
149 for (Instruction instruction : tt1.allInstructions()) {
150 treatmentBuilder.add(instruction);
151 }
152
153 for (Instruction instruction : tt2.allInstructions()) {
154 treatmentBuilder.add(instruction);
155 }
156
157 return treatmentBuilder.build();
158 }
159
Yafit Hadar5796d972015-10-15 13:16:11 +0300160 //CHECKSTYLE:OFF
Xin Jin313708b2015-07-09 13:43:04 -0700161 public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment,
162 TrafficSelector trafficSelector) {
163
164 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
165
166 Map<Criterion.Type, Criterion> criterionMap = new HashMap<>();
167 for (Criterion criterion : trafficSelector.criteria()) {
168 criterionMap.put(criterion.type(), criterion);
169 }
170
171 for (Instruction instruction : trafficTreatment.allInstructions()) {
172 switch (instruction.type()) {
173 case DROP:
174 return null;
175 case OUTPUT:
176 break;
177 case GROUP:
178 break;
179 case L0MODIFICATION: {
180 L0ModificationInstruction l0 = (L0ModificationInstruction) instruction;
181 switch (l0.subtype()) {
182 case LAMBDA:
183 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
184 if (((LambdaCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
185 == ((L0ModificationInstruction.ModLambdaInstruction) l0).lambda()) {
186 criterionMap.remove(Criterion.Type.OCH_SIGID);
187 } else {
188 return null;
189 }
190 } else {
191 break;
192 }
193 case OCH:
194 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
195 if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
196 .equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) {
197 criterionMap.remove(Criterion.Type.OCH_SIGID);
198 } else {
199 return null;
200 }
Xin Jin313708b2015-07-09 13:43:04 -0700201 }
202 default:
203 break;
204 }
205 break;
206 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300207 case L1MODIFICATION: {
208 L1ModificationInstruction l1 = (L1ModificationInstruction) instruction;
209 switch (l1.subtype()) {
210 case ODU_SIGID:
211 if (criterionMap.containsKey(Criterion.Type.ODU_SIGID)) {
212 if (((OduSignalIdCriterion) criterionMap.get((Criterion.Type.ODU_SIGID))).oduSignalId()
213 .equals(((L1ModificationInstruction.ModOduSignalIdInstruction) l1)
214 .oduSignalId())) {
215 criterionMap.remove(Criterion.Type.ODU_SIGID);
216 } else {
217 return null;
218 }
219 }
220 default:
221 break;
222 }
223 break;
224 }
Xin Jin313708b2015-07-09 13:43:04 -0700225 case L2MODIFICATION: {
226 L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
227 switch (l2.subtype()) {
228 case ETH_SRC:
229 if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) {
230 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac()
231 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
232 criterionMap.remove(Criterion.Type.ETH_SRC);
233 } else {
234 return null;
235 }
236 } else {
237 break;
238 }
239 case ETH_DST:
240 if (criterionMap.containsKey(Criterion.Type.ETH_DST)) {
241 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac()
242 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
243 criterionMap.remove(Criterion.Type.ETH_DST);
244 } else {
245 return null;
246 }
247 } else {
248 break;
249 }
250 case VLAN_ID:
251 if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) {
252 if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId()
253 .equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) {
254 criterionMap.remove(Criterion.Type.VLAN_VID);
255 } else {
256 return null;
257 }
258 } else {
259 break;
260 }
261 case VLAN_PCP:
262 if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) {
263 if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority()
264 == ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) {
265 criterionMap.remove(Criterion.Type.VLAN_PCP);
266 } else {
267 return null;
268 }
269 } else {
270 break;
271 }
272 case MPLS_LABEL:
273 if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) {
274 if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label()
HIGUCHI Yuta60db9772015-08-26 17:49:34 -0700275 .equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).mplsLabel())) {
Xin Jin313708b2015-07-09 13:43:04 -0700276 criterionMap.remove(Criterion.Type.ETH_DST);
277 } else {
278 return null;
279 }
280 } else {
281 break;
282 }
283 default:
284 break;
285 }
286 break;
287 }
288 case TABLE:
289 break;
290 case L3MODIFICATION: {
291 L3ModificationInstruction l3 = (L3ModificationInstruction) instruction;
292 switch (l3.subtype()) {
293 case IPV4_SRC:
294 if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) {
295 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip()
296 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
297 criterionMap.remove(Criterion.Type.IPV4_SRC);
298 } else {
299 return null;
300 }
301 } else {
302 break;
303 }
304 case IPV4_DST:
305 if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) {
306 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip()
307 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
308 criterionMap.remove(Criterion.Type.IPV4_DST);
309 } else {
310 return null;
311 }
312 } else {
313 break;
314 }
315 case IPV6_SRC:
316 if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) {
317 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip()
318 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
319 criterionMap.remove(Criterion.Type.IPV6_SRC);
320 } else {
321 return null;
322 }
323 } else {
324 break;
325 }
326 case IPV6_DST:
327 if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) {
328 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip()
329 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
330 criterionMap.remove(Criterion.Type.IPV6_DST);
331 } else {
332 return null;
333 }
334 } else {
335 break;
336 }
337 case IPV6_FLABEL:
338 if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) {
HIGUCHI Yutad275afd2015-09-09 09:57:34 +0900339 if (((IPv6FlowLabelCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).flowLabel()
340 == (((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3).flowLabel())) {
Xin Jin313708b2015-07-09 13:43:04 -0700341 criterionMap.remove(Criterion.Type.IPV4_SRC);
342 } else {
343 return null;
344 }
345 } else {
346 break;
347 }
348 default:
349 break;
350 }
351 break;
352 }
353 case METADATA:
354 break;
355 default:
356 break;
357 }
358 }
359
360 for (Criterion criterion : criterionMap.values()) {
361 selectorBuilder.add(criterion);
362 }
363
364 return selectorBuilder.build();
365 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300366 //CHECKSTYLE:ON
Xin Jin313708b2015-07-09 13:43:04 -0700367
368 public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
369 Set<Criterion.Type> typeSet = new HashSet<>();
370 for (Criterion criterion : trafficSelector.criteria()) {
371 typeSet.add(criterion.type());
372 }
373 return typeSet;
374 }
375
376 public static Criterion intersectCriterion(Criterion c1, Criterion c2) {
377 switch (c1.type()) {
378 case IPV4_SRC: {
379 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
380 if (ipPrefix == null) {
381 return null;
382 } else {
383 return Criteria.matchIPSrc(ipPrefix);
384 }
385 }
386 case IPV4_DST: {
387 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
388 if (ipPrefix == null) {
389 return null;
390 } else {
391 return Criteria.matchIPDst(ipPrefix);
392 }
393 }
394 case IPV6_SRC: {
395 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
396 if (ipPrefix == null) {
397 return null;
398 } else {
399 return Criteria.matchIPv6Src(ipPrefix);
400 }
401 }
402 case IPV6_DST: {
403 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
404 if (ipPrefix == null) {
405 return null;
406 } else {
407 return Criteria.matchIPv6Dst(ipPrefix);
408 }
409 }
410 default:
411 if (!c1.equals(c2)) {
412 return null;
413 } else {
414 return c1;
415 }
416 }
417 }
418
419 public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) {
420 if (ip1.contains(ip2)) {
421 return ip1;
422 } else if (ip2.contains(ip1)) {
423 return ip2;
424 } else {
425 return null;
426 }
427 }
428
429 public static FlowObjectiveCompositionTree parsePolicyString(String policy) {
430 List<FlowObjectiveCompositionTree> postfix = transformToPostfixForm(policy);
431 return buildPolicyTree(postfix);
432 }
433
434 private static List<FlowObjectiveCompositionTree> transformToPostfixForm(String policy) {
435 Stack<Character> stack = new Stack<>();
436 List<FlowObjectiveCompositionTree> postfix = new ArrayList<>();
437
438 for (int i = 0; i < policy.length(); i++) {
439 Character ch = policy.charAt(i);
440 if (Character.isDigit(ch)) {
441
442 int applicationId = ch - '0';
443 while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) {
444 i++;
445 applicationId = applicationId * 10 + policy.charAt(i) - '0';
446 }
447
448 postfix.add(new FlowObjectiveCompositionTree((short) applicationId));
449 } else if (ch == '(') {
450 stack.push(ch);
451 } else if (ch == ')') {
452 while (stack.peek() != '(') {
453 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
454 }
455 stack.pop();
456 } else {
457 while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) {
458 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
459 }
460 stack.push(ch);
461 }
462 }
463 while (!stack.isEmpty()) {
464 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
465 }
466
467 return postfix;
468 }
469
470 private static boolean compareOperatorPriority(char peek, char cur) {
471 if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) {
472 return true;
473 } else if (peek == '>' && (cur == '+' || cur == '>')) {
474 return true;
475 } else if (peek == '+' && cur == '+') {
476 return true;
477 }
478 return false;
479 }
480
481 private static FlowObjectiveCompositionTree buildPolicyTree(List<FlowObjectiveCompositionTree> postfix) {
482 Stack<FlowObjectiveCompositionTree> stack = new Stack<>();
483 for (FlowObjectiveCompositionTree node : postfix) {
484 if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) {
485 stack.push(node);
486 } else {
487 node.rightChild = stack.pop();
488 node.leftChild = stack.pop();
489 stack.push(node);
490 }
491 }
492 return stack.pop();
493 }
494
495 public static Collection<ForwardingObjective> minusForwardingObjectives(Collection<ForwardingObjective> fo1,
496 Collection<ForwardingObjective> fo2) {
497 Map<Integer, ForwardingObjective> map = new HashMap<>();
498 for (ForwardingObjective fo : fo1) {
499 map.put(fo.id(), fo);
500 }
501 for (ForwardingObjective fo : fo2) {
502 map.remove(fo.id());
503 }
504 return map.values();
505 }
506
507
508}