[ONOS-7731] Add a set of CLI for openstack vtap app

Change-Id: I9e269cd549ba8c5e508c163b69f9e93a1b1074cf
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapAddCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapAddCommand.java
new file mode 100644
index 0000000..4b35474
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapAddCommand.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018-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.
+ */
+package org.onosproject.openstackvtap.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.TpPort;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.impl.DefaultOpenstackVtapCriterion;
+
+/**
+ * Command line interface for adding openstack vTap rule.
+ */
+@Command(scope = "onos", name = "openstack-vtap-add",
+        description = "OpenstackVtap activate")
+public class OpenstackVtapAddCommand extends AbstractShellCommand {
+
+    private final OpenstackVtapAdminService vTapService = get(OpenstackVtapAdminService.class);
+
+    @Argument(index = 0, name = "srcIp",
+            description = "source IP address CIDR (e.g., \"10.1.0.0/16\")",
+            required = true, multiValued = false)
+    String srcIp = "";
+
+    @Argument(index = 1, name = "dstIp",
+            description = "destination IP address CIDR (e.g., \"10.1.0.0/16\")",
+            required = true, multiValued = false)
+    String dstIp = "";
+
+    @Argument(index = 2, name = "ipProto",
+            description = "IP protocol [tcp|udp|icmp|none]",
+            required = false, multiValued = false)
+    String ipProto = "";
+
+    @Argument(index = 3, name = "srcTpPort",
+            description = "source transport layer port (0 is skip)",
+            required = false, multiValued = false)
+    int srcTpPort = 0;
+
+    @Argument(index = 4, name = "dstTpPort",
+            description = "destination transport layer port (0 is skip)",
+            required = false, multiValued = false)
+    int dstTpPort = 0;
+
+    @Argument(index = 5, name = "type",
+            description = "vTap type [all|tx|rx]",
+            required = false, multiValued = false)
+    String vTapTypeStr = "all";
+
+    @Override
+    protected void execute() {
+        DefaultOpenstackVtapCriterion.Builder
+                    defaultVtapCriterionBuilder = DefaultOpenstackVtapCriterion.builder();
+        if (makeCriterion(defaultVtapCriterionBuilder)) {
+            OpenstackVtap.Type type = getVtapType(vTapTypeStr);
+            if (type == null) {
+                print("Invalid vTap type");
+                return;
+            }
+
+            OpenstackVtap vTap = vTapService.createVtap(type, defaultVtapCriterionBuilder.build());
+            if (vTap != null) {
+                print("Created OpenstackVtap with id { %s }", vTap.id().toString());
+            } else {
+                print("Failed to create OpenstackVtap");
+            }
+        }
+    }
+
+    private static OpenstackVtap.Type getVtapType(String vTapTypeStr) {
+        switch (vTapTypeStr.toLowerCase()) {
+            case "all":
+                return OpenstackVtap.Type.VTAP_ALL;
+            case "tx":
+                return OpenstackVtap.Type.VTAP_TX;
+            case "rx":
+                return OpenstackVtap.Type.VTAP_RX;
+            default:
+                return OpenstackVtap.Type.VTAP_NONE;
+       }
+    }
+
+    private boolean makeCriterion(DefaultOpenstackVtapCriterion.Builder vTapCriterionBuilder) {
+        try {
+            vTapCriterionBuilder.srcIpPrefix(IpPrefix.valueOf(srcIp));
+            vTapCriterionBuilder.dstIpPrefix(IpPrefix.valueOf(dstIp));
+        } catch (Exception e) {
+            print("Inputted valid source IP & destination IP in CIDR (e.g., \"10.1.0.0/16\")");
+            return false;
+        }
+
+        switch (ipProto.toLowerCase()) {
+            case "tcp":
+                vTapCriterionBuilder.ipProtocol(IPv4.PROTOCOL_TCP);
+                break;
+            case "udp":
+                vTapCriterionBuilder.ipProtocol(IPv4.PROTOCOL_UDP);
+                break;
+            case "icmp":
+                vTapCriterionBuilder.ipProtocol(IPv4.PROTOCOL_ICMP);
+                break;
+            default:
+                log.warn("Invalid protocol type {}", ipProto);
+                return false;
+        }
+
+        vTapCriterionBuilder.srcTpPort(TpPort.tpPort(srcTpPort));
+        vTapCriterionBuilder.dstTpPort(TpPort.tpPort(dstTpPort));
+
+        return true;
+    }
+
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapDeleteCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapDeleteCommand.java
new file mode 100644
index 0000000..267d15e
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapDeleteCommand.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018-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.
+ */
+package org.onosproject.openstackvtap.cli;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.apache.karaf.shell.commands.Argument;
+import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.api.OpenstackVtapId;
+
+/**
+ * Command line interface for removing openstack vTap rule.
+ */
+@Command(scope = "onos", name = "openstack-vtap-del",
+        description = "OpenstackVtap deactivate")
+public class OpenstackVtapDeleteCommand extends AbstractShellCommand {
+
+    private final OpenstackVtapAdminService vTapService = get(OpenstackVtapAdminService.class);
+
+    @Argument(index = 0, name = "id", description = "vTap ID",
+            required = true, multiValued = false)
+    String vTapId = "";
+
+    @Override
+    protected void execute() {
+        OpenstackVtap vTap = vTapService.removeVtap(OpenstackVtapId.vTapId(vTapId));
+        if (vTap != null) {
+            print("Removed OpenstackVtap with id { %s }", vTap.id().toString());
+        } else {
+            print("Failed to remove OpenstackVtap with id { %s }", vTap.id().toString());
+        }
+    }
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapListCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapListCommand.java
new file mode 100644
index 0000000..9da2d63
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapListCommand.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018-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.
+ */
+package org.onosproject.openstackvtap.cli;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.apache.karaf.shell.commands.Argument;
+import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapService;
+
+import java.util.Set;
+
+/**
+ * Command line interface for listing openstack vTap rules.
+ */
+@Command(scope = "onos", name = "openstack-vtap-list",
+        description = "OpenstackVtap list")
+public class OpenstackVtapListCommand extends AbstractShellCommand {
+
+    private final OpenstackVtapService vTapService = get(OpenstackVtapService.class);
+
+    @Argument(index = 0, name = "type",
+            description = "vTap type [all|tx|rx]",
+            required = false, multiValued = false)
+    String vTapType = "none";
+
+    private static final String FORMAT = "ID { %s }: type [%s], srcIP [%s], dstIP [%s]";
+    private static final String FORMAT_TX_DEVICES  = "   tx devices: %s";
+    private static final String FORMAT_RX_DEVICES  = "   rx devices: %s";
+
+    @Override
+    protected void execute() {
+        OpenstackVtap.Type type;
+        switch (vTapType) {
+            case "none":
+                type = OpenstackVtap.Type.VTAP_NONE;
+                break;
+            case "all":
+                type = OpenstackVtap.Type.VTAP_ALL;
+                break;
+            case "tx":
+                type = OpenstackVtap.Type.VTAP_TX;
+                break;
+            case "rx":
+                type = OpenstackVtap.Type.VTAP_RX;
+                break;
+            default:
+                print("Invalid vTap type");
+                return;
+        }
+
+        Set<OpenstackVtap> openstackVtaps = vTapService.getVtaps(type);
+        for (OpenstackVtap vTap : openstackVtaps) {
+            print(FORMAT,
+                    vTap.id().toString(),
+                    vTap.type().toString(),
+                    vTap.vTapCriterion().srcIpPrefix().toString(),
+                    vTap.vTapCriterion().dstIpPrefix().toString());
+            print(FORMAT_TX_DEVICES, vTap.txDeviceIds());
+            print(FORMAT_RX_DEVICES, vTap.rxDeviceIds());
+        }
+    }
+
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapOutputCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapOutputCommand.java
new file mode 100644
index 0000000..293b62e
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapOutputCommand.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018-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.
+ */
+package org.onosproject.openstackvtap.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+
+import static org.onlab.packet.VlanId.UNTAGGED;
+
+/**
+ * Command line interface for set openstack vTap output.
+ */
+@Command(scope = "onos", name = "openstack-vtap-output",
+        description = "OpenstackVtap output setup")
+public class OpenstackVtapOutputCommand extends AbstractShellCommand {
+
+    private final DeviceService deviceService = get(DeviceService.class);
+    private final OpenstackVtapAdminService vTapAdminService = get(OpenstackVtapAdminService.class);
+
+    @Argument(index = 0, name = "deviceId", description = "device id",
+            required = true, multiValued = false)
+    String id = "";
+
+    @Argument(index = 1, name = "port", description = "output port number",
+            required = true, multiValued = false)
+    int port = 0;
+
+    @Argument(index = 2, name = "vlan", description = "vlan id",
+            required = false, multiValued = false)
+    int vlan = UNTAGGED;
+
+    @Argument(index = 3, name = "type", description = "vTap type [all|tx|rx]",
+            required = false, multiValued = false)
+    String vTapType = "all";
+
+    @Override
+    protected void execute() {
+        try {
+            Device device = deviceService.getDevice(DeviceId.deviceId(id));
+            if (device != null) {
+                OpenstackVtap.Type type = getVtapType(vTapType);
+                if (type == null) {
+                    print("Invalid vTap type");
+                    return;
+                }
+
+                vTapAdminService.setVtapOutput(device.id(), type,
+                        PortNumber.portNumber(port), VlanId.vlanId((short) vlan));
+                print("Set OpenstackVtap output deviceId { %s }, port=%s, vlan=%s",
+                        device.id().toString(),
+                        PortNumber.portNumber(port).toString(),
+                        VlanId.vlanId((short) vlan).toString());
+            } else {
+                print("Invalid device id");
+            }
+        } catch (Exception e) {
+            print("Invalid parameter: %s", e.toString());
+        }
+    }
+
+    private static OpenstackVtap.Type getVtapType(String str) {
+        switch (str) {
+            case "all":
+                return OpenstackVtap.Type.VTAP_ALL;
+            case "tx":
+                return OpenstackVtap.Type.VTAP_TX;
+            case "rx":
+                return OpenstackVtap.Type.VTAP_RX;
+            default:
+                return OpenstackVtap.Type.VTAP_NONE;
+        }
+    }
+}
diff --git a/apps/openstackvtap/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/openstackvtap/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 0000000..49c2e50
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,34 @@
+<!--
++  ~ Copyright 2018-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.
++  -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.onosproject.openstackvtap.cli.OpenstackVtapAddCommand" />
+        </command>
+
+        <command>
+            <action class="org.onosproject.openstackvtap.cli.OpenstackVtapListCommand" />
+        </command>
+
+        <command>
+            <action class="org.onosproject.openstackvtap.cli.OpenstackVtapDeleteCommand" />
+        </command>
+
+        <command>
+            <action class="org.onosproject.openstackvtap.cli.OpenstackVtapOutputCommand" />
+        </command>
+    </command-bundle>
+</blueprint>