blob: 74397b01491aa40eb8ffa258ecad806fe30f837e [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()) {
Xin Jin313708b2015-07-09 13:43:04 -0700173 case OUTPUT:
174 break;
175 case GROUP:
176 break;
177 case L0MODIFICATION: {
178 L0ModificationInstruction l0 = (L0ModificationInstruction) instruction;
179 switch (l0.subtype()) {
180 case LAMBDA:
181 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
182 if (((LambdaCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
183 == ((L0ModificationInstruction.ModLambdaInstruction) l0).lambda()) {
184 criterionMap.remove(Criterion.Type.OCH_SIGID);
185 } else {
186 return null;
187 }
188 } else {
189 break;
190 }
191 case OCH:
192 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
193 if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
194 .equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) {
195 criterionMap.remove(Criterion.Type.OCH_SIGID);
196 } else {
197 return null;
198 }
Xin Jin313708b2015-07-09 13:43:04 -0700199 }
200 default:
201 break;
202 }
203 break;
204 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300205 case L1MODIFICATION: {
206 L1ModificationInstruction l1 = (L1ModificationInstruction) instruction;
207 switch (l1.subtype()) {
208 case ODU_SIGID:
209 if (criterionMap.containsKey(Criterion.Type.ODU_SIGID)) {
210 if (((OduSignalIdCriterion) criterionMap.get((Criterion.Type.ODU_SIGID))).oduSignalId()
211 .equals(((L1ModificationInstruction.ModOduSignalIdInstruction) l1)
212 .oduSignalId())) {
213 criterionMap.remove(Criterion.Type.ODU_SIGID);
214 } else {
215 return null;
216 }
Ray Milkey125572b2016-02-22 16:48:17 -0800217 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300218 default:
219 break;
220 }
221 break;
222 }
Xin Jin313708b2015-07-09 13:43:04 -0700223 case L2MODIFICATION: {
224 L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
225 switch (l2.subtype()) {
226 case ETH_SRC:
227 if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) {
228 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac()
229 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
230 criterionMap.remove(Criterion.Type.ETH_SRC);
231 } else {
232 return null;
233 }
234 } else {
235 break;
236 }
237 case ETH_DST:
238 if (criterionMap.containsKey(Criterion.Type.ETH_DST)) {
239 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac()
240 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
241 criterionMap.remove(Criterion.Type.ETH_DST);
242 } else {
243 return null;
244 }
245 } else {
246 break;
247 }
248 case VLAN_ID:
249 if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) {
250 if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId()
251 .equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) {
252 criterionMap.remove(Criterion.Type.VLAN_VID);
253 } else {
254 return null;
255 }
256 } else {
257 break;
258 }
259 case VLAN_PCP:
260 if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) {
261 if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority()
262 == ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) {
263 criterionMap.remove(Criterion.Type.VLAN_PCP);
264 } else {
265 return null;
266 }
267 } else {
268 break;
269 }
270 case MPLS_LABEL:
271 if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) {
272 if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label()
Ray Milkey125572b2016-02-22 16:48:17 -0800273 .equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).label())) {
Xin Jin313708b2015-07-09 13:43:04 -0700274 criterionMap.remove(Criterion.Type.ETH_DST);
275 } else {
276 return null;
277 }
278 } else {
279 break;
280 }
281 default:
282 break;
283 }
284 break;
285 }
286 case TABLE:
287 break;
288 case L3MODIFICATION: {
289 L3ModificationInstruction l3 = (L3ModificationInstruction) instruction;
290 switch (l3.subtype()) {
291 case IPV4_SRC:
292 if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) {
293 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip()
294 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
295 criterionMap.remove(Criterion.Type.IPV4_SRC);
296 } else {
297 return null;
298 }
299 } else {
300 break;
301 }
302 case IPV4_DST:
303 if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) {
304 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip()
305 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
306 criterionMap.remove(Criterion.Type.IPV4_DST);
307 } else {
308 return null;
309 }
310 } else {
311 break;
312 }
313 case IPV6_SRC:
314 if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) {
315 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip()
316 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
317 criterionMap.remove(Criterion.Type.IPV6_SRC);
318 } else {
319 return null;
320 }
321 } else {
322 break;
323 }
324 case IPV6_DST:
325 if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) {
326 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip()
327 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
328 criterionMap.remove(Criterion.Type.IPV6_DST);
329 } else {
330 return null;
331 }
332 } else {
333 break;
334 }
335 case IPV6_FLABEL:
336 if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) {
HIGUCHI Yutad275afd2015-09-09 09:57:34 +0900337 if (((IPv6FlowLabelCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).flowLabel()
338 == (((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3).flowLabel())) {
Xin Jin313708b2015-07-09 13:43:04 -0700339 criterionMap.remove(Criterion.Type.IPV4_SRC);
340 } else {
341 return null;
342 }
343 } else {
344 break;
345 }
346 default:
347 break;
348 }
349 break;
350 }
351 case METADATA:
352 break;
353 default:
354 break;
355 }
356 }
357
358 for (Criterion criterion : criterionMap.values()) {
359 selectorBuilder.add(criterion);
360 }
361
362 return selectorBuilder.build();
363 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300364 //CHECKSTYLE:ON
Xin Jin313708b2015-07-09 13:43:04 -0700365
366 public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
367 Set<Criterion.Type> typeSet = new HashSet<>();
368 for (Criterion criterion : trafficSelector.criteria()) {
369 typeSet.add(criterion.type());
370 }
371 return typeSet;
372 }
373
374 public static Criterion intersectCriterion(Criterion c1, Criterion c2) {
375 switch (c1.type()) {
376 case IPV4_SRC: {
377 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
378 if (ipPrefix == null) {
379 return null;
380 } else {
381 return Criteria.matchIPSrc(ipPrefix);
382 }
383 }
384 case IPV4_DST: {
385 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
386 if (ipPrefix == null) {
387 return null;
388 } else {
389 return Criteria.matchIPDst(ipPrefix);
390 }
391 }
392 case IPV6_SRC: {
393 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
394 if (ipPrefix == null) {
395 return null;
396 } else {
397 return Criteria.matchIPv6Src(ipPrefix);
398 }
399 }
400 case IPV6_DST: {
401 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
402 if (ipPrefix == null) {
403 return null;
404 } else {
405 return Criteria.matchIPv6Dst(ipPrefix);
406 }
407 }
408 default:
409 if (!c1.equals(c2)) {
410 return null;
411 } else {
412 return c1;
413 }
414 }
415 }
416
417 public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) {
418 if (ip1.contains(ip2)) {
419 return ip1;
420 } else if (ip2.contains(ip1)) {
421 return ip2;
422 } else {
423 return null;
424 }
425 }
426
427 public static FlowObjectiveCompositionTree parsePolicyString(String policy) {
428 List<FlowObjectiveCompositionTree> postfix = transformToPostfixForm(policy);
429 return buildPolicyTree(postfix);
430 }
431
432 private static List<FlowObjectiveCompositionTree> transformToPostfixForm(String policy) {
433 Stack<Character> stack = new Stack<>();
434 List<FlowObjectiveCompositionTree> postfix = new ArrayList<>();
435
436 for (int i = 0; i < policy.length(); i++) {
437 Character ch = policy.charAt(i);
438 if (Character.isDigit(ch)) {
439
440 int applicationId = ch - '0';
441 while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) {
442 i++;
443 applicationId = applicationId * 10 + policy.charAt(i) - '0';
444 }
445
446 postfix.add(new FlowObjectiveCompositionTree((short) applicationId));
447 } else if (ch == '(') {
448 stack.push(ch);
449 } else if (ch == ')') {
450 while (stack.peek() != '(') {
451 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
452 }
453 stack.pop();
454 } else {
455 while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) {
456 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
457 }
458 stack.push(ch);
459 }
460 }
461 while (!stack.isEmpty()) {
462 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
463 }
464
465 return postfix;
466 }
467
468 private static boolean compareOperatorPriority(char peek, char cur) {
469 if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) {
470 return true;
471 } else if (peek == '>' && (cur == '+' || cur == '>')) {
472 return true;
473 } else if (peek == '+' && cur == '+') {
474 return true;
475 }
476 return false;
477 }
478
479 private static FlowObjectiveCompositionTree buildPolicyTree(List<FlowObjectiveCompositionTree> postfix) {
480 Stack<FlowObjectiveCompositionTree> stack = new Stack<>();
481 for (FlowObjectiveCompositionTree node : postfix) {
482 if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) {
483 stack.push(node);
484 } else {
485 node.rightChild = stack.pop();
486 node.leftChild = stack.pop();
487 stack.push(node);
488 }
489 }
490 return stack.pop();
491 }
492
493 public static Collection<ForwardingObjective> minusForwardingObjectives(Collection<ForwardingObjective> fo1,
494 Collection<ForwardingObjective> fo2) {
495 Map<Integer, ForwardingObjective> map = new HashMap<>();
496 for (ForwardingObjective fo : fo1) {
497 map.put(fo.id(), fo);
498 }
499 for (ForwardingObjective fo : fo2) {
500 map.remove(fo.id());
501 }
502 return map.values();
503 }
504
505
506}