2 * Copyright 2015 Open Networking Laboratory
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.onosproject.net.flowobjective.impl.composition;
18 import org.onlab.packet.IpPrefix;
19 import org.onosproject.net.flow.DefaultTrafficSelector;
20 import org.onosproject.net.flow.DefaultTrafficTreatment;
21 import org.onosproject.net.flow.TrafficSelector;
22 import org.onosproject.net.flow.TrafficTreatment;
23 import org.onosproject.net.flow.criteria.Criterion;
24 import org.onosproject.net.flow.criteria.LambdaCriterion;
25 import org.onosproject.net.flow.criteria.OchSignalCriterion;
26 import org.onosproject.net.flow.criteria.EthCriterion;
27 import org.onosproject.net.flow.criteria.VlanIdCriterion;
28 import org.onosproject.net.flow.criteria.VlanPcpCriterion;
29 import org.onosproject.net.flow.criteria.MplsCriterion;
30 import org.onosproject.net.flow.criteria.IPCriterion;
31 import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion;
32 import org.onosproject.net.flow.criteria.Criteria;
33 import org.onosproject.net.flow.instructions.Instruction;
34 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
35 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
36 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
37 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
38 import org.onosproject.net.flowobjective.ForwardingObjective;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
47 import java.util.Stack;
50 * Provide util functions for FlowObjectiveComposition.
52 public final class FlowObjectiveCompositionUtil {
54 private FlowObjectiveCompositionUtil() {}
56 // only work with VERSATILE
57 public static ForwardingObjective composeParallel(ForwardingObjective fo1, ForwardingObjective fo2) {
59 TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), fo2.selector());
60 if (trafficSelector == null) {
64 TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
66 return DefaultForwardingObjective.builder()
69 .withFlag(ForwardingObjective.Flag.VERSATILE)
70 .withPriority(fo1.priority() + fo2.priority())
71 .withSelector(trafficSelector)
72 .withTreatment(trafficTreatment)
76 public static ForwardingObjective composeSequential(ForwardingObjective fo1,
77 ForwardingObjective fo2,
78 int priorityMultiplier) {
80 TrafficSelector revertTrafficSelector = revertTreatmentSelector(fo1.treatment(), fo2.selector());
81 if (revertTrafficSelector == null) {
85 TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), revertTrafficSelector);
86 if (trafficSelector == null) {
90 TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
92 return DefaultForwardingObjective.builder()
95 .withFlag(ForwardingObjective.Flag.VERSATILE)
96 .withPriority(fo1.priority() * priorityMultiplier + fo2.priority())
97 .withSelector(trafficSelector)
98 .withTreatment(trafficTreatment)
102 public static ForwardingObjective composeOverride(ForwardingObjective fo, int priorityAddend) {
103 return DefaultForwardingObjective.builder()
107 .withPriority(fo.priority() + priorityAddend)
108 .withSelector(fo.selector())
109 .withTreatment(fo.treatment())
113 public static TrafficSelector intersectTrafficSelector(TrafficSelector ts1, TrafficSelector ts2) {
115 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
117 Set<Criterion.Type> ts1IntersectTs2 = getTypeSet(ts1);
118 ts1IntersectTs2.retainAll(getTypeSet(ts2));
119 for (Criterion.Type type : ts1IntersectTs2) {
120 Criterion criterion = intersectCriterion(ts1.getCriterion(type), ts2.getCriterion(type));
121 if (criterion == null) {
124 selectorBuilder.add(criterion);
128 Set<Criterion.Type> ts1MinusTs2 = getTypeSet(ts1);
129 ts1MinusTs2.removeAll(getTypeSet(ts2));
130 for (Criterion.Type type : ts1MinusTs2) {
131 selectorBuilder.add(ts1.getCriterion(type));
134 Set<Criterion.Type> ts2MinusTs1 = getTypeSet(ts2);
135 ts2MinusTs1.removeAll(getTypeSet(ts1));
136 for (Criterion.Type type : ts2MinusTs1) {
137 selectorBuilder.add(ts2.getCriterion(type));
140 return selectorBuilder.build();
143 public static TrafficTreatment unionTrafficTreatment(TrafficTreatment tt1, TrafficTreatment tt2) {
145 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
147 for (Instruction instruction : tt1.allInstructions()) {
148 treatmentBuilder.add(instruction);
151 for (Instruction instruction : tt2.allInstructions()) {
152 treatmentBuilder.add(instruction);
155 return treatmentBuilder.build();
158 public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment,
159 TrafficSelector trafficSelector) {
161 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
163 Map<Criterion.Type, Criterion> criterionMap = new HashMap<>();
164 for (Criterion criterion : trafficSelector.criteria()) {
165 criterionMap.put(criterion.type(), criterion);
168 for (Instruction instruction : trafficTreatment.allInstructions()) {
169 switch (instruction.type()) {
176 case L0MODIFICATION: {
177 L0ModificationInstruction l0 = (L0ModificationInstruction) instruction;
178 switch (l0.subtype()) {
180 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
181 if (((LambdaCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
182 == ((L0ModificationInstruction.ModLambdaInstruction) l0).lambda()) {
183 criterionMap.remove(Criterion.Type.OCH_SIGID);
191 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
192 if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
193 .equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) {
194 criterionMap.remove(Criterion.Type.OCH_SIGID);
206 case L2MODIFICATION: {
207 L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
208 switch (l2.subtype()) {
210 if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) {
211 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac()
212 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
213 criterionMap.remove(Criterion.Type.ETH_SRC);
221 if (criterionMap.containsKey(Criterion.Type.ETH_DST)) {
222 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac()
223 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
224 criterionMap.remove(Criterion.Type.ETH_DST);
232 if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) {
233 if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId()
234 .equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) {
235 criterionMap.remove(Criterion.Type.VLAN_VID);
243 if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) {
244 if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority()
245 == ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) {
246 criterionMap.remove(Criterion.Type.VLAN_PCP);
254 if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) {
255 if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label()
256 .equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).mplsLabel())) {
257 criterionMap.remove(Criterion.Type.ETH_DST);
271 case L3MODIFICATION: {
272 L3ModificationInstruction l3 = (L3ModificationInstruction) instruction;
273 switch (l3.subtype()) {
275 if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) {
276 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip()
277 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
278 criterionMap.remove(Criterion.Type.IPV4_SRC);
286 if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) {
287 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip()
288 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
289 criterionMap.remove(Criterion.Type.IPV4_DST);
297 if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) {
298 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip()
299 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
300 criterionMap.remove(Criterion.Type.IPV6_SRC);
308 if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) {
309 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip()
310 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
311 criterionMap.remove(Criterion.Type.IPV6_DST);
319 if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) {
320 if (((IPv6FlowLabelCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).flowLabel()
321 == (((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3).flowLabel())) {
322 criterionMap.remove(Criterion.Type.IPV4_SRC);
341 for (Criterion criterion : criterionMap.values()) {
342 selectorBuilder.add(criterion);
345 return selectorBuilder.build();
348 public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
349 Set<Criterion.Type> typeSet = new HashSet<>();
350 for (Criterion criterion : trafficSelector.criteria()) {
351 typeSet.add(criterion.type());
356 public static Criterion intersectCriterion(Criterion c1, Criterion c2) {
359 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
360 if (ipPrefix == null) {
363 return Criteria.matchIPSrc(ipPrefix);
367 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
368 if (ipPrefix == null) {
371 return Criteria.matchIPDst(ipPrefix);
375 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
376 if (ipPrefix == null) {
379 return Criteria.matchIPv6Src(ipPrefix);
383 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
384 if (ipPrefix == null) {
387 return Criteria.matchIPv6Dst(ipPrefix);
391 if (!c1.equals(c2)) {
399 public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) {
400 if (ip1.contains(ip2)) {
402 } else if (ip2.contains(ip1)) {
409 public static FlowObjectiveCompositionTree parsePolicyString(String policy) {
410 List<FlowObjectiveCompositionTree> postfix = transformToPostfixForm(policy);
411 return buildPolicyTree(postfix);
414 private static List<FlowObjectiveCompositionTree> transformToPostfixForm(String policy) {
415 Stack<Character> stack = new Stack<>();
416 List<FlowObjectiveCompositionTree> postfix = new ArrayList<>();
418 for (int i = 0; i < policy.length(); i++) {
419 Character ch = policy.charAt(i);
420 if (Character.isDigit(ch)) {
422 int applicationId = ch - '0';
423 while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) {
425 applicationId = applicationId * 10 + policy.charAt(i) - '0';
428 postfix.add(new FlowObjectiveCompositionTree((short) applicationId));
429 } else if (ch == '(') {
431 } else if (ch == ')') {
432 while (stack.peek() != '(') {
433 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
437 while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) {
438 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
443 while (!stack.isEmpty()) {
444 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
450 private static boolean compareOperatorPriority(char peek, char cur) {
451 if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) {
453 } else if (peek == '>' && (cur == '+' || cur == '>')) {
455 } else if (peek == '+' && cur == '+') {
461 private static FlowObjectiveCompositionTree buildPolicyTree(List<FlowObjectiveCompositionTree> postfix) {
462 Stack<FlowObjectiveCompositionTree> stack = new Stack<>();
463 for (FlowObjectiveCompositionTree node : postfix) {
464 if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) {
467 node.rightChild = stack.pop();
468 node.leftChild = stack.pop();
475 public static Collection<ForwardingObjective> minusForwardingObjectives(Collection<ForwardingObjective> fo1,
476 Collection<ForwardingObjective> fo2) {
477 Map<Integer, ForwardingObjective> map = new HashMap<>();
478 for (ForwardingObjective fo : fo1) {
479 map.put(fo.id(), fo);
481 for (ForwardingObjective fo : fo2) {