Add a Polatis NETCONF driver

Change-Id: Iecfe8df9d656bebbe82bf01bcaf185a77ccd26d8
diff --git a/drivers/polatis/netconf/src/main/java/org/onosproject/drivers/polatis/netconf/PolatisOpticalUtility.java b/drivers/polatis/netconf/src/main/java/org/onosproject/drivers/polatis/netconf/PolatisOpticalUtility.java
new file mode 100644
index 0000000..bac9f63
--- /dev/null
+++ b/drivers/polatis/netconf/src/main/java/org/onosproject/drivers/polatis/netconf/PolatisOpticalUtility.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2017 Open Networking Foundation
+ *
+ * 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.drivers.polatis.netconf;
+
+import com.google.common.collect.Range;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+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.PortCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+
+import org.onosproject.yang.gen.v1.opticalswitch.rev20170804.opticalswitch.CrossConnects;
+import org.onosproject.yang.gen.v1.opticalswitch.rev20170804.opticalswitch.crossconnects.Pair;
+import org.onosproject.yang.gen.v1.opticalswitch.rev20170804.opticalswitch.crossconnects.DefaultPair;
+import org.onosproject.yang.gen.v1.opticalswitch.rev20170804.opticalswitch.DefaultCrossConnects;
+import org.onosproject.yang.gen.v1.opticalswitch.rev20170804.opticalswitch.PortFormat;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Polatis optical utilities.
+ */
+public final class PolatisOpticalUtility {
+
+    private static final int DEFAULT_PRIORITY = 88;
+    private static final String DEFAULT_APP = "org.onosproject.drivers.polatis.netconf";
+    public static final int POWER_MULTIPLIER = 100;
+    public static final Range<Long> POWER_RANGE = Range.closed(-6000L, 2800L);
+
+    private PolatisOpticalUtility() {
+    }
+
+    /**
+     * Transforms a flow FlowRule object to a cross-connect object.
+     * @param behaviour the parent driver handler
+     * @param rule FlowRule object
+     * @return cross connect object
+     */
+    public static CrossConnects fromFlowRule(HandlerBehaviour behaviour, FlowRule rule) {
+        // TrafficSelector
+        Set<Criterion> criterions = rule.selector().criteria();
+        PortNumber inPort = criterions.stream()
+                .filter(c -> c instanceof PortCriterion)
+                .map(c -> ((PortCriterion) c).port())
+                .findAny()
+                .orElse(null);
+        // TrafficTreatment
+        List<Instruction> instructions = rule.treatment().immediate();
+        PortNumber outPort = instructions.stream()
+                .filter(c -> c instanceof Instructions.OutputInstruction)
+                .map(c -> ((Instructions.OutputInstruction) c).port())
+                .findAny()
+                .orElse(null);
+        DefaultCrossConnects crossConnects = new DefaultCrossConnects();
+        DefaultPair p = new DefaultPair();
+        p.ingress(new PortFormat(inPort.toLong()));
+        p.egress(new PortFormat(outPort.toLong()));
+        crossConnects.addToPair(p);
+        return crossConnects;
+    }
+
+    /**
+     * Finds the FlowRule from flow rule store by the given cross connect information.
+     * Returns an extra flow to remove the flow by ONOS if not found.
+     * @param behaviour the parent driver handler
+     * @param cfg cross connect information
+     * @return the flow rule
+     */
+    public static FlowRule toFlowRule(HandlerBehaviour behaviour, CrossConnects cfg) {
+        // Note: do we need to handle more than one pair? In any case, this
+        // looks strange.
+        Pair p = cfg.pair().get(0);
+        long i = p.ingress().uint32();
+        long o = p.egress().uint32();
+        PortNumber iPortNumber = PortNumber.portNumber(i);
+        PortNumber oPortNumber = PortNumber.portNumber(o);
+        return toFlowRule(behaviour, iPortNumber, oPortNumber);
+    }
+
+    /**
+     * Finds the FlowRule from flow rule store by the given ports and channel.
+     * Returns an extra flow to remove the flow by ONOS if not found.
+     * @param behaviour the parent driver handler
+     * @param inPort the input port
+     * @param outPort the output port
+     * @return the flow rule
+     */
+    public static FlowRule toFlowRule(HandlerBehaviour behaviour, PortNumber inPort,
+                                      PortNumber outPort) {
+        FlowRuleService service = behaviour.handler().get(FlowRuleService.class);
+        Iterable<FlowEntry> entries = service.getFlowEntries(behaviour.data().deviceId());
+        // Try to Find the flow from flow rule store.
+        for (FlowEntry entry : entries) {
+            Set<Criterion> criterions = entry.selector().criteria();
+            // input port
+            PortNumber ip = criterions.stream()
+                    .filter(c -> c instanceof PortCriterion)
+                    .map(c -> ((PortCriterion) c).port())
+                    .findAny()
+                    .orElse(null);
+            // output port
+            PortNumber op = entry.treatment().immediate().stream()
+                    .filter(c -> c instanceof Instructions.OutputInstruction)
+                    .map(c -> ((Instructions.OutputInstruction) c).port())
+                    .findAny()
+                    .orElse(null);
+            if (inPort.equals(ip) && outPort.equals(op)) {
+                // Find the flow.
+                return entry;
+            }
+        }
+        // Cannot find the flow from store. So report an extra flow to remove the flow by ONOS.
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchInPort(inPort)
+                .build();
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(outPort)
+                .build();
+        return DefaultFlowRule.builder()
+                .forDevice(behaviour.data().deviceId())
+                .withSelector(selector)
+                .withTreatment(treatment)
+                .makePermanent()
+                .withPriority(DEFAULT_PRIORITY)
+                .fromApp(behaviour.handler().get(CoreService.class).getAppId(DEFAULT_APP))
+                .build();
+
+    }
+}