aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java')
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java488
1 files changed, 488 insertions, 0 deletions
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java
new file mode 100644
index 00000000..137aca1e
--- /dev/null
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java
@@ -0,0 +1,488 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.flowobjective.impl.composition;
+
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.LambdaCriterion;
+import org.onosproject.net.flow.criteria.OchSignalCriterion;
+import org.onosproject.net.flow.criteria.EthCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.criteria.VlanPcpCriterion;
+import org.onosproject.net.flow.criteria.MplsCriterion;
+import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Provide util functions for FlowObjectiveComposition.
+ */
+public final class FlowObjectiveCompositionUtil {
+
+ private FlowObjectiveCompositionUtil() {}
+
+ // only work with VERSATILE
+ public static ForwardingObjective composeParallel(ForwardingObjective fo1, ForwardingObjective fo2) {
+
+ TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), fo2.selector());
+ if (trafficSelector == null) {
+ return null;
+ }
+
+ TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
+
+ return DefaultForwardingObjective.builder()
+ .fromApp(fo1.appId())
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(fo1.priority() + fo2.priority())
+ .withSelector(trafficSelector)
+ .withTreatment(trafficTreatment)
+ .add();
+ }
+
+ public static ForwardingObjective composeSequential(ForwardingObjective fo1,
+ ForwardingObjective fo2,
+ int priorityMultiplier) {
+
+ TrafficSelector revertTrafficSelector = revertTreatmentSelector(fo1.treatment(), fo2.selector());
+ if (revertTrafficSelector == null) {
+ return null;
+ }
+
+ TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), revertTrafficSelector);
+ if (trafficSelector == null) {
+ return null;
+ }
+
+ TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
+
+ return DefaultForwardingObjective.builder()
+ .fromApp(fo1.appId())
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(fo1.priority() * priorityMultiplier + fo2.priority())
+ .withSelector(trafficSelector)
+ .withTreatment(trafficTreatment)
+ .add();
+ }
+
+ public static ForwardingObjective composeOverride(ForwardingObjective fo, int priorityAddend) {
+ return DefaultForwardingObjective.builder()
+ .fromApp(fo.appId())
+ .makePermanent()
+ .withFlag(fo.flag())
+ .withPriority(fo.priority() + priorityAddend)
+ .withSelector(fo.selector())
+ .withTreatment(fo.treatment())
+ .add();
+ }
+
+ public static TrafficSelector intersectTrafficSelector(TrafficSelector ts1, TrafficSelector ts2) {
+
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+
+ Set<Criterion.Type> ts1IntersectTs2 = getTypeSet(ts1);
+ ts1IntersectTs2.retainAll(getTypeSet(ts2));
+ for (Criterion.Type type : ts1IntersectTs2) {
+ Criterion criterion = intersectCriterion(ts1.getCriterion(type), ts2.getCriterion(type));
+ if (criterion == null) {
+ return null;
+ } else {
+ selectorBuilder.add(criterion);
+ }
+ }
+
+ Set<Criterion.Type> ts1MinusTs2 = getTypeSet(ts1);
+ ts1MinusTs2.removeAll(getTypeSet(ts2));
+ for (Criterion.Type type : ts1MinusTs2) {
+ selectorBuilder.add(ts1.getCriterion(type));
+ }
+
+ Set<Criterion.Type> ts2MinusTs1 = getTypeSet(ts2);
+ ts2MinusTs1.removeAll(getTypeSet(ts1));
+ for (Criterion.Type type : ts2MinusTs1) {
+ selectorBuilder.add(ts2.getCriterion(type));
+ }
+
+ return selectorBuilder.build();
+ }
+
+ public static TrafficTreatment unionTrafficTreatment(TrafficTreatment tt1, TrafficTreatment tt2) {
+
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+
+ for (Instruction instruction : tt1.allInstructions()) {
+ treatmentBuilder.add(instruction);
+ }
+
+ for (Instruction instruction : tt2.allInstructions()) {
+ treatmentBuilder.add(instruction);
+ }
+
+ return treatmentBuilder.build();
+ }
+
+ public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment,
+ TrafficSelector trafficSelector) {
+
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+
+ Map<Criterion.Type, Criterion> criterionMap = new HashMap<>();
+ for (Criterion criterion : trafficSelector.criteria()) {
+ criterionMap.put(criterion.type(), criterion);
+ }
+
+ for (Instruction instruction : trafficTreatment.allInstructions()) {
+ switch (instruction.type()) {
+ case DROP:
+ return null;
+ case OUTPUT:
+ break;
+ case GROUP:
+ break;
+ case L0MODIFICATION: {
+ L0ModificationInstruction l0 = (L0ModificationInstruction) instruction;
+ switch (l0.subtype()) {
+ case LAMBDA:
+ if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
+ if (((LambdaCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
+ == ((L0ModificationInstruction.ModLambdaInstruction) l0).lambda()) {
+ criterionMap.remove(Criterion.Type.OCH_SIGID);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case OCH:
+ if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
+ if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
+ .equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) {
+ criterionMap.remove(Criterion.Type.OCH_SIGID);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case L2MODIFICATION: {
+ L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
+ switch (l2.subtype()) {
+ case ETH_SRC:
+ if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) {
+ if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac()
+ .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
+ criterionMap.remove(Criterion.Type.ETH_SRC);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case ETH_DST:
+ if (criterionMap.containsKey(Criterion.Type.ETH_DST)) {
+ if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac()
+ .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
+ criterionMap.remove(Criterion.Type.ETH_DST);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case VLAN_ID:
+ if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) {
+ if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId()
+ .equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) {
+ criterionMap.remove(Criterion.Type.VLAN_VID);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case VLAN_PCP:
+ if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) {
+ if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority()
+ == ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) {
+ criterionMap.remove(Criterion.Type.VLAN_PCP);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case MPLS_LABEL:
+ if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) {
+ if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label()
+ .equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).mplsLabel())) {
+ criterionMap.remove(Criterion.Type.ETH_DST);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case TABLE:
+ break;
+ case L3MODIFICATION: {
+ L3ModificationInstruction l3 = (L3ModificationInstruction) instruction;
+ switch (l3.subtype()) {
+ case IPV4_SRC:
+ if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) {
+ if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip()
+ .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
+ criterionMap.remove(Criterion.Type.IPV4_SRC);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case IPV4_DST:
+ if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) {
+ if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip()
+ .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
+ criterionMap.remove(Criterion.Type.IPV4_DST);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case IPV6_SRC:
+ if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) {
+ if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip()
+ .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
+ criterionMap.remove(Criterion.Type.IPV6_SRC);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case IPV6_DST:
+ if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) {
+ if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip()
+ .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
+ criterionMap.remove(Criterion.Type.IPV6_DST);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ case IPV6_FLABEL:
+ if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) {
+ if (((IPv6FlowLabelCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).flowLabel()
+ == (((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3).flowLabel())) {
+ criterionMap.remove(Criterion.Type.IPV4_SRC);
+ } else {
+ return null;
+ }
+ } else {
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case METADATA:
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (Criterion criterion : criterionMap.values()) {
+ selectorBuilder.add(criterion);
+ }
+
+ return selectorBuilder.build();
+ }
+
+ public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
+ Set<Criterion.Type> typeSet = new HashSet<>();
+ for (Criterion criterion : trafficSelector.criteria()) {
+ typeSet.add(criterion.type());
+ }
+ return typeSet;
+ }
+
+ public static Criterion intersectCriterion(Criterion c1, Criterion c2) {
+ switch (c1.type()) {
+ case IPV4_SRC: {
+ IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
+ if (ipPrefix == null) {
+ return null;
+ } else {
+ return Criteria.matchIPSrc(ipPrefix);
+ }
+ }
+ case IPV4_DST: {
+ IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
+ if (ipPrefix == null) {
+ return null;
+ } else {
+ return Criteria.matchIPDst(ipPrefix);
+ }
+ }
+ case IPV6_SRC: {
+ IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
+ if (ipPrefix == null) {
+ return null;
+ } else {
+ return Criteria.matchIPv6Src(ipPrefix);
+ }
+ }
+ case IPV6_DST: {
+ IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
+ if (ipPrefix == null) {
+ return null;
+ } else {
+ return Criteria.matchIPv6Dst(ipPrefix);
+ }
+ }
+ default:
+ if (!c1.equals(c2)) {
+ return null;
+ } else {
+ return c1;
+ }
+ }
+ }
+
+ public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) {
+ if (ip1.contains(ip2)) {
+ return ip1;
+ } else if (ip2.contains(ip1)) {
+ return ip2;
+ } else {
+ return null;
+ }
+ }
+
+ public static FlowObjectiveCompositionTree parsePolicyString(String policy) {
+ List<FlowObjectiveCompositionTree> postfix = transformToPostfixForm(policy);
+ return buildPolicyTree(postfix);
+ }
+
+ private static List<FlowObjectiveCompositionTree> transformToPostfixForm(String policy) {
+ Stack<Character> stack = new Stack<>();
+ List<FlowObjectiveCompositionTree> postfix = new ArrayList<>();
+
+ for (int i = 0; i < policy.length(); i++) {
+ Character ch = policy.charAt(i);
+ if (Character.isDigit(ch)) {
+
+ int applicationId = ch - '0';
+ while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) {
+ i++;
+ applicationId = applicationId * 10 + policy.charAt(i) - '0';
+ }
+
+ postfix.add(new FlowObjectiveCompositionTree((short) applicationId));
+ } else if (ch == '(') {
+ stack.push(ch);
+ } else if (ch == ')') {
+ while (stack.peek() != '(') {
+ postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
+ }
+ stack.pop();
+ } else {
+ while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) {
+ postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
+ }
+ stack.push(ch);
+ }
+ }
+ while (!stack.isEmpty()) {
+ postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
+ }
+
+ return postfix;
+ }
+
+ private static boolean compareOperatorPriority(char peek, char cur) {
+ if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) {
+ return true;
+ } else if (peek == '>' && (cur == '+' || cur == '>')) {
+ return true;
+ } else if (peek == '+' && cur == '+') {
+ return true;
+ }
+ return false;
+ }
+
+ private static FlowObjectiveCompositionTree buildPolicyTree(List<FlowObjectiveCompositionTree> postfix) {
+ Stack<FlowObjectiveCompositionTree> stack = new Stack<>();
+ for (FlowObjectiveCompositionTree node : postfix) {
+ if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) {
+ stack.push(node);
+ } else {
+ node.rightChild = stack.pop();
+ node.leftChild = stack.pop();
+ stack.push(node);
+ }
+ }
+ return stack.pop();
+ }
+
+ public static Collection<ForwardingObjective> minusForwardingObjectives(Collection<ForwardingObjective> fo1,
+ Collection<ForwardingObjective> fo2) {
+ Map<Integer, ForwardingObjective> map = new HashMap<>();
+ for (ForwardingObjective fo : fo1) {
+ map.put(fo.id(), fo);
+ }
+ for (ForwardingObjective fo : fo2) {
+ map.remove(fo.id());
+ }
+ return map.values();
+ }
+
+
+}