[ODTN] Interface of a new driver behavior for checking internal connectivity in a device.

This would be used mostly for optical devices which typically have many connectivity constraints.

The patch also includes a CLI command to using driver behavior and an empty driver implementation.

patch 1: first draft: behaviour, CLI, empty driver, xml.

patch 2,3,4,6: checkstyle.

patch 5: comments by Andrea.

Change-Id: Ia1573a9f14b49c39c96fa3351ccc37988f1526ec
diff --git a/cli/src/main/java/org/onosproject/cli/net/InternalConnectivityCommand.java b/cli/src/main/java/org/onosproject/cli/net/InternalConnectivityCommand.java
new file mode 100644
index 0000000..939bdc4
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/InternalConnectivityCommand.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020-present 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.behaviour.InternalConnectivity;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+@Service
+@Command(scope = "onos", name = "check-internal-connectivity",
+        description = "Check if two port of a device can be connected")
+public class InternalConnectivityCommand extends AbstractShellCommand {
+
+    private static final Logger log = getLogger(BitErrorCommand.class);
+
+    @Argument(index = 0, name = "input port", description = "{DeviceID}/{PortNumber}",
+            required = true, multiValued = false)
+    @Completion(ConnectPointCompleter.class)
+    private String input = null;
+
+    @Argument(index = 1, name = "output port", description = "{DeviceID}/{PortNumber}",
+            required = true, multiValued = false)
+    @Completion(ConnectPointCompleter.class)
+    private String output = null;
+
+    @Override
+    protected void doExecute() throws Exception {
+        ConnectPoint inputConnectPoint = ConnectPoint.deviceConnectPoint(input);
+        ConnectPoint outputConnectPoint = ConnectPoint.deviceConnectPoint(output);
+
+        DeviceService deviceService = get(DeviceService.class);
+        DeviceId inputDeviceId = inputConnectPoint.deviceId();
+        DeviceId outputDeviceId = outputConnectPoint.deviceId();
+        PortNumber inputPortNumber = inputConnectPoint.port();
+        PortNumber outputPortNumber = outputConnectPoint.port();
+
+        InternalConnectivity internalConnectivityBehaviour;
+
+        if (!inputDeviceId.equals(outputDeviceId)) {
+            print("[ERROR] specified connect points should belong to the same device.");
+            return;
+        }
+
+        Device device = deviceService.getDevice(inputDeviceId);
+
+        if (device != null && device.is(InternalConnectivity.class)) {
+            internalConnectivityBehaviour = device.as(InternalConnectivity.class);
+        } else {
+            print("[ERROR] specified device %s does not support Internal Connectivity Behaviour.",
+                    device.toString());
+            return;
+        }
+
+        if (internalConnectivityBehaviour.testConnectivity(inputPortNumber, outputPortNumber)) {
+            print("[CONNECTIVITY ALLOWED] device %s from input-port %s to output-port %s",
+                    device.id().toString(),
+                    inputPortNumber.toString(),
+                    outputPortNumber.toString());
+        } else {
+            print("[CONNECTIVITY NOT ALLOWED] device %s from input-port %s to output-port %s",
+                    device.id().toString(),
+                    inputPortNumber.toString(),
+                    outputPortNumber.toString());
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/InternalConnectivity.java b/core/api/src/main/java/org/onosproject/net/behaviour/InternalConnectivity.java
new file mode 100644
index 0000000..c8e7bf9
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/InternalConnectivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020-present 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+
+package org.onosproject.net.behaviour;
+
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.HandlerBehaviour;
+
+import java.util.Set;
+
+/**
+ * Handler behaviour for retrieving internal connectivity information.
+ */
+public interface InternalConnectivity extends HandlerBehaviour {
+    /**
+     * Test if two ports of the device can be internally connected.
+     *
+     * @param inputPort in port of device
+     * @param outputPort out port of device
+     * @return true if inputPort can be connected outputPort
+     */
+    boolean testConnectivity(PortNumber inputPort, PortNumber outputPort);
+
+    /**
+     * Returns the set of output ports that can be connected to inputPort.
+     *
+     * @param inputPort in port of device
+     * @return list of output ports that can be connected to inputPort
+     */
+    Set<PortNumber> getOutputPorts(PortNumber inputPort);
+
+    /**
+     * Returns the set of input ports that can be connected to outputPort.
+     *
+     * @param outputPort out port of device
+     * @return list of input ports that can be connected to outputPort
+     */
+    Set<PortNumber> getInputPorts(PortNumber outputPort);
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/FullMeshInternalConnectivity.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/FullMeshInternalConnectivity.java
new file mode 100644
index 0000000..c279def
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/FullMeshInternalConnectivity.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020-present 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.
+
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.InternalConnectivity;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class FullMeshInternalConnectivity
+    extends AbstractHandlerBehaviour implements InternalConnectivity {
+
+    /**
+     * Returnung true for all pairs this implements a device with full connectivity.
+     *
+     * @param inputPort in port
+     * @param outputPort out port
+     * @return true if connectivity is allowed
+     */
+    @Override
+    public boolean testConnectivity(PortNumber inputPort, PortNumber outputPort) {
+        //It is not allowed touse the same port as input and output
+        if (inputPort.equals(outputPort)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * To be implemented.
+     *
+     * @param inputPort in port
+     * @return Set of out ports that can be connected to specified in port
+     */
+    @Override
+    public Set<PortNumber> getOutputPorts(PortNumber inputPort) {
+        Set<PortNumber> ports;
+
+        //Returns all the device ports, not including input port itself
+        DeviceService deviceService = this.handler().get(DeviceService.class);
+        ports = deviceService.getPorts(did()).stream()
+                .filter(p -> !p.equals(inputPort))
+                .map(p -> p.number())
+                .collect(Collectors.toSet());
+
+        return ports;
+    }
+
+    /**
+     * To be implemented.
+     *
+     * @param outputPort out port
+     * @return Set of in ports that can be connected to specified out port
+     */
+    @Override
+    public Set<PortNumber> getInputPorts(PortNumber outputPort) {
+        Set<PortNumber> ports;
+
+        //Returns all the device ports, not including output port itself
+        DeviceService deviceService = this.handler().get(DeviceService.class);
+        ports = deviceService.getPorts(did()).stream()
+                .filter(p -> !p.equals(outputPort))
+                .map(p -> p.number())
+                .collect(Collectors.toSet());
+
+        return ports;
+    }
+
+    /**
+     * Get the deviceId for which the methods apply.
+     *
+     * @return The deviceId as contained in the handler data
+     */
+    private DeviceId did() {
+        return handler().data().deviceId();
+    }
+}
diff --git a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
index a9e110f..a008a60 100644
--- a/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
+++ b/drivers/odtn-driver/src/main/resources/odtn-drivers.xml
@@ -54,6 +54,8 @@
                    impl="org.onosproject.drivers.odtn.openconfig.TerminalDeviceLambdaQuery"/>
         <behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
                    impl="org.onosproject.drivers.odtn.openconfig.ClientLineTerminalDeviceFlowRuleProgrammable"/>
+        <behaviour api="org.onosproject.net.behaviour.InternalConnectivity"
+                   impl="org.onosproject.drivers.odtn.FullMeshInternalConnectivity"/>
     </driver>
 
     <driver name="openroadm" extends="" manufacturer="CTTC/CNIT" hwVersion="0.0.1" swVersion="0.0.1">