[ONOS-7731] Update api interface & implementation of openstack vtap app
Change-Id: I7c3c7888b00a7357b13e3b1756e9cd0a1bb6a5c0
diff --git a/apps/openstackvtap/app/BUCK b/apps/openstackvtap/app/BUCK
index dc3f55c..3656f6c 100644
--- a/apps/openstackvtap/app/BUCK
+++ b/apps/openstackvtap/app/BUCK
@@ -25,8 +25,8 @@
deps = COMPILE_DEPS,
test_deps = TEST_DEPS,
web_context = '/onos/openstackvtap',
- api_title = 'OpenStack Network vTap REST API',
+ api_title = 'OpenStack Vtap REST API',
api_version = '1.0',
- api_description = 'OpenStack Network vTap REST API',
+ api_description = 'OpenStack Vtap REST API',
api_package = 'org.onosproject.openstackvtap.web',
)
diff --git a/apps/openstackvtap/app/BUILD b/apps/openstackvtap/app/BUILD
index 078ed2b..7d2ceba 100644
--- a/apps/openstackvtap/app/BUILD
+++ b/apps/openstackvtap/app/BUILD
@@ -12,9 +12,9 @@
]
osgi_jar_with_tests(
- api_description = "OpenStack Network vTap REST API",
+ api_description = "Openstack Vtap REST API",
api_package = "org.onosproject.openstackvtap.web",
- api_title = "OpenStack Network vTap REST API",
+ api_title = "Openstack Vtap REST API",
api_version = "1.0",
test_deps = TEST_DEPS,
web_context = "/onos/openstackvtap",
diff --git a/apps/openstackvtap/app/app.xml b/apps/openstackvtap/app/app.xml
index 45024d9..b077858 100644
--- a/apps/openstackvtap/app/app.xml
+++ b/apps/openstackvtap/app/app.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
<app name="org.onosproject.openstackvtap" origin="Open Networking Foundation"
- version="${project.version}" category="Utility" title="OpenStack vTap App"
+ version="${project.version}" category="Utility" title="Openstack Vtap App"
features="${project.artifactId}" apps="org.onosproject.openstacknetworking"
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features">
<description>${project.description}</description>
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
index 8d9955f..5272083 100644
--- 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
@@ -28,13 +28,13 @@
import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
/**
- * Command line interface for adding openstack vTap rule.
+ * Adds a openstack vtap rule.
*/
@Command(scope = "onos", name = "openstack-vtap-add",
description = "OpenstackVtap activate")
public class OpenstackVtapAddCommand extends AbstractShellCommand {
- private final OpenstackVtapAdminService vTapService =
+ private final OpenstackVtapAdminService vtapService =
get(OpenstackVtapAdminService.class);
@Argument(index = 0, name = "srcIp",
@@ -48,9 +48,9 @@
String dstIp = "";
@Argument(index = 2, name = "ipProto",
- description = "IP protocol [tcp|udp|icmp|none]",
+ description = "IP protocol [any|tcp|udp|icmp]",
required = false, multiValued = false)
- String ipProto = "";
+ String ipProto = "any";
@Argument(index = 3, name = "srcTpPort",
description = "source transport layer port (0 is skip)",
@@ -63,43 +63,42 @@
int dstTpPort = 0;
@Argument(index = 5, name = "type",
- description = "vTap type [all|tx|rx]",
+ description = "vtap type [all|rx|tx]",
required = false, multiValued = false)
- String vTapTypeStr = "all";
+ String vtapTypeStr = "all";
@Override
protected void execute() {
- DefaultOpenstackVtapCriterion.Builder
- defaultVtapCriterionBuilder = DefaultOpenstackVtapCriterion.builder();
- if (makeCriterion(defaultVtapCriterionBuilder)) {
- OpenstackVtap.Type type = getVtapTypeFromString(vTapTypeStr);
+ DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder = DefaultOpenstackVtapCriterion.builder();
+ if (makeCriterion(vtapCriterionBuilder)) {
+ OpenstackVtap.Type type = getVtapTypeFromString(vtapTypeStr);
if (type == null) {
- print("Invalid vTap type");
+ print("Invalid vtap type");
return;
}
- OpenstackVtap vTap = vTapService.createVtap(type, defaultVtapCriterionBuilder.build());
- if (vTap != null) {
- print("Created OpenstackVtap with id { %s }", vTap.id().toString());
+ OpenstackVtap vtap = vtapService.createVtap(type, vtapCriterionBuilder.build());
+ if (vtap != null) {
+ print("Created OpenstackVtap with id { %s }", vtap.id().toString());
} else {
print("Failed to create OpenstackVtap");
}
}
}
- private boolean makeCriterion(DefaultOpenstackVtapCriterion.Builder vTapCriterionBuilder) {
+ private boolean makeCriterion(DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder) {
try {
- vTapCriterionBuilder.srcIpPrefix(IpPrefix.valueOf(srcIp));
- vTapCriterionBuilder.dstIpPrefix(IpPrefix.valueOf(dstIp));
+ 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.4/32\")");
return false;
}
- vTapCriterionBuilder.ipProtocol(getProtocolTypeFromString(ipProto.toLowerCase()));
+ vtapCriterionBuilder.ipProtocol(getProtocolTypeFromString(ipProto.toLowerCase()));
- vTapCriterionBuilder.srcTpPort(TpPort.tpPort(srcTpPort));
- vTapCriterionBuilder.dstTpPort(TpPort.tpPort(dstTpPort));
+ 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
index e4a167b..e54f6ac 100644
--- 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
@@ -22,25 +22,25 @@
import org.onosproject.openstackvtap.api.OpenstackVtapId;
/**
- * Command line interface for removing openstack vTap rule.
+ * Delete a openstack vtap rule from the existing vtaps.
*/
@Command(scope = "onos", name = "openstack-vtap-del",
description = "OpenstackVtap deactivate")
public class OpenstackVtapDeleteCommand extends AbstractShellCommand {
- private final OpenstackVtapAdminService vTapService = get(OpenstackVtapAdminService.class);
+ private final OpenstackVtapAdminService vtapService = get(OpenstackVtapAdminService.class);
- @Argument(index = 0, name = "id", description = "vTap ID",
+ @Argument(index = 0, name = "id", description = "vtap ID",
required = true, multiValued = false)
- String vTapId = "";
+ 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());
+ 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 }", vTapId);
+ print("Failed to remove OpenstackVtap with id { %s }", vtapId);
}
}
}
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
index afb9bbf..a0989b33d 100644
--- 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
@@ -15,46 +15,66 @@
*/
package org.onosproject.openstackvtap.cli;
+import com.google.common.collect.ImmutableSet;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.onosproject.openstackvtap.api.OpenstackVtap;
import org.onosproject.openstackvtap.api.OpenstackVtapService;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
/**
- * Command line interface for listing openstack vTap rules.
+ * Lists 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);
+ private final OpenstackVtapService vtapService = get(OpenstackVtapService.class);
+ private final OpenstackNodeService osNodeService = get(OpenstackNodeService.class);
@Argument(index = 0, name = "type",
- description = "vTap type [all|tx|rx]",
+ description = "vtap type [any|all|rx|tx]",
required = false, multiValued = false)
- String vTapType = "none";
+ String vtapType = "any";
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";
+ private static final String FORMAT_TX_NODES = " tx openstack nodes: %s";
+ private static final String FORMAT_RX_NODES = " rx openstack nodes: %s";
@Override
protected void execute() {
- OpenstackVtap.Type type = getVtapTypeFromString(vTapType);
- Set<OpenstackVtap> openstackVtaps = vTapService.getVtaps(type);
- for (OpenstackVtap vTap : openstackVtaps) {
+ OpenstackVtap.Type type = getVtapTypeFromString(vtapType);
+ 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());
+ vtap.id().toString(),
+ vtap.type().toString(),
+ vtap.vtapCriterion().srcIpPrefix().toString(),
+ vtap.vtapCriterion().dstIpPrefix().toString());
+ print(FORMAT_TX_NODES, osNodeNames(vtap.txDeviceIds()));
+ print(FORMAT_RX_NODES, osNodeNames(vtap.rxDeviceIds()));
}
}
+
+ private Set<String> osNodeNames(Set<DeviceId> deviceIds) {
+ if (deviceIds == null) {
+ return ImmutableSet.of();
+ } else {
+ return deviceIds.parallelStream()
+ .map(osNodeService::node)
+ .filter(Objects::nonNull)
+ .map(OpenstackNode::hostname)
+ .collect(Collectors.toSet());
+ }
+ }
+
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapNetworkListCommand.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapNetworkListCommand.java
new file mode 100644
index 0000000..68a94f8
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapNetworkListCommand.java
@@ -0,0 +1,68 @@
+/*
+ * 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 com.google.common.collect.ImmutableSet;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Lists openstack vtap networks.
+ */
+@Command(scope = "onos", name = "openstack-vtap-network-list",
+ description = "OpenstackVtap network list")
+public class OpenstackVtapNetworkListCommand extends AbstractShellCommand {
+
+ private final OpenstackVtapAdminService osVtapAdminService = get(OpenstackVtapAdminService.class);
+ private final OpenstackNodeService osNodeService = get(OpenstackNodeService.class);
+
+ private static final String FORMAT = "mode [%s], networkId [%d], serverIp [%s]";
+ private static final String FORMAT_NODES = " openstack nodes: %s";
+
+ @Override
+ protected void execute() {
+ OpenstackVtapNetwork vtapNetwork = osVtapAdminService.getVtapNetwork();
+ if (vtapNetwork != null) {
+ print(FORMAT,
+ vtapNetwork.mode().toString(),
+ vtapNetwork.networkId() != null ? vtapNetwork.networkId() : "N/A",
+ vtapNetwork.serverIp().toString());
+ print(FORMAT_NODES, osNodeNames(osVtapAdminService.getVtapNetworkDevices()));
+ }
+ }
+
+ private Set<String> osNodeNames(Set<DeviceId> deviceIds) {
+ if (deviceIds == null) {
+ return ImmutableSet.of();
+ } else {
+ return deviceIds.parallelStream()
+ .map(osNodeService::node)
+ .filter(Objects::nonNull)
+ .map(OpenstackNode::hostname)
+ .collect(Collectors.toSet());
+ }
+ }
+
+}
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
deleted file mode 100644
index 257cb9a..0000000
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/OpenstackVtapOutputCommand.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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;
-import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
-
-/**
- * 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 vTapTypeStr = "all";
-
- @Override
- protected void execute() {
- try {
- Device device = deviceService.getDevice(DeviceId.deviceId(id));
- if (device != null) {
- OpenstackVtap.Type type = getVtapTypeFromString(vTapTypeStr);
-
- 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());
- }
- }
-}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java
index 3d0f747..3bfcf2b 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/ProtocolTypeCompleter.java
@@ -28,10 +28,10 @@
@Override
protected List<String> choices() {
List<String> strings = Lists.newArrayList();
+ strings.add("any");
strings.add("tcp");
strings.add("udp");
strings.add("icmp");
- strings.add("none");
return strings;
}
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java
index c53098d..dad6e8e 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapIdCompleter.java
@@ -27,11 +27,11 @@
import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
/**
- * vTap ID completer.
+ * Vtap ID completer.
*/
public class VtapIdCompleter implements Completer {
- private static final String VTAP_TYPE = "none";
+ private static final String VTAP_TYPE = "any";
@Override
public int complete(String buffer, int cursor, List<String> candidates) {
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java
index 2784833..c77c913 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/VtapTypeCompleter.java
@@ -21,16 +21,17 @@
import java.util.List;
/**
- * vTap type completer.
+ * Vtap type completer.
*/
public class VtapTypeCompleter extends AbstractChoicesCompleter {
@Override
protected List<String> choices() {
List<String> strings = Lists.newArrayList();
- strings.add("tx");
- strings.add("rx");
strings.add("all");
+ strings.add("rx");
+ strings.add("tx");
+ strings.add("any");
return strings;
}
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java
index 772bbc8..3b3dec1 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/cli/package-info.java
@@ -15,6 +15,6 @@
*/
/**
- * Console commands for OpenStack vtap.
+ * Console commands for openstack vtap.
*/
package org.onosproject.openstackvtap.cli;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/OpenstackVtapNetworkCodec.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/OpenstackVtapNetworkCodec.java
new file mode 100644
index 0000000..6dd6b5c
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/OpenstackVtapNetworkCodec.java
@@ -0,0 +1,73 @@
+/*
+ * 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.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.openstackvtap.impl.DefaultOpenstackVtapNetwork;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Openstack vtap network codec used for serializing and de-serializing JSON string.
+ */
+public final class OpenstackVtapNetworkCodec extends JsonCodec<OpenstackVtapNetwork> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String MODE = "mode";
+ private static final String NETWORK_ID = "networkId";
+ private static final String SERVER_IP = "serverIp";
+ private static final String NODES = "nodes";
+
+ private static final String JSON_NULL_MESSAGE = "% cannot be null";
+ private static final String JSON_MISSING_MESSAGE = "% is required";
+ private static final String JSON_TYPE_MESSAGE = "% is not json object type";
+
+ @Override
+ public ObjectNode encode(OpenstackVtapNetwork network, CodecContext context) {
+ checkNotNull(network, JSON_NULL_MESSAGE, "OpenstackVtapNetwork object");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(MODE, network.mode().toString())
+ .put(NETWORK_ID, network.networkId())
+ .put(SERVER_IP, network.serverIp().toString());
+
+ return result;
+ }
+
+ @Override
+ public OpenstackVtapNetwork decode(ObjectNode json, CodecContext context) {
+ checkNotNull(json, JSON_NULL_MESSAGE, "OpenstackVtapNetwork json");
+ checkState(json.isObject(), JSON_TYPE_MESSAGE, "OpenstackVtapNetwork json");
+
+ DefaultOpenstackVtapNetwork.Builder builder = DefaultOpenstackVtapNetwork.builder()
+ .mode(OpenstackVtapNetwork.Mode.valueOf(checkNotNull(json.get(MODE).asText(null),
+ JSON_MISSING_MESSAGE, MODE)))
+ .networkId(json.get(NETWORK_ID).asInt(0))
+ .serverIp(IpAddress.valueOf(checkNotNull(json.get(SERVER_IP).asText(null),
+ JSON_MISSING_MESSAGE, SERVER_IP)));
+
+ log.debug("OpenstackVtapNetwork is {}", builder.build().toString());
+ return builder.build();
+ }
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/package-info.java
new file mode 100644
index 0000000..f76f7a9
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/codec/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implementations of the codec broker and openstack vtap entity JSON codecs.
+ */
+package org.onosproject.openstackvtap.codec;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUI.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUI.java
new file mode 100644
index 0000000..c68c338
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUI.java
@@ -0,0 +1,85 @@
+/*
+ * 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.gui;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.ui.UiExtensionService;
+import org.onosproject.ui.UiMessageHandlerFactory;
+import org.onosproject.ui.UiTopoOverlayFactory;
+import org.onosproject.ui.UiView;
+import org.onosproject.ui.UiViewHidden;
+import org.onosproject.ui.UiExtension;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Mechanism to stream data to the GUI.
+ */
+@Component(immediate = true, enabled = true)
+@Service(value = OpenstackVtapUI.class)
+public class OpenstackVtapUI {
+ private static final String OPENSTACK_VTAP_ID = "openstackvtap";
+ private static final String RESOURCE_PATH = "gui";
+ private static final ClassLoader CL = OpenstackVtapUI.class.getClassLoader();
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected UiExtensionService uiExtensionService;
+
+ // Factory for UI message handlers
+ private final UiMessageHandlerFactory messageHandlerFactory =
+ () -> ImmutableList.of(new OpenstackVtapViewMessageHandler());
+
+ // List of application views
+ private final List<UiView> views = ImmutableList.of(
+ new UiViewHidden(OPENSTACK_VTAP_ID)
+ );
+
+ // Factory for UI topology overlays
+ private final UiTopoOverlayFactory topoOverlayFactory =
+ () -> ImmutableList.of(
+ new OpenstackVtapUiTopovOverlay()
+ );
+
+ // Application UI extension
+ private final UiExtension uiExtension =
+ new UiExtension.Builder(CL, views)
+ .messageHandlerFactory(messageHandlerFactory)
+ .resourcePath(RESOURCE_PATH)
+ .topoOverlayFactory(topoOverlayFactory)
+ .build();
+
+ @Activate
+ protected void activate() {
+ uiExtensionService.register(uiExtension);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ uiExtensionService.unregister(uiExtension);
+ log.info("Stopped");
+ }
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUiTopovOverlay.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUiTopovOverlay.java
new file mode 100644
index 0000000..287aa99
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapUiTopovOverlay.java
@@ -0,0 +1,40 @@
+/*
+ * 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.gui;
+
+import org.onosproject.ui.UiTopoOverlay;
+
+public class OpenstackVtapUiTopovOverlay extends UiTopoOverlay {
+ private static final String OVERLAY_ID = "vtap-overlay";
+
+ public OpenstackVtapUiTopovOverlay() {
+ super(OVERLAY_ID);
+ }
+
+ @Override
+ public void activate() {
+ super.activate();
+ log.debug("Openstack VtapOverlay Activated");
+ }
+
+ @Override
+ public void deactivate() {
+ super.deactivate();
+ log.debug("Openstack VtapOverlay Deactivated");
+ }
+
+}
+
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapViewMessageHandler.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapViewMessageHandler.java
new file mode 100644
index 0000000..f95bbc4
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/OpenstackVtapViewMessageHandler.java
@@ -0,0 +1,230 @@
+/*
+ * 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.gui;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.ui.RequestHandler;
+import org.onosproject.ui.UiConnection;
+import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Collection;
+import java.util.Set;
+import java.util.Iterator;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.TpPort;
+import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.impl.DefaultOpenstackVtapCriterion;
+
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getProtocolTypeFromString;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getVtapTypeFromString;
+
+
+import static org.onosproject.net.HostId.hostId;
+
+/**
+ * Message handler for Openstack Vtap related messages.
+ */
+public class OpenstackVtapViewMessageHandler extends UiMessageHandler {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String OSV_IS_ACTIVATED_REQ = "openstackVtapIsActivatedRequest";
+ private static final String OSV_IS_ACTIVATED_RESP = "openstackVtapIsActivatedResponse";
+ private static final String OSV_CREATE_REQ = "openstackVtapCreateRequest";
+ private static final String OSV_CREATE_RESP = "openstackVtapCreateResponse";
+
+ private static final String SOURCE = "src";
+ private static final String DESTINATION = "dst";
+ private static final String SOURCE_IP = "srcIp";
+ private static final String DESTINATION_IP = "dstIp";
+ private static final String SOURCE_TRANSPORT_PORT = "srcPort";
+ private static final String DESTINATION_TRANSPORT_PORT = "dstPort";
+ private static final String SOURCE_HOST_NAME = "srcName";
+ private static final String DESTINATION_HOST_NAME = "dstName";
+ private static final String IP_PROTOCOL = "ipProto";
+ private static final String VTAP_TYPE = "vtapType";
+ private static final String IP_PROTOCOL_LIST = "ipProtoList";
+ private static final String VTAP_TYPE_LIST = "vtapTypeList";
+
+ private static final String RESULT = "result";
+ private static final String VALUE = "value";
+ private static final String SUCCESS = "Success";
+ private static final String FAILED = "Failed";
+ private static final String INVALID_VTAP_TYPE = "Invalid vtap type";
+ private static final String FAILED_TO_CREATE_VTAP = "Failed to create OpenstackVtap";
+ private static final String WRONG_IP_ADDRESS =
+ "Inputted valid source & destination IP in CIDR (e.g., \"10.1.0.4/32\")";
+ private static final String INVALID_TRANSPORT_PORT =
+ "Invalid source & destination transport port has been entered";
+
+ private static final String[] IP_PROTOCOL_ARRAY = {"Any", "TCP", "UDP", "ICMP"};
+ private static final String[] VTAP_TYPE_ARRAY = {"All", "RX", "TX"};
+
+ private HostService hostService;
+ private OpenstackVtapAdminService vtapService;
+
+ @Override
+ public void init(UiConnection connection, ServiceDirectory directory) {
+ super.init(connection, directory);
+
+ hostService = directory.get(HostService.class);
+ vtapService = directory.get(OpenstackVtapAdminService.class);
+ }
+
+ @Override
+ protected Collection<RequestHandler> createRequestHandlers() {
+ return ImmutableSet.of(
+ new VtapIsActivatedRequestHandler(),
+ new VtapCreateRequestHandler()
+ );
+
+ }
+
+ private final class VtapIsActivatedRequestHandler extends RequestHandler {
+
+ private VtapIsActivatedRequestHandler() {
+ super(OSV_IS_ACTIVATED_REQ);
+ }
+
+ @Override
+ public void process(ObjectNode payload) {
+ String srcId = string(payload, SOURCE, null);
+ String dstId = string(payload, DESTINATION, null);
+
+ if (srcId != null && dstId != null) {
+ HostId sHostId = hostId(srcId);
+ HostId dHostId = hostId(dstId);
+
+ Host sHost = hostService.getHost(sHostId);
+ Host dHost = hostService.getHost(dHostId);
+
+ if (sHost != null && dHost != null) {
+ ArrayNode ipProtos = arrayNode();
+ ArrayNode types = arrayNode();
+ String sHostName = ipForHost(sHost);
+ String dHostName = ipForHost(dHost);
+
+ for (String proto : IP_PROTOCOL_ARRAY) {
+ ipProtos.add(proto);
+ }
+
+ for (String type : VTAP_TYPE_ARRAY) {
+ types.add(type);
+ }
+
+ payload.put(SOURCE_HOST_NAME, sHostName);
+ payload.put(DESTINATION_HOST_NAME, dHostName);
+ payload.put(IP_PROTOCOL_LIST, ipProtos);
+ payload.put(VTAP_TYPE_LIST, types);
+
+ sendMessage(OSV_IS_ACTIVATED_RESP, payload);
+ }
+ }
+ }
+
+ // Returns the first of the given host's set of IP addresses as a string.
+ private String ipForHost(Host host) {
+ Set<IpAddress> ipAddresses = host.ipAddresses();
+ Iterator<IpAddress> it = ipAddresses.iterator();
+ return it.hasNext() ? it.next().toString() + "/32" : "unknown";
+ }
+ }
+
+ private final class VtapCreateRequestHandler extends RequestHandler {
+ private String srcIp;
+ private String dstIp;
+ private String ipProto;
+ private String srcTpPort;
+ private String dstTpPort;
+ private String vtapTypeStr;
+ private ObjectNode result = objectNode();
+
+ private VtapCreateRequestHandler() {
+ super(OSV_CREATE_REQ);
+ }
+
+ @Override
+ public void process(ObjectNode payload) {
+ srcIp = string(payload, SOURCE_IP, null);
+ dstIp = string(payload, DESTINATION_IP, null);
+ ipProto = string(payload, IP_PROTOCOL, null);
+ srcTpPort = string(payload, SOURCE_TRANSPORT_PORT, null);
+ dstTpPort = string(payload, DESTINATION_TRANSPORT_PORT, null);
+ vtapTypeStr = string(payload, VTAP_TYPE, null);
+ log.trace("VtapCreateRequestHandler payload srcIp:{}, dstIp:{}, ipPro:{}, " +
+ "srcTpPort:{}, dstTpPort:{}, vtapType:{}", srcIp, dstIp, ipProto,
+ srcTpPort, dstTpPort, vtapTypeStr);
+
+ DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder = DefaultOpenstackVtapCriterion.builder();
+ if (makeCriterion(vtapCriterionBuilder)) {
+ OpenstackVtap.Type type = getVtapTypeFromString(vtapTypeStr.toLowerCase());
+ if (type == null) {
+ log.warn(INVALID_VTAP_TYPE);
+ result.put(RESULT, FAILED);
+ result.put(VALUE, INVALID_VTAP_TYPE);
+ sendMessage(OSV_CREATE_RESP, result);
+ return;
+ }
+
+ OpenstackVtap vtap = vtapService.createVtap(type, vtapCriterionBuilder.build());
+ if (vtap != null) {
+ log.info("Created OpenstackVtap with id {}", vtap.id().toString());
+ result.put(RESULT, SUCCESS);
+ result.put(VALUE, "vtap id: " + vtap.id().toString());
+ } else {
+ log.warn(FAILED_TO_CREATE_VTAP);
+ result.put(RESULT, FAILED);
+ result.put(VALUE, FAILED_TO_CREATE_VTAP);
+ }
+ }
+ sendMessage(OSV_CREATE_RESP, result);
+ }
+
+ private boolean makeCriterion(DefaultOpenstackVtapCriterion.Builder vtapCriterionBuilder) {
+ try {
+ vtapCriterionBuilder.srcIpPrefix(IpPrefix.valueOf(srcIp));
+ vtapCriterionBuilder.dstIpPrefix(IpPrefix.valueOf(dstIp));
+ } catch (Exception e) {
+ log.warn(WRONG_IP_ADDRESS);
+ result.put(RESULT, FAILED);
+ result.put(VALUE, WRONG_IP_ADDRESS);
+ return false;
+ }
+
+ vtapCriterionBuilder.ipProtocol(getProtocolTypeFromString(ipProto.toLowerCase()));
+
+ try {
+ vtapCriterionBuilder.srcTpPort(TpPort.tpPort(Integer.valueOf(srcTpPort)));
+ vtapCriterionBuilder.dstTpPort(TpPort.tpPort(Integer.valueOf(dstTpPort)));
+ } catch (Exception e) {
+ log.warn(INVALID_TRANSPORT_PORT);
+ result.put(RESULT, FAILED);
+ result.put(VALUE, INVALID_TRANSPORT_PORT);
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/package-info.java
new file mode 100644
index 0000000..7521561
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/gui/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Web GUI for the control plane manager.
+ */
+package org.onosproject.openstackvtap.gui;
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java
index d5c842f..cc258c0 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtap.java
@@ -15,9 +15,7 @@
*/
package org.onosproject.openstackvtap.impl;
-import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
import org.onosproject.net.AbstractDescription;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DeviceId;
@@ -26,33 +24,47 @@
import org.onosproject.openstackvtap.api.OpenstackVtapCriterion;
import org.onosproject.openstackvtap.api.OpenstackVtapId;
+import java.util.Objects;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
/**
- * Default implementation of an immutable openstack vTap.
+ * Default implementation of an immutable OpenstackVtap.
*/
public final class DefaultOpenstackVtap extends AbstractDescription implements OpenstackVtap {
private final OpenstackVtapId id;
private final Type type;
- private final OpenstackVtapCriterion vTapCriterion;
+ private final OpenstackVtapCriterion vtapCriterion;
private final Set<DeviceId> txDeviceIds;
private final Set<DeviceId> rxDeviceIds;
- // private constructor not intended to use from external
- private DefaultOpenstackVtap(OpenstackVtapId id, Type type,
- OpenstackVtapCriterion vTapCriterion,
- Set<DeviceId> txDeviceIds, Set<DeviceId> rxDeviceIds,
+ /**
+ * Creates an DefaultOpenstackVtap using the supplied information.
+ *
+ * @param id vtap identifier
+ * @param type type of vtap (all,rx,tx)
+ * @param vtapCriterion criterion of vtap
+ * @param txDeviceIds device identifiers applied by vtap tx
+ * @param rxDeviceIds device identifiers applied by vtap rx
+ * @param annotations optional key/value annotations
+ */
+ private DefaultOpenstackVtap(OpenstackVtapId id,
+ Type type,
+ OpenstackVtapCriterion vtapCriterion,
+ Set<DeviceId> txDeviceIds,
+ Set<DeviceId> rxDeviceIds,
SparseAnnotations... annotations) {
super(annotations);
- this.id = id;
- this.type = type;
- this.vTapCriterion = vTapCriterion;
- this.txDeviceIds = txDeviceIds;
- this.rxDeviceIds = rxDeviceIds;
+ this.id = checkNotNull(id);
+ this.type = checkNotNull(type);
+ this.vtapCriterion = checkNotNull(vtapCriterion);
+ this.txDeviceIds = Objects.nonNull(txDeviceIds) ?
+ ImmutableSet.copyOf(txDeviceIds) : ImmutableSet.of();
+ this.rxDeviceIds = Objects.nonNull(rxDeviceIds) ?
+ ImmutableSet.copyOf(rxDeviceIds) : ImmutableSet.of();
}
@Override
@@ -66,129 +78,184 @@
}
@Override
- public OpenstackVtapCriterion vTapCriterion() {
- return vTapCriterion;
+ public OpenstackVtapCriterion vtapCriterion() {
+ return vtapCriterion;
}
@Override
public Set<DeviceId> txDeviceIds() {
- return ImmutableSet.copyOf(txDeviceIds);
+ return txDeviceIds;
}
@Override
public Set<DeviceId> rxDeviceIds() {
- return ImmutableSet.copyOf(rxDeviceIds);
+ return rxDeviceIds;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, type, vtapCriterion, txDeviceIds, rxDeviceIds);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultOpenstackVtap) {
+ final DefaultOpenstackVtap other = (DefaultOpenstackVtap) obj;
+ return Objects.equals(this.id, other.id) &&
+ Objects.equals(this.type, other.type) &&
+ Objects.equals(this.vtapCriterion, other.vtapCriterion) &&
+ Objects.equals(this.txDeviceIds(), other.txDeviceIds()) &&
+ Objects.equals(this.rxDeviceIds(), other.rxDeviceIds()) &&
+ Objects.equals(this.annotations(), other.annotations());
+ }
+ return false;
}
@Override
public String toString() {
return toStringHelper(this)
- .add("id", id)
- .add("type", type)
- .add("vTapCriterion", vTapCriterion)
- .add("txDeviceIds", txDeviceIds)
- .add("rxDeviceIds", rxDeviceIds)
+ .add("id", id())
+ .add("type", type())
+ .add("vtapCriterion", vtapCriterion())
+ .add("txDeviceIds", txDeviceIds())
+ .add("rxDeviceIds", rxDeviceIds())
+ .add("annotations", annotations())
.toString();
}
- @Override
- public int hashCode() {
- return Objects.hashCode(id, type, vTapCriterion, txDeviceIds, rxDeviceIds);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- DefaultOpenstackVtap that = (DefaultOpenstackVtap) o;
- return Objects.equal(this.id, that.id)
- && Objects.equal(this.type, that.type)
- && Objects.equal(this.vTapCriterion, that.vTapCriterion)
- && Objects.equal(this.txDeviceIds, that.txDeviceIds)
- && Objects.equal(this.rxDeviceIds, that.rxDeviceIds);
- }
-
/**
- * Creates a new default openstack vTap builder.
+ * Creates OpenstackVtap builder with default parameters.
*
- * @return default openstack vTap builder
+ * @return builder
*/
public static Builder builder() {
return new Builder();
}
/**
+ * Creates OpenstackVtap builder inheriting with default parameters,
+ * from specified OpenstackVtap.
+ *
+ * @param vtap to inherit default from
+ * @return builder
+ */
+ public static Builder builder(OpenstackVtap vtap) {
+ return new Builder(vtap);
+ }
+
+ /**
* Builder for DefaultOpenstackVtap object.
*/
public static class Builder implements OpenstackVtap.Builder {
- private static final SparseAnnotations EMPTY = DefaultAnnotations.builder().build();
-
private OpenstackVtapId id;
- private Type type;
- private OpenstackVtapCriterion vTapCriterion;
+ private Type type = Type.VTAP_ALL;
+ private OpenstackVtapCriterion vtapCriterion;
private Set<DeviceId> txDeviceIds;
private Set<DeviceId> rxDeviceIds;
- private SparseAnnotations annotations = EMPTY;
+ private SparseAnnotations annotations = DefaultAnnotations.EMPTY;
- // private constructor not intended to use from external
+ // Private constructor not intended to use from external
Builder() {
}
+ Builder(OpenstackVtap description) {
+ this.id = description.id();
+ this.type = description.type();
+ this.vtapCriterion = description.vtapCriterion();
+ this.type = description.type();
+ this.txDeviceIds = description.txDeviceIds();
+ this.rxDeviceIds = description.rxDeviceIds();
+ this.annotations = (SparseAnnotations) description.annotations();
+ }
+
+ /**
+ * Sets mandatory field id.
+ *
+ * @param id to set
+ * @return self
+ */
@Override
public Builder id(OpenstackVtapId id) {
this.id = id;
return this;
}
+ /**
+ * Sets mandatory field type.
+ *
+ * @param type of the vtap
+ * @return self
+ */
@Override
public Builder type(Type type) {
this.type = type;
return this;
}
+ /**
+ * Sets mandatory field criterion.
+ *
+ * @param vtapCriterion for the vtap
+ * @return self
+ */
@Override
- public Builder vTapCriterion(OpenstackVtapCriterion vTapCriterion) {
- this.vTapCriterion = vTapCriterion;
+ public Builder vtapCriterion(OpenstackVtapCriterion vtapCriterion) {
+ this.vtapCriterion = vtapCriterion;
return this;
}
+ /**
+ * Sets a tx deviceId set.
+ *
+ * @param txDeviceIds deviceId set for tx
+ * @return builder
+ */
@Override
public Builder txDeviceIds(Set<DeviceId> txDeviceIds) {
- if (txDeviceIds != null) {
- this.txDeviceIds = ImmutableSet.copyOf(txDeviceIds);
- } else {
- this.txDeviceIds = Sets.newHashSet();
- }
+ this.txDeviceIds = txDeviceIds;
return this;
}
+ /**
+ * Sets a rx deviceId set.
+ *
+ * @param rxDeviceIds deviceId set for rx
+ * @return builder
+ */
@Override
public Builder rxDeviceIds(Set<DeviceId> rxDeviceIds) {
- if (rxDeviceIds != null) {
- this.rxDeviceIds = ImmutableSet.copyOf(rxDeviceIds);
- } else {
- this.rxDeviceIds = Sets.newHashSet();
- }
+ this.rxDeviceIds = rxDeviceIds;
return this;
}
+ /**
+ * Sets annotations.
+ *
+ * @param annotations of the vtap
+ * @return self
+ */
@Override
- public Builder annotations(SparseAnnotations... annotations) {
- checkArgument(annotations.length <= 1,
- "Only one set of annotations is expected");
- this.annotations = annotations.length == 1 ? annotations[0] : EMPTY;
+ public Builder annotations(SparseAnnotations annotations) {
+ this.annotations = annotations;
return this;
}
+ /**
+ * Builds a DefaultOpenstackVtap instance.
+ *
+ * @return DefaultOpenstackVtap
+ */
@Override
public DefaultOpenstackVtap build() {
- return new DefaultOpenstackVtap(id, type, vTapCriterion,
- txDeviceIds, rxDeviceIds, annotations);
+ return new DefaultOpenstackVtap(checkNotNull(id),
+ checkNotNull(type),
+ checkNotNull(vtapCriterion),
+ txDeviceIds,
+ rxDeviceIds,
+ checkNotNull(annotations));
}
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java
index d53bf25..287f763 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapCriterion.java
@@ -24,16 +24,15 @@
import static com.google.common.base.Preconditions.checkArgument;
/**
- * Default implementation of an immutable openstack vTap criterion.
+ * Default implementation of an immutable openstack vtap criterion.
*/
public final class DefaultOpenstackVtapCriterion implements OpenstackVtapCriterion {
+
private final IpPrefix srcIpPrefix;
private final IpPrefix dstIpPrefix;
- private final byte ipProtocol;
+ private final byte ipProtocol;
private final TpPort srcTpPort;
- private final TpPort dstTpPort;
-
- private static final String NOT_NULL_MSG = "Element % cannot be null";
+ private final TpPort dstTpPort;
// private constructor not intended to use from external
private DefaultOpenstackVtapCriterion(IpPrefix srcIpPrefix,
@@ -107,18 +106,20 @@
}
/**
- * Creates a new default openstack vTap criterion builder.
+ * Creates a new default openstack vtap criterion builder.
*
- * @return default openstack vTap criterion builder
+ * @return default openstack vtap criterion builder
*/
public static Builder builder() {
return new Builder();
}
/**
- * A builder class for openstack vTap criterion builder.
+ * A builder class for openstack vtap criterion builder.
*/
public static final class Builder implements OpenstackVtapCriterion.Builder {
+ private static final String NOT_NULL_MSG = "OpenstackVtapCriterion % cannot be null";
+
private IpPrefix srcIpPrefix;
private IpPrefix dstIpPrefix;
private byte ipProtocol;
@@ -168,4 +169,5 @@
return this;
}
}
+
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapNetwork.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapNetwork.java
new file mode 100644
index 0000000..af086a2
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapNetwork.java
@@ -0,0 +1,203 @@
+/*
+ * 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.impl;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.AbstractDescription;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default implementation of an immutable OpenstackVtapNetwork.
+ */
+public class DefaultOpenstackVtapNetwork extends AbstractDescription implements OpenstackVtapNetwork {
+
+ private final Mode mode;
+ private final Integer networkId;
+ private final IpAddress serverIp;
+
+ /**
+ * Creates an DefaultOpenstackVtapNetwork using the supplied information.
+ *
+ * @param mode mode of vtap network
+ * @param networkId network id of the vtap tunneling network
+ * @param serverIp server IP address used for tunneling
+ * @param annotations optional key/value annotations
+ */
+ protected DefaultOpenstackVtapNetwork(Mode mode,
+ Integer networkId,
+ IpAddress serverIp,
+ SparseAnnotations... annotations) {
+ super(annotations);
+ this.mode = checkNotNull(mode);
+ this.networkId = networkId;
+ this.serverIp = checkNotNull(serverIp);
+ }
+
+ @Override
+ public Mode mode() {
+ return mode;
+ }
+
+ @Override
+ public Integer networkId() {
+ return networkId;
+ }
+
+ @Override
+ public IpAddress serverIp() {
+ return serverIp;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mode, networkId, serverIp);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DefaultOpenstackVtapNetwork) {
+ final DefaultOpenstackVtapNetwork other = (DefaultOpenstackVtapNetwork) obj;
+ return Objects.equals(this.mode, other.mode) &&
+ Objects.equals(this.networkId, other.networkId) &&
+ Objects.equals(this.serverIp, other.serverIp) &&
+ Objects.equals(this.annotations(), other.annotations());
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("mode", mode())
+ .add("networkId", networkId())
+ .add("serverIp", serverIp())
+ .add("annotations", annotations())
+ .toString();
+ }
+
+ /**
+ * Creates OpenstackVtapNetwork builder with default parameters.
+ *
+ * @return builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Creates OpenstackVtapNetwork builder inheriting with default parameters,
+ * from specified OpenstackVtapNetwork.
+ *
+ * @param vtapNetwork to inherit default from
+ * @return builder
+ */
+ public static Builder builder(OpenstackVtapNetwork vtapNetwork) {
+ return new Builder(vtapNetwork);
+ }
+
+ /**
+ * Builder for DefaultOpenstackVtapNetwork object.
+ */
+ public static class Builder implements OpenstackVtapNetwork.Builder {
+ private Mode mode;
+ private Integer networkId;
+ private IpAddress serverIp;
+ private SparseAnnotations annotations = DefaultAnnotations.EMPTY;
+
+ // private constructor not intended to use from external
+ private Builder() {
+ }
+
+ Builder(OpenstackVtapNetwork description) {
+ this.mode = description.mode();
+ this.networkId = description.networkId();
+ this.serverIp = description.serverIp();
+ this.annotations = (SparseAnnotations) description.annotations();
+ }
+
+ /**
+ * Sets mandatory field mode.
+ *
+ * @param mode of vtap network
+ * @return self
+ */
+ @Override
+ public Builder mode(Mode mode) {
+ this.mode = mode;
+ return this;
+ }
+
+ /**
+ * Sets mandatory field networkId.
+ *
+ * @param networkId of the vtap tunneling network
+ * @return self
+ */
+ @Override
+ public Builder networkId(Integer networkId) {
+ this.networkId = networkId;
+ return this;
+ }
+
+ /**
+ * Sets mandatory field serverIp.
+ *
+ * @param serverIp address used for tunneling
+ * @return self
+ */
+ @Override
+ public Builder serverIp(IpAddress serverIp) {
+ this.serverIp = serverIp;
+ return this;
+ }
+
+ /**
+ * Sets annotations.
+ *
+ * @param annotations of the vtap network
+ * @return self
+ */
+ @Override
+ public Builder annotations(SparseAnnotations annotations) {
+ this.annotations = annotations;
+ return this;
+ }
+
+ /**
+ * Builds a DefaultOpenstackVtapNetwork instance.
+ *
+ * @return DefaultOpenstackVtapNetwork
+ */
+ @Override
+ public DefaultOpenstackVtapNetwork build() {
+ return new DefaultOpenstackVtapNetwork(checkNotNull(mode),
+ networkId,
+ checkNotNull(serverIp),
+ checkNotNull(annotations));
+ }
+ }
+
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java
index 141af0b..9f2ee12 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/DistributedOpenstackVtapStore.java
@@ -29,9 +29,10 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.SparseAnnotations;
import org.onosproject.openstackvtap.api.OpenstackVtap;
-import org.onosproject.openstackvtap.api.OpenstackVtapCriterion;
+import org.onosproject.openstackvtap.api.OpenstackVtap.Type;
import org.onosproject.openstackvtap.api.OpenstackVtapEvent;
import org.onosproject.openstackvtap.api.OpenstackVtapId;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
import org.onosproject.openstackvtap.api.OpenstackVtapStore;
import org.onosproject.openstackvtap.api.OpenstackVtapStoreDelegate;
import org.onosproject.store.AbstractStore;
@@ -42,6 +43,7 @@
import org.onosproject.store.service.MapEventListener;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
import org.slf4j.Logger;
import java.util.Comparator;
@@ -53,465 +55,570 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.DefaultAnnotations.merge;
+import static org.onosproject.store.service.Versioned.valueOrNull;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Manages the inventory of users using a {@code ConsistentMap}.
+ * Manages the inventory of openstack vtap and openstack vtap network using a {@code ConsistentMap}.
*/
@Component(immediate = true)
@Service
public class DistributedOpenstackVtapStore
extends AbstractStore<OpenstackVtapEvent, OpenstackVtapStoreDelegate>
implements OpenstackVtapStore {
+
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
- private ConsistentMap<OpenstackVtapId, DefaultOpenstackVtap> vTapConsistentMap;
- private MapEventListener<OpenstackVtapId, DefaultOpenstackVtap>
- vTapListener = new VtapEventListener();
- private Map<OpenstackVtapId, DefaultOpenstackVtap> vTapMap;
+ private ConsistentMap<OpenstackVtapId, DefaultOpenstackVtap> vtapConsistentMap;
+ private MapEventListener<OpenstackVtapId, DefaultOpenstackVtap> vtapListener =
+ new VtapEventListener();
+ private Map<OpenstackVtapId, DefaultOpenstackVtap> vtapMap;
+
+ private ConsistentMap<Integer, DefaultOpenstackVtapNetwork> vtapNetworkConsistentMap;
+ private MapEventListener<Integer, DefaultOpenstackVtapNetwork> vtapNetworkListener =
+ new VtapNetworkEventListener();
+ private Map<Integer, DefaultOpenstackVtapNetwork> vtapNetworkMap;
+
+ private ConsistentMap<Integer, Set<DeviceId>> vtapNetworkDevicesConsistentMap;
private static final Serializer SERIALIZER = Serializer
.using(new KryoNamespace.Builder().register(KryoNamespaces.API)
.register(OpenstackVtapId.class)
.register(UUID.class)
.register(DefaultOpenstackVtap.class)
- .register(OpenstackVtap.Type.class)
+ .register(Type.class)
.register(DefaultOpenstackVtapCriterion.class)
+ .register(DefaultOpenstackVtapNetwork.class)
+ .register(OpenstackVtapNetwork.Mode.class)
.nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
.build());
private Map<DeviceId, Set<OpenstackVtapId>>
- vTapIdsByTxDeviceId = Maps.newConcurrentMap();
+ vtapIdsByTxDeviceId = Maps.newConcurrentMap();
private Map<DeviceId, Set<OpenstackVtapId>>
- vTapIdsByRxDeviceId = Maps.newConcurrentMap();
+ vtapIdsByRxDeviceId = Maps.newConcurrentMap();
private ScheduledExecutorService eventExecutor;
+ private Consumer<Status> vtapStatusListener;
- private Consumer<Status> vTapStatusListener;
-
- public static final String INVALID_DESCRIPTION = "Invalid create/update parameter";
+ private static final String ERR_NOT_FOUND = "ID {} does not exist";
+ private static final String ERR_DUPLICATE = "ID {} already exists";
@Activate
public void activate() {
eventExecutor = newSingleThreadScheduledExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
- vTapConsistentMap = storageService.<OpenstackVtapId, DefaultOpenstackVtap>
+ // vtap network data
+ vtapNetworkConsistentMap = storageService.<Integer, DefaultOpenstackVtapNetwork>
consistentMapBuilder()
- .withName("vTapMap")
+ .withName("vtapNetworkMap")
+ .withSerializer(SERIALIZER)
+ .build();
+ vtapNetworkMap = vtapNetworkConsistentMap.asJavaMap();
+ vtapNetworkConsistentMap.addListener(vtapNetworkListener);
+
+ // vtap network devices data
+ vtapNetworkDevicesConsistentMap = storageService.<Integer, Set<DeviceId>>
+ consistentMapBuilder()
+ .withName("vtapNetworkDevicesMap")
.withSerializer(SERIALIZER)
.build();
- vTapMap = vTapConsistentMap.asJavaMap();
- vTapConsistentMap.addListener(vTapListener);
+ // vtap data
+ vtapConsistentMap = storageService.<OpenstackVtapId, DefaultOpenstackVtap>
+ consistentMapBuilder()
+ .withName("vtapMap")
+ .withSerializer(SERIALIZER)
+ .build();
+ vtapMap = vtapConsistentMap.asJavaMap();
+ vtapConsistentMap.addListener(vtapListener);
- vTapStatusListener = status -> {
+ // initialize vtap data
+ vtapStatusListener = status -> {
if (status == Status.ACTIVE) {
eventExecutor.execute(this::loadVtapIds);
}
};
- vTapConsistentMap.addStatusChangeListener(vTapStatusListener);
+ vtapConsistentMap.addStatusChangeListener(vtapStatusListener);
- log.info("Started {} - {}", this.getClass().getSimpleName());
+ log.info("Started");
}
@Deactivate
public void deactivate() {
- vTapConsistentMap.removeStatusChangeListener(vTapStatusListener);
- vTapConsistentMap.removeListener(vTapListener);
+ vtapConsistentMap.removeStatusChangeListener(vtapStatusListener);
+ vtapConsistentMap.removeListener(vtapListener);
+ vtapNetworkConsistentMap.removeListener(vtapNetworkListener);
+
eventExecutor.shutdown();
- log.info("Stopped {} - {}", this.getClass().getSimpleName());
+ log.info("Stopped");
}
- @Override
- public OpenstackVtap createOrUpdateVtap(OpenstackVtapId vTapId,
- OpenstackVtap description,
- boolean replaceFlag) {
-
- return vTapMap.compute(vTapId, (id, existing) -> {
- if (existing == null &&
- (description.type() == null ||
- description.vTapCriterion() == null ||
- description.txDeviceIds() == null ||
- description.rxDeviceIds() == null)) {
- checkState(false, INVALID_DESCRIPTION);
- return null;
- }
-
- if (shouldUpdate(existing, description, replaceFlag)) {
- // Replace items
- OpenstackVtap.Type type =
- (description.type() == null ? existing.type() : description.type());
- OpenstackVtapCriterion vTapCriterion =
- (description.vTapCriterion() == null ?
- existing.vTapCriterion() : description.vTapCriterion());
-
- // Replace or add devices
- Set<DeviceId> txDeviceIds;
- if (description.txDeviceIds() == null) {
- txDeviceIds = existing.txDeviceIds();
- } else {
- if (existing == null || replaceFlag) {
- txDeviceIds = ImmutableSet.copyOf(description.txDeviceIds());
- } else {
- txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
- txDeviceIds.addAll(description.txDeviceIds());
- }
- }
-
- Set<DeviceId> rxDeviceIds;
- if (description.rxDeviceIds() == null) {
- rxDeviceIds = existing.rxDeviceIds();
- } else {
- if (existing == null || replaceFlag) {
- rxDeviceIds = ImmutableSet.copyOf(description.rxDeviceIds());
- } else {
- rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
- rxDeviceIds.addAll(description.rxDeviceIds());
- }
- }
-
- // Replace or add annotations
- SparseAnnotations annotations;
- if (existing != null) {
- annotations = merge((DefaultAnnotations) existing.annotations(),
- (SparseAnnotations) description.annotations());
- } else {
- annotations = (SparseAnnotations) description.annotations();
- }
-
- // Make new changed vTap and return
- return DefaultOpenstackVtap.builder()
- .id(vTapId)
- .type(type)
- .vTapCriterion(vTapCriterion)
- .txDeviceIds(txDeviceIds)
- .rxDeviceIds(rxDeviceIds)
- .annotations(annotations)
- .build();
- }
- return existing;
- });
- }
-
- @Override
- public OpenstackVtap removeVtapById(OpenstackVtapId vTapId) {
- return vTapMap.remove(vTapId);
- }
-
- @Override
- public boolean addDeviceToVtap(OpenstackVtapId vTapId,
- OpenstackVtap.Type type,
- DeviceId deviceId) {
- checkNotNull(vTapId);
- checkNotNull(deviceId);
-
- OpenstackVtap vTap = vTapMap.compute(vTapId, (id, existing) -> {
- if (existing == null) {
- return null;
- }
- if (!existing.type().isValid(type)) {
- log.error("Not valid OpenstackVtap type {} for requested type {}",
- existing.type(), type);
- return existing;
- }
-
- Set<DeviceId> txDeviceIds = null;
- if (type.isValid(OpenstackVtap.Type.VTAP_TX) &&
- !existing.txDeviceIds().contains(deviceId)) {
- txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
- txDeviceIds.add(deviceId);
- }
-
- Set<DeviceId> rxDeviceIds = null;
- if (type.isValid(OpenstackVtap.Type.VTAP_RX) &&
- !existing.rxDeviceIds().contains(deviceId)) {
- rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
- rxDeviceIds.add(deviceId);
- }
-
- if (txDeviceIds != null || rxDeviceIds != null) {
- //updateVTapIdFromDeviceId(existing.id(), deviceId); // execute from event listener
-
- return DefaultOpenstackVtap.builder()
- .id(vTapId)
- .type(existing.type())
- .vTapCriterion(existing.vTapCriterion())
- .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
- .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
- .annotations(existing.annotations())
- .build();
- }
- return existing;
- });
- return (vTap != null);
- }
-
- @Override
- public boolean removeDeviceFromVtap(OpenstackVtapId vTapId,
- OpenstackVtap.Type type,
- DeviceId deviceId) {
- checkNotNull(vTapId);
- checkNotNull(deviceId);
-
- OpenstackVtap vTap = vTapMap.compute(vTapId, (id, existing) -> {
- if (existing == null) {
- return null;
- }
- if (!existing.type().isValid(type)) {
- log.error("Not valid OpenstackVtap type {} for requested type {}",
- existing.type(), type);
- return existing;
- }
-
- Set<DeviceId> txDeviceIds = null;
- if (type.isValid(OpenstackVtap.Type.VTAP_TX) &&
- existing.txDeviceIds().contains(deviceId)) {
- txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
- txDeviceIds.remove(deviceId);
- }
-
- Set<DeviceId> rxDeviceIds = null;
- if (type.isValid(OpenstackVtap.Type.VTAP_RX) &&
- existing.rxDeviceIds().contains(deviceId)) {
- rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
- rxDeviceIds.remove(deviceId);
- }
-
- if (txDeviceIds != null || rxDeviceIds != null) {
- //removeVTapIdFromDeviceId(existing.id(), deviceId); // execute from event listener
-
- return DefaultOpenstackVtap.builder()
- .id(vTapId)
- .type(existing.type())
- .vTapCriterion(existing.vTapCriterion())
- .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
- .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
- .annotations(existing.annotations())
- .build();
- }
- return existing;
- });
- return (vTap != null);
- }
-
- @Override
- public boolean updateDeviceForVtap(OpenstackVtapId vTapId,
- Set<DeviceId> txDeviceIds, Set<DeviceId> rxDeviceIds,
- boolean replaceDevices) {
- checkNotNull(vTapId);
- checkNotNull(txDeviceIds);
- checkNotNull(rxDeviceIds);
-
- OpenstackVtap vTap = vTapMap.compute(vTapId, (id, existing) -> {
- if (existing == null) {
- return null;
- }
-
- // Replace or add devices
- Set<DeviceId> txDS = null;
- if (replaceDevices) {
- if (!existing.txDeviceIds().equals(txDeviceIds)) {
- txDS = ImmutableSet.copyOf(txDeviceIds);
- }
- } else {
- if (!existing.txDeviceIds().containsAll(txDeviceIds)) {
- txDS = Sets.newHashSet(existing.txDeviceIds());
- txDS.addAll(txDeviceIds);
- }
- }
-
- Set<DeviceId> rxDS = null;
- if (replaceDevices) {
- if (!existing.rxDeviceIds().equals(rxDeviceIds)) {
- rxDS = ImmutableSet.copyOf(rxDeviceIds);
- }
- } else {
- if (!existing.rxDeviceIds().containsAll(rxDeviceIds)) {
- rxDS = Sets.newHashSet(existing.rxDeviceIds());
- rxDS.addAll(rxDeviceIds);
- }
- }
-
- if (txDS != null || rxDS != null) {
-
- return DefaultOpenstackVtap.builder()
- .id(vTapId)
- .type(existing.type())
- .vTapCriterion(existing.vTapCriterion())
- .txDeviceIds(txDS != null ? txDS : existing.txDeviceIds())
- .rxDeviceIds(rxDS != null ? rxDS : existing.rxDeviceIds())
- .annotations(existing.annotations())
- .build();
- }
- return existing;
- });
- return (vTap != null);
- }
-
- @Override
- public int getVtapCount(OpenstackVtap.Type type) {
- return (int) vTapMap.values().parallelStream()
- .filter(vTap -> vTap.type().isValid(type))
- .count();
- }
-
- @Override
- public Set<OpenstackVtap> getVtaps(OpenstackVtap.Type type) {
- return ImmutableSet.copyOf(
- vTapMap.values().parallelStream()
- .filter(vTap -> vTap.type().isValid(type))
- .collect(Collectors.toSet()));
- }
-
- @Override
- public OpenstackVtap getVtap(OpenstackVtapId vTapId) {
- return vTapMap.get(vTapId);
- }
-
- @Override
- public Set<OpenstackVtap> getVtapsByDeviceId(OpenstackVtap.Type type,
- DeviceId deviceId) {
- Set<OpenstackVtapId> vtapIds = Sets.newHashSet();
- if (type.isValid(OpenstackVtap.Type.VTAP_TX)) {
- if (vTapIdsByTxDeviceId.get(deviceId) != null) {
- vtapIds.addAll(vTapIdsByTxDeviceId.get(deviceId));
- }
- }
- if (type.isValid(OpenstackVtap.Type.VTAP_RX)) {
- if (vTapIdsByRxDeviceId.get(deviceId) != null) {
- vtapIds.addAll(vTapIdsByRxDeviceId.get(deviceId));
- }
- }
-
- return ImmutableSet.copyOf(
- vtapIds.parallelStream()
- .map(vTapId -> vTapMap.get(vTapId))
- .filter(Objects::nonNull)
- .collect(Collectors.toSet()));
- }
-
- private void loadVtapIds() {
- vTapIdsByTxDeviceId.clear();
- vTapIdsByRxDeviceId.clear();
- vTapMap.values().forEach(vTap -> refreshDeviceIdsByVtap(null, vTap));
- }
-
- private boolean shouldUpdate(DefaultOpenstackVtap existing,
- OpenstackVtap description,
- boolean replaceDevices) {
+ private boolean shouldUpdateVtapNetwork(DefaultOpenstackVtapNetwork existing,
+ OpenstackVtapNetwork description) {
if (existing == null) {
return true;
}
- if ((description.type() != null && !description.type().equals(existing.type()))
- || (description.vTapCriterion() != null &&
- !description.vTapCriterion().equals(existing.vTapCriterion()))) {
+ if (!Objects.equals(existing.mode(), description.mode()) ||
+ !Objects.equals(existing.networkId(), description.networkId()) ||
+ !Objects.equals(existing.serverIp(), description.serverIp())) {
return true;
}
- if (description.txDeviceIds() != null) {
- if (replaceDevices) {
- if (!existing.txDeviceIds().equals(description.txDeviceIds())) {
- return true;
- }
- } else {
- if (!existing.txDeviceIds().containsAll(description.txDeviceIds())) {
- return true;
- }
- }
- }
-
- if (description.rxDeviceIds() != null) {
- if (replaceDevices) {
- if (!existing.rxDeviceIds().equals(description.rxDeviceIds())) {
- return true;
- }
- } else {
- if (!existing.rxDeviceIds().containsAll(description.rxDeviceIds())) {
- return true;
- }
- }
- }
-
- // check to see if any of the annotations provided by vTap
- // differ from those in the existing vTap
+ // check to see if any of the annotations provided by description
+ // differ from those in the existing vtap network
return description.annotations().keys().stream()
.anyMatch(k -> !Objects.equals(description.annotations().value(k),
existing.annotations().value(k)));
}
+ private OpenstackVtapNetwork createOrUpdateVtapNetwork(boolean update,
+ Integer key,
+ OpenstackVtapNetwork description) {
+ DefaultOpenstackVtapNetwork result =
+ vtapNetworkMap.compute(key, (id, existing) -> {
+ // Check create or update validity
+ if (update && existing == null) {
+ return null;
+ } else if (!update && existing != null) {
+ return existing;
+ }
+
+ if (shouldUpdateVtapNetwork(existing, description)) {
+ // Replace or add annotations
+ final SparseAnnotations annotations;
+ if (existing != null) {
+ annotations = merge((DefaultAnnotations) existing.annotations(),
+ (SparseAnnotations) description.annotations());
+ } else {
+ annotations = (SparseAnnotations) description.annotations();
+ }
+
+ return DefaultOpenstackVtapNetwork.builder(description)
+ .annotations(annotations)
+ .build();
+ }
+ return existing;
+ });
+ return result;
+ }
+
+ @Override
+ public OpenstackVtapNetwork createVtapNetwork(Integer key, OpenstackVtapNetwork description) {
+ if (getVtapNetwork(key) == null) {
+ OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(false, key, description);
+ if (Objects.equals(vtapNetwork, description)) {
+ return vtapNetwork;
+ }
+ }
+ log.error(ERR_DUPLICATE, key);
+ return null;
+ }
+
+ @Override
+ public OpenstackVtapNetwork updateVtapNetwork(Integer key, OpenstackVtapNetwork description) {
+ OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(true, key, description);
+ if (vtapNetwork == null) {
+ log.error(ERR_NOT_FOUND, key);
+ }
+ return vtapNetwork;
+ }
+
+ @Override
+ public OpenstackVtapNetwork removeVtapNetwork(Integer key) {
+ return vtapNetworkMap.remove(key);
+ }
+
+ @Override
+ public void clearVtapNetworks() {
+ vtapNetworkMap.clear();
+ }
+
+ @Override
+ public int getVtapNetworkCount() {
+ return vtapNetworkMap.size();
+ }
+
+ @Override
+ public OpenstackVtapNetwork getVtapNetwork(Integer key) {
+ return vtapNetworkMap.get(key);
+ }
+
+ @Override
+ public boolean addDeviceToVtapNetwork(Integer key, DeviceId deviceId) {
+ Versioned<Set<DeviceId>> result =
+ vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
+ // Add deviceId to deviceIds
+ if (existing == null) {
+ return Sets.newHashSet(deviceId);
+ } else if (!existing.contains(deviceId)) {
+ Set<DeviceId> deviceIds = Sets.newHashSet(existing);
+ deviceIds.add(deviceId);
+ return deviceIds;
+ } else {
+ return existing;
+ }
+ });
+ return Objects.nonNull(valueOrNull(result));
+ }
+
+ @Override
+ public boolean removeDeviceFromVtapNetwork(Integer key, DeviceId deviceId) {
+ Versioned<Set<DeviceId>> result =
+ vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
+ // Remove deviceId from deviceIds
+ if (existing != null && existing.contains(deviceId)) {
+ Set<DeviceId> deviceIds = Sets.newHashSet(existing);
+ deviceIds.remove(deviceId);
+ return deviceIds;
+ } else {
+ return existing;
+ }
+ });
+ return Objects.nonNull(valueOrNull(result));
+ }
+
+ @Override
+ public Set<DeviceId> getVtapNetworkDevices(Integer key) {
+ return valueOrNull(vtapNetworkDevicesConsistentMap.get(key));
+ }
+
+ private boolean shouldUpdateVtap(DefaultOpenstackVtap existing,
+ OpenstackVtap description,
+ boolean replaceDevices) {
+ if (existing == null) {
+ return true;
+ }
+
+ if (!Objects.equals(existing.type(), description.type()) ||
+ !Objects.equals(existing.vtapCriterion(), description.vtapCriterion())) {
+ return true;
+ }
+
+ if (replaceDevices) {
+ if (!Objects.equals(description.txDeviceIds(), existing.txDeviceIds()) ||
+ !Objects.equals(description.rxDeviceIds(), existing.rxDeviceIds())) {
+ return true;
+ }
+ } else {
+ if (!existing.txDeviceIds().containsAll(description.txDeviceIds()) ||
+ !existing.rxDeviceIds().containsAll(description.rxDeviceIds())) {
+ return true;
+ }
+ }
+
+ // check to see if any of the annotations provided by description
+ // differ from those in the existing vtap
+ return description.annotations().keys().stream()
+ .anyMatch(k -> !Objects.equals(description.annotations().value(k),
+ existing.annotations().value(k)));
+ }
+
+ private OpenstackVtap createOrUpdateVtap(boolean update,
+ OpenstackVtap description,
+ boolean replaceDevices) {
+ DefaultOpenstackVtap result =
+ vtapMap.compute(description.id(), (id, existing) -> {
+ // Check create or update validity
+ if (update && existing == null) {
+ return null;
+ } else if (!update && existing != null) {
+ return existing;
+ }
+
+ if (shouldUpdateVtap(existing, description, replaceDevices)) {
+ // Replace or add devices
+ final Set<DeviceId> txDeviceIds;
+ if (existing == null || replaceDevices) {
+ txDeviceIds = description.txDeviceIds();
+ } else {
+ txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
+ txDeviceIds.addAll(description.txDeviceIds());
+ }
+
+ final Set<DeviceId> rxDeviceIds;
+ if (existing == null || replaceDevices) {
+ rxDeviceIds = description.rxDeviceIds();
+ } else {
+ rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
+ rxDeviceIds.addAll(description.rxDeviceIds());
+ }
+
+ // Replace or add annotations
+ final SparseAnnotations annotations;
+ if (existing != null) {
+ annotations = merge((DefaultAnnotations) existing.annotations(),
+ (SparseAnnotations) description.annotations());
+ } else {
+ annotations = (SparseAnnotations) description.annotations();
+ }
+
+ return DefaultOpenstackVtap.builder(description)
+ .txDeviceIds(txDeviceIds)
+ .rxDeviceIds(rxDeviceIds)
+ .annotations(annotations)
+ .build();
+ }
+ return existing;
+ });
+ return result;
+ }
+
+ @Override
+ public OpenstackVtap createVtap(OpenstackVtap description) {
+ if (getVtap(description.id()) == null) {
+ OpenstackVtap vtap = createOrUpdateVtap(false, description, true);
+ if (Objects.equals(vtap, description)) {
+ return vtap;
+ }
+ }
+ log.error(ERR_DUPLICATE, description.id());
+ return null;
+ }
+
+ @Override
+ public OpenstackVtap updateVtap(OpenstackVtap description, boolean replaceDevices) {
+ OpenstackVtap vtap = createOrUpdateVtap(true, description, replaceDevices);
+ if (vtap == null) {
+ log.error(ERR_NOT_FOUND, description.id());
+ }
+ return vtap;
+ }
+
+ @Override
+ public OpenstackVtap removeVtap(OpenstackVtapId vtapId) {
+ return vtapMap.remove(vtapId);
+ }
+
+ @Override
+ public void clearVtaps() {
+ vtapMap.clear();
+ }
+
+ @Override
+ public int getVtapCount(Type type) {
+ return (int) vtapMap.values().parallelStream()
+ .filter(vtap -> vtap.type().isValid(type))
+ .count();
+ }
+
+ @Override
+ public Set<OpenstackVtap> getVtaps(Type type) {
+ return ImmutableSet.copyOf(
+ vtapMap.values().parallelStream()
+ .filter(vtap -> vtap.type().isValid(type))
+ .collect(Collectors.toSet()));
+ }
+
+ @Override
+ public OpenstackVtap getVtap(OpenstackVtapId vtapId) {
+ return vtapMap.get(vtapId);
+ }
+
+ @Override
+ public boolean addDeviceToVtap(OpenstackVtapId vtapId, Type type, DeviceId deviceId) {
+ OpenstackVtap result =
+ vtapMap.compute(vtapId, (id, existing) -> {
+ if (existing == null) {
+ return null;
+ }
+
+ // Check type validate
+ if (!existing.type().isValid(type)) {
+ log.error("Not valid OpenstackVtap type {} for requested type {}", existing.type(), type);
+ return existing;
+ }
+
+ // Add deviceId to txDeviceIds
+ final Set<DeviceId> txDeviceIds;
+ if (existing.type().isValid(Type.VTAP_TX) &&
+ (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
+ !existing.txDeviceIds().contains(deviceId)) {
+ txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
+ txDeviceIds.add(deviceId);
+ } else {
+ txDeviceIds = null;
+ }
+
+ // Add deviceId to rxDeviceIds
+ final Set<DeviceId> rxDeviceIds;
+ if (existing.type().isValid(Type.VTAP_RX) &&
+ (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
+ !existing.rxDeviceIds().contains(deviceId)) {
+ rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
+ rxDeviceIds.add(deviceId);
+ } else {
+ rxDeviceIds = null;
+ }
+
+ if (txDeviceIds != null || rxDeviceIds != null) {
+ return DefaultOpenstackVtap.builder()
+ .id(id)
+ .type(existing.type())
+ .vtapCriterion(existing.vtapCriterion())
+ .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
+ .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
+ .annotations(existing.annotations())
+ .build();
+ } else {
+ return existing;
+ }
+ });
+ return Objects.nonNull(result);
+ }
+
+ @Override
+ public boolean removeDeviceFromVtap(OpenstackVtapId vtapId, OpenstackVtap.Type type, DeviceId deviceId) {
+ OpenstackVtap result =
+ vtapMap.compute(vtapId, (id, existing) -> {
+ if (existing == null) {
+ return null;
+ }
+
+ // Check type validate
+ if (!existing.type().isValid(type)) {
+ log.error("Not valid OpenstackVtap type {} for requested type {}",
+ existing.type(), type);
+ return existing;
+ }
+
+ // Remove deviceId from txDeviceIds
+ final Set<DeviceId> txDeviceIds;
+ if (existing.type().isValid(Type.VTAP_TX) &&
+ (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
+ existing.txDeviceIds().contains(deviceId)) {
+ txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
+ txDeviceIds.remove(deviceId);
+ } else {
+ txDeviceIds = null;
+ }
+
+ // Remove deviceId from rxDeviceIds
+ final Set<DeviceId> rxDeviceIds;
+ if (existing.type().isValid(Type.VTAP_RX) &&
+ (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
+ existing.rxDeviceIds().contains(deviceId)) {
+ rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
+ rxDeviceIds.remove(deviceId);
+ } else {
+ rxDeviceIds = null;
+ }
+
+ if (txDeviceIds != null || rxDeviceIds != null) {
+ return DefaultOpenstackVtap.builder()
+ .id(id)
+ .type(existing.type())
+ .vtapCriterion(existing.vtapCriterion())
+ .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
+ .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
+ .annotations(existing.annotations())
+ .build();
+ } else {
+ return existing;
+ }
+ });
+ return Objects.nonNull(result);
+ }
+
+ @Override
+ public Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId) {
+ Set<OpenstackVtapId> vtapIds = Sets.newHashSet();
+ Set<OpenstackVtapId> txIds = vtapIdsByTxDeviceId.get(deviceId);
+ if (txIds != null) {
+ vtapIds.addAll(txIds);
+ }
+ Set<OpenstackVtapId> rxIds = vtapIdsByRxDeviceId.get(deviceId);
+ if (rxIds != null) {
+ vtapIds.addAll(rxIds);
+ }
+ return ImmutableSet.copyOf(
+ vtapIds.parallelStream()
+ .map(vtapId -> vtapMap.get(vtapId))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet()));
+ }
+
private class VtapComparator implements Comparator<OpenstackVtap> {
@Override
public int compare(OpenstackVtap v1, OpenstackVtap v2) {
int diff = (v2.type().compareTo(v1.type()));
if (diff == 0) {
- return (v2.vTapCriterion().ipProtocol() - v1.vTapCriterion().ipProtocol());
+ return (v2.vtapCriterion().ipProtocol() - v1.vtapCriterion().ipProtocol());
}
return diff;
}
}
- private static Set<OpenstackVtapId> addVTapIds(OpenstackVtapId vTapId) {
+ private void loadVtapIds() {
+ vtapIdsByTxDeviceId.clear();
+ vtapIdsByRxDeviceId.clear();
+ vtapMap.values().forEach(vtap -> refreshDeviceIdsByVtap(null, vtap));
+ }
+
+ private static Set<OpenstackVtapId> addVTapIds(OpenstackVtapId vtapId) {
Set<OpenstackVtapId> vtapIds = Sets.newConcurrentHashSet();
- vtapIds.add(vTapId);
+ vtapIds.add(vtapId);
return vtapIds;
}
private static Set<OpenstackVtapId> updateVTapIds(Set<OpenstackVtapId> existingVtapIds,
- OpenstackVtapId vTapId) {
- existingVtapIds.add(vTapId);
+ OpenstackVtapId vtapId) {
+ existingVtapIds.add(vtapId);
return existingVtapIds;
}
private static Set<OpenstackVtapId> removeVTapIds(Set<OpenstackVtapId> existingVtapIds,
- OpenstackVtapId vTapId) {
- existingVtapIds.remove(vTapId);
+ OpenstackVtapId vtapId) {
+ existingVtapIds.remove(vtapId);
if (existingVtapIds.isEmpty()) {
return null;
}
return existingVtapIds;
}
- private void updateVTapIdFromTxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
- vTapIdsByTxDeviceId.compute(deviceId, (k, v) -> v == null ?
- addVTapIds(vTapId) : updateVTapIds(v, vTapId));
+ private void updateVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+ vtapIdsByTxDeviceId.compute(deviceId, (k, v) -> v == null ?
+ addVTapIds(vtapId) : updateVTapIds(v, vtapId));
}
- private void removeVTapIdFromTxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
- vTapIdsByTxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vTapId));
+ private void removeVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+ vtapIdsByTxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
}
- private void updateVTapIdFromRxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
- vTapIdsByRxDeviceId.compute(deviceId, (k, v) -> v == null ?
- addVTapIds(vTapId) : updateVTapIds(v, vTapId));
+ private void updateVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+ vtapIdsByRxDeviceId.compute(deviceId, (k, v) -> v == null ?
+ addVTapIds(vtapId) : updateVTapIds(v, vtapId));
}
- private void removeVTapIdFromRxDeviceId(OpenstackVtapId vTapId, DeviceId deviceId) {
- vTapIdsByRxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vTapId));
+ private void removeVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
+ vtapIdsByRxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
}
- private void refreshDeviceIdsByVtap(OpenstackVtap oldOpenstackVtap,
- OpenstackVtap newOpenstackVtap) {
+ private void refreshDeviceIdsByVtap(OpenstackVtap newOpenstackVtap,
+ OpenstackVtap oldOpenstackVtap) {
+ if (Objects.equals(newOpenstackVtap, oldOpenstackVtap)) {
+ return;
+ }
+
if (oldOpenstackVtap != null) {
Set<DeviceId> removeDeviceIds;
- // Remove TX vTap
+ // Remove TX vtap
removeDeviceIds = (newOpenstackVtap != null) ?
Sets.difference(oldOpenstackVtap.txDeviceIds(),
newOpenstackVtap.txDeviceIds()) : oldOpenstackVtap.txDeviceIds();
removeDeviceIds.forEach(id -> removeVTapIdFromTxDeviceId(oldOpenstackVtap.id(), id));
- // Remove RX vTap
+ // Remove RX vtap
removeDeviceIds = (newOpenstackVtap != null) ?
Sets.difference(oldOpenstackVtap.rxDeviceIds(),
newOpenstackVtap.rxDeviceIds()) : oldOpenstackVtap.rxDeviceIds();
@@ -521,13 +628,13 @@
if (newOpenstackVtap != null) {
Set<DeviceId> addDeviceIds;
- // Add TX vTap
+ // Add TX vtap
addDeviceIds = (oldOpenstackVtap != null) ?
Sets.difference(newOpenstackVtap.txDeviceIds(),
oldOpenstackVtap.txDeviceIds()) : newOpenstackVtap.txDeviceIds();
addDeviceIds.forEach(id -> updateVTapIdFromTxDeviceId(newOpenstackVtap.id(), id));
- // Add RX vTap
+ // Add RX vtap
addDeviceIds = (oldOpenstackVtap != null) ?
Sets.difference(newOpenstackVtap.rxDeviceIds(),
oldOpenstackVtap.rxDeviceIds()) : newOpenstackVtap.rxDeviceIds();
@@ -544,26 +651,24 @@
DefaultOpenstackVtap oldValue =
event.oldValue() != null ? event.oldValue().value() : null;
- log.debug("VtapEventListener {} -> {}, {}", event.type(), oldValue, newValue);
+ log.trace("VtapEventListener {}: {} -> {}", event.type(), oldValue, newValue);
switch (event.type()) {
case INSERT:
- refreshDeviceIdsByVtap(oldValue, newValue);
+ refreshDeviceIdsByVtap(newValue, oldValue);
notifyDelegate(new OpenstackVtapEvent(
- OpenstackVtapEvent.Type.VTAP_ADDED, newValue));
+ OpenstackVtapEvent.Type.VTAP_ADDED, newValue, null));
break;
case UPDATE:
- if (!Objects.equals(newValue, oldValue)) {
- refreshDeviceIdsByVtap(oldValue, newValue);
- notifyDelegate(new OpenstackVtapEvent(
- OpenstackVtapEvent.Type.VTAP_UPDATED, newValue, oldValue));
- }
+ refreshDeviceIdsByVtap(newValue, oldValue);
+ notifyDelegate(new OpenstackVtapEvent(
+ OpenstackVtapEvent.Type.VTAP_UPDATED, newValue, oldValue));
break;
case REMOVE:
- refreshDeviceIdsByVtap(oldValue, newValue);
+ refreshDeviceIdsByVtap(newValue, oldValue);
notifyDelegate(new OpenstackVtapEvent(
- OpenstackVtapEvent.Type.VTAP_REMOVED, oldValue));
+ OpenstackVtapEvent.Type.VTAP_REMOVED, null, oldValue));
break;
default:
@@ -571,4 +676,37 @@
}
}
}
+
+ private class VtapNetworkEventListener
+ implements MapEventListener<Integer, DefaultOpenstackVtapNetwork> {
+ @Override
+ public void event(MapEvent<Integer, DefaultOpenstackVtapNetwork> event) {
+ DefaultOpenstackVtapNetwork newValue =
+ event.newValue() != null ? event.newValue().value() : null;
+ DefaultOpenstackVtapNetwork oldValue =
+ event.oldValue() != null ? event.oldValue().value() : null;
+
+ log.trace("VtapNetworkEventListener {}: {} -> {}", event.type(), oldValue, newValue);
+ switch (event.type()) {
+ case INSERT:
+ notifyDelegate(new OpenstackVtapEvent(
+ OpenstackVtapEvent.Type.VTAP_NETWORK_ADDED, newValue, null));
+ break;
+
+ case UPDATE:
+ notifyDelegate(new OpenstackVtapEvent(
+ OpenstackVtapEvent.Type.VTAP_NETWORK_UPDATED, newValue, oldValue));
+ break;
+
+ case REMOVE:
+ notifyDelegate(new OpenstackVtapEvent(
+ OpenstackVtapEvent.Type.VTAP_NETWORK_REMOVED, null, oldValue));
+ break;
+
+ default:
+ log.warn("Unknown map event type: {}", event.type());
+ }
+ }
+ }
+
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java
index 02a6579..6370de6 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/OpenstackVtapManager.java
@@ -22,12 +22,15 @@
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
-import org.onlab.packet.VlanId;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId;
@@ -35,21 +38,21 @@
import org.onosproject.core.CoreService;
import org.onosproject.core.GroupId;
import org.onosproject.event.AbstractListenerManager;
-import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostLocation;
+import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.DefaultTunnelDescription;
import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
+import org.onosproject.net.behaviour.InterfaceConfig;
+import org.onosproject.net.behaviour.TunnelDescription;
+import org.onosproject.net.behaviour.TunnelEndPoints;
+import org.onosproject.net.behaviour.TunnelKey;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DefaultDriverData;
-import org.onosproject.net.driver.DefaultDriverHandler;
-import org.onosproject.net.driver.Driver;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -59,6 +62,7 @@
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.ExtensionPropertyException;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
@@ -69,6 +73,7 @@
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
+import org.onosproject.openstacknode.api.OpenstackNode;
import org.onosproject.openstacknode.api.OpenstackNodeEvent;
import org.onosproject.openstacknode.api.OpenstackNodeListener;
import org.onosproject.openstacknode.api.OpenstackNodeService;
@@ -79,17 +84,19 @@
import org.onosproject.openstackvtap.api.OpenstackVtapEvent;
import org.onosproject.openstackvtap.api.OpenstackVtapId;
import org.onosproject.openstackvtap.api.OpenstackVtapListener;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork.Mode;
import org.onosproject.openstackvtap.api.OpenstackVtapService;
import org.onosproject.openstackvtap.api.OpenstackVtapStore;
import org.onosproject.openstackvtap.api.OpenstackVtapStoreDelegate;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
+import java.util.Dictionary;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@@ -99,9 +106,10 @@
import static org.onlab.packet.IPv4.PROTOCOL_ICMP;
import static org.onlab.packet.IPv4.PROTOCOL_TCP;
import static org.onlab.packet.IPv4.PROTOCOL_UDP;
-import static org.onlab.packet.VlanId.UNTAGGED;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT_TABLE;
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
@@ -114,12 +122,20 @@
import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_GROUP_TABLE;
import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_MIRROR_TABLE;
import static org.onosproject.openstacknetworking.api.Constants.VTAP_OUTBOUND_TABLE;
+import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
+import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.containsIp;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.dumpStackTrace;
import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getGroupKey;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getTunnelName;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.getTunnelType;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.hostCompareIp;
+import static org.onosproject.openstackvtap.util.OpenstackVtapUtil.isValidHost;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Provides basic implementation of the user APIs.
+ * Provides implementation of the openstack vtap and openstack vtap network APIs.
*/
@Component(immediate = true)
@Service
@@ -139,12 +155,6 @@
protected LeadershipService leadershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected MastershipService mastershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DriverService driverService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -154,36 +164,59 @@
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeService osNodeService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackVtapStore store;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected OpenstackNodeService osNodeService;
+ protected ComponentConfigService componentConfigService;
+
+ private static final boolean DEFAULT_TUNNEL_NICRA = false;
+ @Property(name = TUNNEL_NICIRA, boolValue = DEFAULT_TUNNEL_NICRA,
+ label = "Use nicra extension for tunneling")
+ private boolean tunnelNicira = DEFAULT_TUNNEL_NICRA;
public static final String APP_ID = "org.onosproject.openstackvtap";
-
- public static final String VTAP_ID_NULL = "OpenstackVtap ID cannot be null";
- public static final String VTAP_DESC_NULL = "OpenstackVtap fields cannot be null";
- public static final String DEVICE_ID_NULL = "Device ID cannot be null";
+ public static final String VTAP_DESC_NULL = "vtap field %s cannot be null";
private static final int PRIORITY_VTAP_RULE = 50000;
- private static final int PRIORITY_VTAP_OUTPORT_RULE = 1000;
- private static final int PRIORITY_VTAP_DROP = 0;
+ private static final int PRIORITY_VTAP_OUTPUT_RULE = 1000;
+ private static final int PRIORITY_VTAP_OUTPUT_DROP = 0;
- private static final int NONE_TABLE = -1;
private static final int INBOUND_NEXT_TABLE = DHCP_ARP_TABLE;
private static final int FLAT_OUTBOUND_NEXT_TABLE = FLAT_TABLE;
private static final int OUTBOUND_NEXT_TABLE = FORWARDING_TABLE;
+ private static final int[][] VTAP_TABLES = {
+ {VTAP_INBOUND_TABLE, VTAP_INBOUND_GROUP_TABLE,
+ INBOUND_NEXT_TABLE, VTAP_INBOUND_MIRROR_TABLE},
+ {VTAP_FLAT_OUTBOUND_TABLE, VTAP_FLAT_OUTBOUND_GROUP_TABLE,
+ FLAT_OUTBOUND_NEXT_TABLE, VTAP_FLAT_OUTBOUND_MIRROR_TABLE},
+ {VTAP_OUTBOUND_TABLE, VTAP_OUTBOUND_GROUP_TABLE,
+ OUTBOUND_NEXT_TABLE, VTAP_OUTBOUND_MIRROR_TABLE}};
+ private static final int VTAP_TABLE_INBOUND_IDX = 0;
+ private static final int VTAP_TABLE_FLAT_OUTBOUND_IDX = 1;
+ private static final int VTAP_TABLE_OUTBOUND_IDX = 2;
+ private static final int VTAP_TABLE_INPUT_IDX = 0;
+ private static final int VTAP_TABLE_GROUP_IDX = 1;
+ private static final int VTAP_TABLE_NEXT_IDX = 2;
+ private static final int VTAP_TABLE_OUTPUT_IDX = 3;
+
private static final IpPrefix ARBITRARY_IP_PREFIX =
IpPrefix.valueOf(IpAddress.valueOf("0.0.0.0"), 0);
- private static final String TABLE_PROPERTY_KEY = "table";
+ private static final String TABLE_EXTENSION = "table";
+ private static final String TUNNEL_DST_EXTENSION = "tunnelDst";
+ private static final String TUNNEL_NICIRA = "tunnelNicira";
+
+ private static final int VTAP_NETWORK_KEY = 0;
private final DeviceListener deviceListener = new InternalDeviceListener();
- private final HostListener hostListener = new InternalHostListener();
private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
+ private final HostListener hostListener = new InternalHostListener();
private OpenstackVtapStoreDelegate delegate = new InternalStoreDelegate();
@@ -191,12 +224,16 @@
private NodeId localNodeId;
private ScheduledExecutorService eventExecutor;
+ private final Object syncInterface = new Object(); // notification of tunnel interface
+ private static final int INTERFACE_MANIPULATION_TIMEOUT = 1000; // 1000msec
+ private static final int INTERFACE_MANIPULATION_RETRY = 10; // 10 times (totally 10sec)
@Activate
public void activate(ComponentContext context) {
appId = coreService.registerApplication(APP_ID);
localNodeId = clusterService.getLocalNode().id();
leadershipService.runForLeadership(appId.name());
+ componentConfigService.registerProperties(getClass());
eventExecutor = newSingleThreadScheduledExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
@@ -205,29 +242,200 @@
eventDispatcher.addSink(OpenstackVtapEvent.class, listenerRegistry);
deviceService.addListener(deviceListener);
- hostService.addListener(hostListener);
osNodeService.addListener(osNodeListener);
+ hostService.addListener(hostListener);
- initFlowAndGroupForCompNodes();
+ initVtap();
- log.info("Started {} - {}", appId.name(), this.getClass().getSimpleName());
+ log.info("Started");
}
@Deactivate
public void deactivate() {
- clearFlowAndGroupForCompNodes();
+ clearVtap();
- osNodeService.removeListener(osNodeListener);
hostService.removeListener(hostListener);
+ osNodeService.removeListener(osNodeListener);
deviceService.removeListener(deviceListener);
eventDispatcher.removeSink(OpenstackVtapEvent.class);
store.unsetDelegate(delegate);
eventExecutor.shutdown();
+
+ componentConfigService.unregisterProperties(getClass(), false);
leadershipService.withdraw(appId.name());
- log.info("Stopped {} - {}", appId.name(), this.getClass().getSimpleName());
+ log.info("Stopped");
+ }
+
+ @Modified
+ protected void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+
+ boolean updatedTunnelNicira = Tools.isPropertyEnabled(properties, TUNNEL_NICIRA);
+ if (tunnelNicira != updatedTunnelNicira) {
+ if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+ // Update the tunnel flow rule by reflecting the change.
+ osNodeService.completeNodes(COMPUTE)
+ .forEach(osNode -> applyVtapNetwork(getVtapNetwork(), osNode, false));
+ tunnelNicira = updatedTunnelNicira;
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(osNode -> osNode.state() == COMPLETE)
+ .forEach(osNode -> applyVtapNetwork(getVtapNetwork(), osNode, true));
+ log.debug("Apply {} nicira extension for tunneling", tunnelNicira ? "enable" : "disable");
+ } else {
+ tunnelNicira = updatedTunnelNicira;
+ }
+ }
+
+ log.info("Modified");
+ }
+
+ /**
+ * Initializes the flow rules and group tables, tunneling interface for all completed compute nodes.
+ */
+ @Override
+ public void initVtap() {
+ if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(osNode -> osNode.state() == COMPLETE)
+ .forEach(osNode -> initVtapForNode(osNode));
+ log.trace("{} flow rules, groups, tunnel interface are initialized", appId.name());
+ }
+ }
+
+ /**
+ * Clears the flow rules and group tables, tunneling interface for all compute nodes.
+ */
+ @Override
+ public void clearVtap() {
+ if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+ osNodeService.completeNodes(COMPUTE).stream()
+ .forEach(osNode -> clearVtapForNode(osNode));
+ log.trace("{} flow rules, groups, tunnel interface are cleared", appId.name());
+ }
+ }
+
+ /**
+ * Purges all flow rules and group tables, tunneling interface for openstack vtap.
+ */
+ @Override
+ public void purgeVtap() {
+ // Remove all flow rules
+ flowRuleService.removeFlowRulesById(appId);
+
+ // Remove all groups and tunnel interfaces
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(osNode -> osNode.state() == COMPLETE)
+ .forEach(osNode -> {
+ groupService.getGroups(osNode.intgBridge(), appId)
+ .forEach(group ->
+ groupService.removeGroup(osNode.intgBridge(), group.appCookie(), appId));
+
+ OpenstackVtapNetwork vtapNetwork = getVtapNetwork();
+ setTunnelInterface(osNode, vtapNetwork, false);
+ });
+
+ log.trace("{} all flow rules, groups, tunnel interface are purged", appId.name());
+ }
+
+ private void initVtapForNode(OpenstackNode osNode) {
+ // Make base vtap network
+ initVtapNetwork(osNode);
+
+ // Make vtap connections by OpenstackVtap config
+ getVtapsByDeviceId(osNode.intgBridge())
+ .forEach(vtap -> applyVtap(vtap, osNode, true));
+
+ // Make vtap networks by OpenstackVtapNetwork config
+ applyVtapNetwork(getVtapNetwork(), osNode, true);
+ }
+
+ private void clearVtapForNode(OpenstackNode osNode) {
+ // Clear vtap networks by OpenstackVtapNetwork config
+ applyVtapNetwork(getVtapNetwork(), osNode, false);
+
+ // Clear vtap connections by OpenstackVtap config
+ getVtapsByDeviceId(osNode.intgBridge())
+ .forEach(vtap -> applyVtap(vtap, osNode, false));
+
+ // Clear base vtap network
+ clearVtapNetwork(osNode);
+ }
+
+ /**
+ * Initializes vtap pipeline of the given device.
+ *
+ * @param osNode device identifier
+ */
+ private void initVtapNetwork(OpenstackNode osNode) {
+ // Create default output tables
+ for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+ setOutputTableForDrop(osNode.intgBridge(),
+ VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX], true);
+ }
+
+ // Create group tables
+ for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+ createGroupTable(osNode.intgBridge(),
+ VTAP_TABLES[idx][VTAP_TABLE_GROUP_IDX],
+ ImmutableList.of(VTAP_TABLES[idx][VTAP_TABLE_NEXT_IDX],
+ VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX]),
+ null);
+ }
+ }
+
+ /**
+ * Clear vtap pipeline of the given device.
+ *
+ * @param osNode device identifier
+ */
+ private void clearVtapNetwork(OpenstackNode osNode) {
+ // Clear group tables
+ for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+ removeGroupTable(osNode.intgBridge(),
+ VTAP_TABLES[idx][VTAP_TABLE_GROUP_IDX]);
+ }
+
+ // Clear default output tables
+ for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+ setOutputTableForDrop(osNode.intgBridge(),
+ VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX], false);
+ }
+ }
+
+ @Override
+ public OpenstackVtapNetwork getVtapNetwork() {
+ return store.getVtapNetwork(VTAP_NETWORK_KEY);
+ }
+
+ @Override
+ public OpenstackVtapNetwork createVtapNetwork(Mode mode, Integer networkId, IpAddress serverIp) {
+ checkNotNull(mode, VTAP_DESC_NULL, "mode");
+ checkNotNull(serverIp, VTAP_DESC_NULL, "serverIp");
+ DefaultOpenstackVtapNetwork vtapNetwork = DefaultOpenstackVtapNetwork.builder()
+ .mode(mode)
+ .networkId(networkId)
+ .serverIp(serverIp)
+ .build();
+ return store.createVtapNetwork(VTAP_NETWORK_KEY, vtapNetwork);
+ }
+
+ @Override
+ public OpenstackVtapNetwork updateVtapNetwork(OpenstackVtapNetwork description) {
+ checkNotNull(description, VTAP_DESC_NULL, "vtapNetwork");
+ return store.updateVtapNetwork(VTAP_NETWORK_KEY, description);
+ }
+
+ @Override
+ public OpenstackVtapNetwork removeVtapNetwork() {
+ return store.removeVtapNetwork(VTAP_NETWORK_KEY);
+ }
+
+ @Override
+ public Set<DeviceId> getVtapNetworkDevices() {
+ return store.getVtapNetworkDevices(VTAP_NETWORK_KEY);
}
@Override
@@ -241,87 +449,54 @@
}
@Override
- public OpenstackVtap getVtap(OpenstackVtapId vTapId) {
- checkNotNull(vTapId, VTAP_ID_NULL);
- return store.getVtap(vTapId);
+ public OpenstackVtap getVtap(OpenstackVtapId vtapId) {
+ return store.getVtap(vtapId);
}
@Override
- public Set<OpenstackVtap> getVtapsByDeviceId(OpenstackVtap.Type type,
- DeviceId deviceId) {
- checkNotNull(deviceId, DEVICE_ID_NULL);
- return store.getVtapsByDeviceId(type, deviceId);
+ public Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId) {
+ return store.getVtapsByDeviceId(deviceId);
}
@Override
- public OpenstackVtap createVtap(Type type, OpenstackVtapCriterion vTapCriterion) {
- checkNotNull(vTapCriterion, VTAP_DESC_NULL);
+ public OpenstackVtap createVtap(Type type, OpenstackVtapCriterion vtapCriterion) {
+ checkNotNull(type, VTAP_DESC_NULL, "type");
+ checkNotNull(vtapCriterion, VTAP_DESC_NULL, "vtapCriterion");
Set<DeviceId> txDevices = type.isValid(Type.VTAP_TX) ?
- getEdgeDevice(type, vTapCriterion) : ImmutableSet.of();
+ getEdgeDevice(Type.VTAP_TX, vtapCriterion) : ImmutableSet.of();
Set<DeviceId> rxDevices = type.isValid(Type.VTAP_RX) ?
- getEdgeDevice(type, vTapCriterion) : ImmutableSet.of();
+ getEdgeDevice(Type.VTAP_RX, vtapCriterion) : ImmutableSet.of();
- OpenstackVtap description =
- DefaultOpenstackVtap.builder()
- .id(OpenstackVtapId.vTapId())
- .type(type)
- .vTapCriterion(vTapCriterion)
- .txDeviceIds(txDevices)
- .rxDeviceIds(rxDevices)
- .build();
- return store.createOrUpdateVtap(description.id(), description, true);
+ DefaultOpenstackVtap description = DefaultOpenstackVtap.builder()
+ .id(OpenstackVtapId.vtapId())
+ .type(type)
+ .vtapCriterion(vtapCriterion)
+ .txDeviceIds(txDevices)
+ .rxDeviceIds(rxDevices)
+ .build();
+ return store.createVtap(description);
}
@Override
- public OpenstackVtap updateVtap(OpenstackVtapId vTapId, OpenstackVtap vTap) {
- checkNotNull(vTapId, VTAP_ID_NULL);
- checkNotNull(vTap, VTAP_DESC_NULL);
+ public OpenstackVtap updateVtap(OpenstackVtap description) {
+ checkNotNull(description, VTAP_DESC_NULL, "vtap");
- if (store.getVtap(vTapId) == null) {
- return null;
- }
+ Set<DeviceId> txDevices = description.type().isValid(Type.VTAP_TX) ?
+ getEdgeDevice(Type.VTAP_TX, description.vtapCriterion()) : ImmutableSet.of();
+ Set<DeviceId> rxDevices = description.type().isValid(Type.VTAP_RX) ?
+ getEdgeDevice(Type.VTAP_RX, description.vtapCriterion()) : ImmutableSet.of();
- Set<DeviceId> txDevices = vTap.type().isValid(Type.VTAP_TX) ?
- getEdgeDevice(vTap.type(), vTap.vTapCriterion()) : ImmutableSet.of();
- Set<DeviceId> rxDevices = vTap.type().isValid(Type.VTAP_RX) ?
- getEdgeDevice(vTap.type(), vTap.vTapCriterion()) : ImmutableSet.of();
-
- DefaultOpenstackVtap description =
- DefaultOpenstackVtap.builder()
- .id(vTapId)
- .type(vTap.type())
- .vTapCriterion(vTap.vTapCriterion())
- .txDeviceIds(txDevices)
- .rxDeviceIds(rxDevices)
- .build();
- return store.createOrUpdateVtap(vTapId, description, true);
+ DefaultOpenstackVtap vtap = DefaultOpenstackVtap.builder(description)
+ .txDeviceIds(txDevices)
+ .rxDeviceIds(rxDevices)
+ .build();
+ return store.updateVtap(vtap, true);
}
@Override
- public OpenstackVtap removeVtap(OpenstackVtapId vTapId) {
- checkNotNull(vTapId, VTAP_ID_NULL);
- return store.removeVtapById(vTapId);
- }
-
- @Override
- public void setVtapOutput(DeviceId deviceId, OpenstackVtap.Type type,
- PortNumber portNumber, VlanId vlanId) {
-
- // Make output table
- if (type.isValid(Type.VTAP_TX)) {
- createOutputTable(deviceId, VTAP_INBOUND_MIRROR_TABLE, portNumber, vlanId);
- }
-
- if (type.isValid(Type.VTAP_RX)) {
- createOutputTable(deviceId, VTAP_FLAT_OUTBOUND_MIRROR_TABLE, portNumber, vlanId);
- createOutputTable(deviceId, VTAP_OUTBOUND_MIRROR_TABLE, portNumber, vlanId);
- }
- }
-
- @Override
- public void setVtapOutput(DeviceId deviceId, Type type, PortNumber portNumber, int vni) {
- // TODO: need to provide implementation
+ public OpenstackVtap removeVtap(OpenstackVtapId vtapId) {
+ return store.removeVtap(vtapId);
}
/**
@@ -329,274 +504,138 @@
* Note that, in most of cases target host is attached to one device,
* however, in some cases, the host can be attached to multiple devices.
*
- * @param type vTap type
- * @param criterion vTap criterion
+ * @param type vtap type
+ * @param criterion vtap criterion
* @return a collection of device identifiers
*/
private Set<DeviceId> getEdgeDevice(Type type, OpenstackVtapCriterion criterion) {
Set<DeviceId> deviceIds = Sets.newConcurrentHashSet();
StreamSupport.stream(hostService.getHosts().spliterator(), true)
- .forEach(host -> {
- if (host.ipAddresses().stream()
- .anyMatch(ip -> containsIp(type, criterion, ip))) {
- deviceIds.addAll(host.locations().stream()
- .map(HostLocation::deviceId)
- .collect(Collectors.toSet()));
- }
- });
+ .filter(host -> isValidHost(host) &&
+ host.ipAddresses().stream().anyMatch(ip -> containsIp(type, criterion, ip)))
+ .forEach(host -> {
+ Set<DeviceId> hostDeviceIds =
+ host.locations().stream()
+ .map(HostLocation::deviceId)
+ .filter(deviceId -> Objects.nonNull(osNodeService.node(deviceId)))
+ .collect(Collectors.toSet());
+ deviceIds.addAll(hostDeviceIds);
+ });
return deviceIds;
}
/**
- * Checks whether the given IP address is included in vTap criterion.
- * We both check the TX and RX directions.
- *
- * @param type vTap type
- * @param criterion vTap criterion
- * @param ip IP address
- * @return boolean value indicates the check result
- */
- private boolean containsIp(Type type, OpenstackVtapCriterion criterion, IpAddress ip) {
- boolean isTxEdge = type.isValid(Type.VTAP_TX) &&
- criterion.srcIpPrefix().contains(ip);
- boolean isRxEdge = type.isValid(Type.VTAP_RX) &&
- criterion.dstIpPrefix().contains(ip);
-
- return isTxEdge || isRxEdge;
- }
-
- /**
- * Updates device list of vTaps with respect to the host changes.
+ * Updates device list of vtaps with respect to the host changes.
*
* @param newHost new host instance
* @param oldHost old host instance
*/
+ private void updateHostbyType(Type type, Host newHost, Host oldHost) {
+ getVtaps(type).forEach(vtap -> {
+ IpPrefix prefix = (type == Type.VTAP_TX) ?
+ vtap.vtapCriterion().srcIpPrefix() :
+ vtap.vtapCriterion().dstIpPrefix();
+
+ int hostDiff = hostCompareIp(newHost, oldHost, prefix);
+ if (hostDiff < 0) {
+ oldHost.locations().stream()
+ .map(HostLocation::deviceId)
+ .forEach(deviceId ->
+ store.removeDeviceFromVtap(vtap.id(), type, deviceId));
+ } else if (hostDiff > 0) {
+ newHost.locations().stream()
+ .map(HostLocation::deviceId)
+ .filter(deviceId -> Objects.nonNull(osNodeService.node(deviceId)))
+ .forEach(deviceId ->
+ store.addDeviceToVtap(vtap.id(), type, deviceId));
+ }
+ });
+ }
+
private void updateHost(Host newHost, Host oldHost) {
- // update devices for vTap tx
- getVtaps(Type.VTAP_TX).parallelStream().forEach(vTap -> {
+ // update devices for vtap tx
+ updateHostbyType(Type.VTAP_TX, newHost, oldHost);
- if (hostDiff(oldHost, newHost, vTap.vTapCriterion().srcIpPrefix())) {
- oldHost.locations().stream().map(HostLocation::deviceId)
- .forEach(deviceId ->
- store.removeDeviceFromVtap(vTap.id(), Type.VTAP_TX,
- oldHost.location().deviceId()));
- }
-
- if (hostDiff(newHost, oldHost, vTap.vTapCriterion().srcIpPrefix())) {
- newHost.locations().stream().map(HostLocation::deviceId)
- .forEach(deviceId ->
- store.addDeviceToVtap(vTap.id(), Type.VTAP_TX,
- newHost.location().deviceId()));
- }
- });
-
- // update devices for vTap rx
- getVtaps(Type.VTAP_RX).parallelStream().forEach(vTap -> {
-
- if (hostDiff(oldHost, newHost, vTap.vTapCriterion().dstIpPrefix())) {
- oldHost.locations().stream().map(HostLocation::deviceId)
- .forEach(deviceId ->
- store.removeDeviceFromVtap(vTap.id(), Type.VTAP_RX,
- oldHost.location().deviceId()));
- }
-
- if (hostDiff(newHost, oldHost, vTap.vTapCriterion().dstIpPrefix())) {
- newHost.locations().stream().map(HostLocation::deviceId)
- .forEach(deviceId ->
- store.addDeviceToVtap(vTap.id(), Type.VTAP_RX,
- newHost.location().deviceId()));
- }
- });
+ // update devices for vtap rx
+ updateHostbyType(Type.VTAP_RX, newHost, oldHost);
}
- /**
- * Checks whether the given IP prefix is contained in the first host rather
- * than in the second host.
- *
- * @param host1 first host instance
- * @param host2 second host instance
- * @param ipPrefix IP prefix to be looked up
- * @return boolean value
- */
- private boolean hostDiff(Host host1, Host host2, IpPrefix ipPrefix) {
- return ((host1 != null && host1.ipAddresses().stream().anyMatch(ipPrefix::contains)) &&
- (host2 == null || host2.ipAddresses().stream().noneMatch(ipPrefix::contains)));
- }
+ private void applyFlowRule(FlowRule flowRule, boolean install) {
+ FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
- /**
- * Initializes the flow rules and group tables for all completed compute nodes.
- */
- private void initFlowAndGroupForCompNodes() {
- osNodeService.completeNodes(COMPUTE).forEach(node ->
- initFlowAndGroupByDeviceId(node.intgBridge()));
- }
-
- /**
- * Initializes the flow rules and group table of the given device identifier.
- *
- * @param deviceId device identifier
- */
- private void initFlowAndGroupByDeviceId(DeviceId deviceId) {
- // Make vTap pipeline
- // TODO: need to selective creation by store device consistentMap
- initVtapPipeline(deviceId);
-
- // Install tx filter
- getVtapsByDeviceId(Type.VTAP_TX, deviceId).forEach(vTap -> {
- connectTables(deviceId,
- VTAP_INBOUND_TABLE, NONE_TABLE, VTAP_INBOUND_GROUP_TABLE,
- vTap.vTapCriterion(), PRIORITY_VTAP_RULE, true);
- });
-
- // Install rx filter
- getVtapsByDeviceId(Type.VTAP_RX, deviceId).forEach(vTap -> {
- connectTables(deviceId,
- VTAP_FLAT_OUTBOUND_TABLE, NONE_TABLE, VTAP_FLAT_OUTBOUND_GROUP_TABLE,
- vTap.vTapCriterion(), PRIORITY_VTAP_RULE, true);
- connectTables(deviceId,
- VTAP_OUTBOUND_TABLE, NONE_TABLE, VTAP_OUTBOUND_GROUP_TABLE,
- vTap.vTapCriterion(), PRIORITY_VTAP_RULE, true);
- });
- }
-
- /**
- * Initializes vTap pipeline of the given device.
- *
- * @param deviceId device identifier
- */
- private void initVtapPipeline(DeviceId deviceId) {
- // Make output table
- createOutputTable(deviceId, VTAP_INBOUND_MIRROR_TABLE, null, null);
- createOutputTable(deviceId, VTAP_FLAT_OUTBOUND_MIRROR_TABLE, null, null);
- createOutputTable(deviceId, VTAP_OUTBOUND_MIRROR_TABLE, null, null);
-
- // Make tx group table
- createGroupTable(deviceId, VTAP_INBOUND_GROUP_TABLE,
- ImmutableList.of(INBOUND_NEXT_TABLE, VTAP_INBOUND_MIRROR_TABLE),
- ImmutableList.of());
-
- // Make rx group table
- createGroupTable(deviceId, VTAP_FLAT_OUTBOUND_GROUP_TABLE,
- ImmutableList.of(FLAT_OUTBOUND_NEXT_TABLE, VTAP_FLAT_OUTBOUND_MIRROR_TABLE),
- ImmutableList.of());
- createGroupTable(deviceId, VTAP_OUTBOUND_GROUP_TABLE,
- ImmutableList.of(OUTBOUND_NEXT_TABLE, VTAP_OUTBOUND_MIRROR_TABLE),
- ImmutableList.of());
- }
-
- /**
- * Purges all flow rules and group tables for completed compute nodes.
- */
- private void clearFlowAndGroupForCompNodes() {
- osNodeService.completeNodes(COMPUTE).forEach(node ->
- clearFlowAndGroupByDeviceId(node.intgBridge()));
- }
-
- /**
- * Purges all flow rules and group tables using the given device identifier.
- *
- * @param deviceId device identifier
- */
- private void clearFlowAndGroupByDeviceId(DeviceId deviceId) {
- Set<FlowRule> purgedRules = Sets.newConcurrentHashSet();
- for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
- if (flowRule.deviceId().equals(deviceId)) {
- purgedRules.add(flowRule);
- }
+ if (install) {
+ flowOpsBuilder.add(flowRule);
+ } else {
+ flowOpsBuilder.remove(flowRule);
}
- flowRuleService.removeFlowRules(purgedRules.toArray(new FlowRule[0]));
+ flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
+ @Override
+ public void onSuccess(FlowRuleOperations ops) {
+ log.debug("Installed flow rules for vtap");
+ }
- groupService.getGroups(deviceId, appId).forEach(group -> {
- groupService.removeGroup(deviceId, group.appCookie(), appId);
- });
- log.info("OpenstackVtap flow rules and groups are purged");
+ @Override
+ public void onError(FlowRuleOperations ops) {
+ log.warn("Failed to install flow rules for vtap");
+ }
+ }));
}
- private void installFilterRule(Set<DeviceId> txDeviceIds, Set<DeviceId> rxDeviceIds,
- OpenstackVtapCriterion vTapCriterion, boolean install) {
- final int inbound = 0;
- final int flatOutbound = 1;
- final int outbound = 2;
-
- BiFunction<Set<DeviceId>, Integer, Void> installFlow = (deviceIds, table) -> {
- int inTable = (table == inbound ? VTAP_INBOUND_TABLE :
- (table == flatOutbound ? VTAP_FLAT_OUTBOUND_TABLE :
- VTAP_OUTBOUND_TABLE));
-
- int outGroup = (table == inbound ? VTAP_INBOUND_GROUP_TABLE :
- (table == flatOutbound ? VTAP_FLAT_OUTBOUND_GROUP_TABLE :
- VTAP_OUTBOUND_GROUP_TABLE));
-
- deviceIds.stream()
- .filter(deviceId -> mastershipService.isLocalMaster(deviceId))
- .forEach(deviceId -> {
- connectTables(deviceId, inTable, NONE_TABLE, outGroup,
- vTapCriterion, PRIORITY_VTAP_RULE, install);
- });
- return null;
- };
-
- installFlow.apply(txDeviceIds, inbound);
- installFlow.apply(rxDeviceIds, flatOutbound);
- installFlow.apply(rxDeviceIds, outbound);
- }
-
- private void connectTables(DeviceId deviceId, int fromTable, int toTable, int toGroup,
- OpenstackVtapCriterion vTapCriterion, int rulePriority,
- boolean install) {
- log.trace("Table Transition: table[{}] -> table[{}] or group[{}]", fromTable, toTable, toGroup);
+ private void connectTables(DeviceId deviceId,
+ int fromTable,
+ int toTableOrGroup, boolean isGroup,
+ OpenstackVtapCriterion vtapCriterion,
+ int rulePriority, boolean install) {
+ log.debug("Table Transition: table[{}] -> table/group[{}]", fromTable, toTableOrGroup);
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
.matchEthType(TYPE_IPV4);
// if the IpPrefix is "0.0.0.0/0", we do not include such a match into the flow rule
- if (!vTapCriterion.srcIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
- selectorBuilder.matchIPSrc(vTapCriterion.srcIpPrefix());
+ if (!vtapCriterion.srcIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
+ selectorBuilder.matchIPSrc(vtapCriterion.srcIpPrefix());
}
- if (!vTapCriterion.dstIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
- selectorBuilder.matchIPDst(vTapCriterion.dstIpPrefix());
+ if (!vtapCriterion.dstIpPrefix().equals(ARBITRARY_IP_PREFIX)) {
+ selectorBuilder.matchIPDst(vtapCriterion.dstIpPrefix());
}
- switch (vTapCriterion.ipProtocol()) {
+ switch (vtapCriterion.ipProtocol()) {
case PROTOCOL_TCP:
- selectorBuilder.matchIPProtocol(vTapCriterion.ipProtocol());
+ selectorBuilder.matchIPProtocol(vtapCriterion.ipProtocol());
// Add port match only if the port number is greater than zero
- if (vTapCriterion.srcTpPort().toInt() > 0) {
- selectorBuilder.matchTcpSrc(vTapCriterion.srcTpPort());
+ if (vtapCriterion.srcTpPort().toInt() > 0) {
+ selectorBuilder.matchTcpSrc(vtapCriterion.srcTpPort());
}
- if (vTapCriterion.dstTpPort().toInt() > 0) {
- selectorBuilder.matchTcpDst(vTapCriterion.dstTpPort());
+ if (vtapCriterion.dstTpPort().toInt() > 0) {
+ selectorBuilder.matchTcpDst(vtapCriterion.dstTpPort());
}
break;
case PROTOCOL_UDP:
- selectorBuilder.matchIPProtocol(vTapCriterion.ipProtocol());
+ selectorBuilder.matchIPProtocol(vtapCriterion.ipProtocol());
// Add port match only if the port number is greater than zero
- if (vTapCriterion.srcTpPort().toInt() > 0) {
- selectorBuilder.matchUdpSrc(vTapCriterion.srcTpPort());
+ if (vtapCriterion.srcTpPort().toInt() > 0) {
+ selectorBuilder.matchUdpSrc(vtapCriterion.srcTpPort());
}
- if (vTapCriterion.dstTpPort().toInt() > 0) {
- selectorBuilder.matchUdpDst(vTapCriterion.dstTpPort());
+ if (vtapCriterion.dstTpPort().toInt() > 0) {
+ selectorBuilder.matchUdpDst(vtapCriterion.dstTpPort());
}
break;
case PROTOCOL_ICMP:
- selectorBuilder.matchIPProtocol(vTapCriterion.ipProtocol());
+ selectorBuilder.matchIPProtocol(vtapCriterion.ipProtocol());
break;
default:
break;
}
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
- if (toTable != NONE_TABLE) {
- treatmentBuilder.transition(toTable);
- } else if (toGroup != NONE_TABLE) {
- treatmentBuilder.group(GroupId.valueOf(toGroup));
+ if (isGroup) {
+ treatmentBuilder.group(GroupId.valueOf(toTableOrGroup));
} else {
- log.warn("Not specified toTable or toGroup value");
- return;
+ treatmentBuilder.transition(toTableOrGroup);
}
FlowRule flowRule = DefaultFlowRule.builder()
@@ -612,69 +651,246 @@
applyFlowRule(flowRule, install);
}
- private void createOutputTable(DeviceId deviceId, int tableId,
- PortNumber outPort, VlanId vlanId) {
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-
- // Set output port & vlan
- int priority = PRIORITY_VTAP_DROP;
- if (vlanId != null && vlanId.toShort() != UNTAGGED) {
- treatment.pushVlan().setVlanId(vlanId);
+ /**
+ * Creates/Removes a tunnel interface in a given openstack node by vtap network information.
+ *
+ * @param osNode openstack node
+ * @param vtapNetwork openstack vtap network for making
+ *
+ */
+ private boolean setTunnelInterface(OpenstackNode osNode,
+ OpenstackVtapNetwork vtapNetwork,
+ boolean install) {
+ String tunnelName = getTunnelName(vtapNetwork.mode());
+ if (tunnelName == null) {
+ return false;
}
- if (outPort != null) {
- treatment.setOutput(outPort);
- priority = PRIORITY_VTAP_OUTPORT_RULE;
+
+ if (!deviceService.isAvailable(osNode.ovsdb())) {
+ log.warn("Not available osNode {} ovs {}", osNode.hostname(), osNode.ovsdb());
+ return false;
+ }
+
+ if (install == isInterfaceEnabled(osNode.intgBridge(), tunnelName)) {
+ log.warn("Already {} {} interface on osNode ovs {}, bridge {}",
+ install ? "add" : "remove",
+ tunnelName, osNode.ovsdb(), osNode.intgBridge());
+ return true;
+ }
+
+ Device device = deviceService.getDevice(osNode.ovsdb());
+ if (device == null || !device.is(InterfaceConfig.class)) {
+ log.warn("Not able to get InterfaceConfig on osNode ovs {}", osNode.ovsdb());
+ return false;
+ }
+
+ InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
+ if (install) {
+ TunnelDescription.Builder tunnelDesc = DefaultTunnelDescription.builder()
+ .deviceId(INTEGRATION_BRIDGE)
+ .ifaceName(tunnelName)
+ .type(getTunnelType(vtapNetwork.mode()))
+ .key((vtapNetwork.networkId() == 0) ? null : new TunnelKey<>(vtapNetwork.networkId()))
+ .remote(TunnelEndPoints.ipTunnelEndpoint(vtapNetwork.serverIp()));
+ if (!ifaceConfig.addTunnelMode(tunnelName, tunnelDesc.build())) {
+ log.error("Fail to create {} interface on osNode ovs {}", tunnelName, osNode.ovsdb());
+ return false;
+ }
+ } else {
+ if (!ifaceConfig.removeTunnelMode(tunnelName)) {
+ log.error("Fail to remove {} interface on osNode ovs {}", tunnelName, osNode.ovsdb());
+ return false;
+ }
+ }
+
+ // Wait for tunnel interface create/remove complete
+ synchronized (syncInterface) {
+ for (int i = 0; i < INTERFACE_MANIPULATION_RETRY; i++) {
+ try {
+ syncInterface.wait(INTERFACE_MANIPULATION_TIMEOUT);
+ if (install == isInterfaceEnabled(osNode.intgBridge(), tunnelName)) {
+ log.debug("Success to {} {} interface on osNode ovs {}, bridge {}",
+ install ? "add" : "remove",
+ tunnelName, osNode.ovsdb(), osNode.intgBridge());
+ return true;
+ }
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ log.warn("Fail to {} {} interface on osNode ovs {}, bridge {}",
+ install ? "add" : "remove",
+ tunnelName, osNode.ovsdb(), osNode.intgBridge());
+ return false;
+ }
+
+ /**
+ * Checks whether a given network interface in a given openstack node is enabled or not.
+ *
+ * @param deviceId openstack node
+ * @param interfaceName network interface name
+ * @return true if the given interface is enabled, false otherwise
+ */
+ private boolean isInterfaceEnabled(DeviceId deviceId, String interfaceName) {
+ return deviceService.isAvailable(deviceId) &&
+ deviceService.getPorts(deviceId).parallelStream().anyMatch(port ->
+ Objects.equals(port.annotations().value(PORT_NAME), interfaceName) && port.isEnabled());
+ }
+
+ private PortNumber portNumber(DeviceId deviceId, String interfaceName) {
+ Port port = deviceService.getPorts(deviceId).stream()
+ .filter(p -> p.isEnabled() &&
+ Objects.equals(p.annotations().value(PORT_NAME), interfaceName))
+ .findAny().orElse(null);
+ return port != null ? port.number() : null;
+ }
+
+ private void setOutputTableForTunnel(DeviceId deviceId, int tableId,
+ PortNumber outPort, IpAddress serverIp,
+ boolean install) {
+ log.debug("setOutputTableForTunnel[{}]: deviceId={}, tableId={}, outPort={}, serverIp={}",
+ install ? "add" : "remove", deviceId, tableId, outPort, serverIp);
+
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+ .setOutput(outPort);
+
+ if (tunnelNicira) {
+ ExtensionTreatment extensionTreatment = buildTunnelExtension(deviceId, serverIp);
+ if (extensionTreatment == null) {
+ return;
+ }
+ treatment.extension(extensionTreatment, deviceId);
}
FlowRule flowRule = DefaultFlowRule.builder()
.forDevice(deviceId)
.withSelector(selector.build())
.withTreatment(treatment.build())
- .withPriority(priority)
+ .withPriority(PRIORITY_VTAP_OUTPUT_RULE)
.makePermanent()
.forTable(tableId)
.fromApp(appId)
.build();
- applyFlowRule(flowRule, true);
+
+ log.debug("setOutputTableForTunnel flowRule={}, install={}", flowRule, install);
+ applyFlowRule(flowRule, install);
}
- private ExtensionTreatment buildNiciraExtension(DeviceId id, int tableId) {
- Driver driver = driverService.getDriver(id);
- DriverHandler driverHandler =
- new DefaultDriverHandler(new DefaultDriverData(driver, id));
- ExtensionTreatmentResolver resolver =
- driverHandler.behaviour(ExtensionTreatmentResolver.class);
+ private void setOutputTableForDrop(DeviceId deviceId, int tableId,
+ boolean install) {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
- ExtensionTreatment extensionInstruction =
- resolver.getExtensionInstruction(NICIRA_RESUBMIT_TABLE.type());
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(selector.build())
+ .withTreatment(treatment.build())
+ .withPriority(PRIORITY_VTAP_OUTPUT_DROP)
+ .makePermanent()
+ .forTable(tableId)
+ .fromApp(appId)
+ .build();
+ applyFlowRule(flowRule, install);
+ }
- try {
- extensionInstruction.setPropertyValue(TABLE_PROPERTY_KEY, ((short) tableId));
- } catch (Exception e) {
- log.error("Failed to set extension treatment for resubmit table {}", id);
+ private void setOutputTable(DeviceId deviceId, Mode mode,
+ IpAddress serverIp, boolean install) {
+ log.debug("setOutputTable[{}]: deviceId={}, mode={}, serverIp={}",
+ install ? "add" : "remove", deviceId, mode, serverIp);
+
+ if (deviceId == null) {
+ return;
}
- return extensionInstruction;
+ switch (mode) {
+ case GRE:
+ case VXLAN:
+ String tunnelName = getTunnelName(mode);
+ PortNumber vtapPort = portNumber(deviceId, tunnelName);
+ if (vtapPort != null) {
+ for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+ setOutputTableForTunnel(deviceId, VTAP_TABLES[idx][VTAP_TABLE_OUTPUT_IDX],
+ vtapPort, serverIp, install);
+ }
+ } else {
+ log.warn("Vtap tunnel port {} doesn't exist", tunnelName);
+ }
+ break;
+ default:
+ log.warn("Invalid vtap network mode {}", mode);
+ break;
+ }
+ }
+
+ /**
+ * Returns tunnel destination extension treatment object.
+ *
+ * @param deviceId device id to apply this treatment
+ * @param remoteIp tunnel destination ip address
+ * @return extension treatment
+ */
+ private ExtensionTreatment buildTunnelExtension(DeviceId deviceId, IpAddress remoteIp) {
+ Device device = deviceService.getDevice(deviceId);
+ if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
+ log.warn("Nicira extension treatment is not supported");
+ return null;
+ }
+
+ ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+ ExtensionTreatment treatment =
+ resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
+ try {
+ treatment.setPropertyValue(TUNNEL_DST_EXTENSION, remoteIp.getIp4Address());
+ return treatment;
+ } catch (ExtensionPropertyException e) {
+ log.error("Failed to set nicira tunnelDst extension treatment for {}", deviceId);
+ return null;
+ }
+ }
+
+ private ExtensionTreatment buildResubmitExtension(DeviceId deviceId, int tableId) {
+ Device device = deviceService.getDevice(deviceId);
+ if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
+ log.warn("Nicira extension treatment is not supported");
+ return null;
+ }
+
+ ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+ ExtensionTreatment treatment =
+ resolver.getExtensionInstruction(NICIRA_RESUBMIT_TABLE.type());
+
+ try {
+ treatment.setPropertyValue(TABLE_EXTENSION, ((short) tableId));
+ return treatment;
+ } catch (ExtensionPropertyException e) {
+ log.error("Failed to set nicira resubmit extension treatment for {}", deviceId);
+ return null;
+ }
}
private void createGroupTable(DeviceId deviceId, int groupId,
List<Integer> tableIds, List<PortNumber> ports) {
List<GroupBucket> buckets = Lists.newArrayList();
- tableIds.forEach(tableId -> {
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
- .extension(buildNiciraExtension(deviceId, tableId), deviceId);
- GroupBucket bucket = DefaultGroupBucket
- .createAllGroupBucket(treatment.build());
- buckets.add(bucket);
- });
- ports.forEach(port -> {
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
- .setOutput(port);
- GroupBucket bucket = DefaultGroupBucket
- .createAllGroupBucket(treatment.build());
- buckets.add(bucket);
- });
+ if (tableIds != null) {
+ tableIds.forEach(tableId -> {
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+ .extension(buildResubmitExtension(deviceId, tableId), deviceId);
+ GroupBucket bucket = DefaultGroupBucket
+ .createAllGroupBucket(treatment.build());
+ buckets.add(bucket);
+ });
+ }
+ if (ports != null) {
+ ports.forEach(port -> {
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
+ .setOutput(port);
+ GroupBucket bucket = DefaultGroupBucket
+ .createAllGroupBucket(treatment.build());
+ buckets.add(bucket);
+ });
+ }
GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
GroupDescription.Type.ALL,
@@ -685,42 +901,36 @@
groupService.addGroup(groupDescription);
}
- private void applyFlowRule(FlowRule flowRule, boolean install) {
- FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
-
- flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
-
- flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
- @Override
- public void onSuccess(FlowRuleOperations ops) {
- log.debug("Installed flow rules for tapping");
- }
-
- @Override
- public void onError(FlowRuleOperations ops) {
- log.debug("Failed to install flow rules for tapping");
- }
- }));
+ private void removeGroupTable(DeviceId deviceId, int groupId) {
+ groupService.removeGroup(deviceId, getGroupKey(groupId), appId);
}
+ /**
+ * Internal listener for device events.
+ */
private class InternalDeviceListener implements DeviceListener {
- @Override
- public boolean isRelevant(DeviceEvent event) {
- // do not allow to proceed without Mastership
- DeviceId deviceId = event.subject().id();
- return mastershipService.isLocalMaster(deviceId) &&
- event.subject().type() == Device.Type.SWITCH;
- }
@Override
public void event(DeviceEvent event) {
DeviceEvent.Type type = event.type();
- DeviceId deviceId = event.subject().id();
- log.trace("InternalDeviceListener deviceId={}, type={}", deviceId, type);
+ Device device = event.subject();
switch (type) {
- case DEVICE_ADDED:
- eventExecutor.execute(() -> initFlowAndGroupByDeviceId(deviceId));
+ case PORT_ADDED:
+ case PORT_UPDATED:
+ case PORT_REMOVED:
+ String portName = event.port().annotations().value(PORT_NAME);
+ if (portName.equals(getTunnelName(Mode.GRE)) ||
+ portName.equals(getTunnelName(Mode.VXLAN))) {
+ log.trace("InternalDeviceListener type={}, host={}", type, device);
+ synchronized (syncInterface) {
+ try {
+ syncInterface.notifyAll();
+ } catch (IllegalMonitorStateException e) {
+ log.warn("Already syncInterface exited");
+ }
+ }
+ }
break;
default:
break;
@@ -728,9 +938,60 @@
}
}
+ /**
+ * Internal listener for openstack node events.
+ */
+ private class InternalOpenstackNodeListener implements OpenstackNodeListener {
+
+ @Override
+ public boolean isRelevant(OpenstackNodeEvent event) {
+ // do not allow to proceed without leadership and compute node
+ NodeId leader = leadershipService.getLeader(appId.name());
+ OpenstackNode osNode = event.subject();
+
+ return Objects.equals(localNodeId, leader) && osNode.type() == COMPUTE;
+ }
+
+ @Override
+ public void event(OpenstackNodeEvent event) {
+ OpenstackNodeEvent.Type type = event.type();
+ OpenstackNode osNode = event.subject();
+ log.trace("InternalOpenstackNodeListener type={}, osNode={}", type, osNode);
+
+ eventExecutor.execute(() -> {
+ try {
+ switch (type) {
+ case OPENSTACK_NODE_COMPLETE:
+ initVtapForNode(osNode);
+ break;
+
+ case OPENSTACK_NODE_REMOVED:
+ clearVtapForNode(osNode);
+ break;
+
+ default:
+ break;
+ }
+ } catch (Exception e) {
+ dumpStackTrace(log, e);
+ }
+ });
+ }
+ }
+
+ /**
+ * Internal listener for host events.
+ */
private class InternalHostListener implements HostListener {
+
@Override
public boolean isRelevant(HostEvent event) {
+ Host host = event.subject();
+ if (!isValidHost(host)) {
+ log.debug("Invalid host detected, ignore it {}", host);
+ return false;
+ }
+
// do not allow to proceed without leadership
NodeId leader = leadershipService.getLeader(appId.name());
return Objects.equals(localNodeId, leader);
@@ -740,102 +1001,173 @@
public void event(HostEvent event) {
HostEvent.Type type = event.type();
Host host = event.subject();
- log.trace("InternalHostListener hostId={}, type={}", host.id(), type);
+ Host prevHost = event.prevSubject();
+ log.trace("InternalHostListener {}: {} -> {}", type, prevHost, host);
- switch (type) {
- case HOST_ADDED:
- eventExecutor.execute(() -> updateHost(host, null));
- break;
+ eventExecutor.execute(() -> {
+ try {
+ switch (event.type()) {
+ case HOST_ADDED:
+ updateHost(host, null);
+ break;
- case HOST_REMOVED:
- eventExecutor.execute(() -> updateHost(null, host));
- break;
+ case HOST_REMOVED:
+ updateHost(null, host);
+ break;
- case HOST_UPDATED:
- case HOST_MOVED:
- eventExecutor.execute(() -> updateHost(host, event.prevSubject()));
- break;
- default:
- break;
- }
- }
- }
+ case HOST_MOVED:
+ case HOST_UPDATED:
+ updateHost(host, prevHost);
+ break;
- private class InternalOpenstackNodeListener implements OpenstackNodeListener {
-
- @Override
- public boolean isRelevant(OpenstackNodeEvent event) {
- // do not allow to proceed without leadership
- NodeId leader = leadershipService.getLeader(appId.name());
- return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
- }
-
- @Override
- public void event(OpenstackNodeEvent event) {
- DeviceId deviceId = event.subject().intgBridge();
- switch (event.type()) {
- case OPENSTACK_NODE_CREATED:
- case OPENSTACK_NODE_UPDATED:
- eventExecutor.execute(() -> initFlowAndGroupByDeviceId(deviceId));
- break;
- case OPENSTACK_NODE_REMOVED:
- eventExecutor.execute(() -> clearFlowAndGroupByDeviceId(deviceId));
- break;
- default:
- break;
- }
+ default:
+ break;
+ }
+ } catch (Exception e) {
+ dumpStackTrace(log, e);
+ }
+ });
}
}
// Store delegate to re-post events emitted from the store.
private class InternalStoreDelegate implements OpenstackVtapStoreDelegate {
+
@Override
public void notify(OpenstackVtapEvent event) {
OpenstackVtapEvent.Type type = event.type();
- OpenstackVtap vTap = event.subject();
- log.trace("vTapStoreDelegate vTap={}, type={}", vTap, type);
+ log.trace("InternalStoreDelegate {}: {} -> {}", type, event.prevSubject(), event.subject());
- switch (type) {
- case VTAP_ADDED:
- eventExecutor.execute(() -> {
- // Add new devices
- installFilterRule(vTap.txDeviceIds(), vTap.rxDeviceIds(),
- vTap.vTapCriterion(), true);
- });
- break;
+ if (Objects.equals(localNodeId, leadershipService.getLeader(appId.name()))) {
+ eventExecutor.execute(() -> {
+ try {
+ switch (type) {
+ case VTAP_NETWORK_ADDED:
+ case VTAP_NETWORK_UPDATED:
+ case VTAP_NETWORK_REMOVED:
+ // Update network
+ updateVtapNetwork(event.openstackVtapNetwork(),
+ event.prevOpenstackVtapNetwork());
+ break;
- case VTAP_UPDATED:
- OpenstackVtap oldOpenstackVtap = event.prevSubject();
- eventExecutor.execute(() -> {
- // Remove excluded devices
- installFilterRule(
- Sets.difference(oldOpenstackVtap.txDeviceIds(),
- vTap.txDeviceIds()),
- Sets.difference(oldOpenstackVtap.rxDeviceIds(),
- vTap.rxDeviceIds()),
- oldOpenstackVtap.vTapCriterion(), false);
+ case VTAP_ADDED:
+ case VTAP_UPDATED:
+ case VTAP_REMOVED:
+ // Update vtap rule
+ updateVtap(event.openstackVtap(),
+ event.prevOpenstackVtap());
+ break;
- // Add new devices
- installFilterRule(
- Sets.difference(vTap.txDeviceIds(),
- oldOpenstackVtap.txDeviceIds()),
- Sets.difference(vTap.rxDeviceIds(),
- oldOpenstackVtap.rxDeviceIds()),
- vTap.vTapCriterion(), true);
- });
- break;
-
- case VTAP_REMOVED:
- eventExecutor.execute(() -> {
- // Remove excluded devices
- installFilterRule(vTap.txDeviceIds(), vTap.rxDeviceIds(),
- vTap.vTapCriterion(), false);
- });
- break;
- default:
- break;
+ default:
+ break;
+ }
+ } catch (Exception e) {
+ dumpStackTrace(log, e);
+ }
+ });
}
post(event);
}
}
+
+ private void applyVtap(OpenstackVtap vtap,
+ OpenstackNode osNode,
+ boolean install) {
+ if (vtap == null || osNode == null) {
+ return;
+ }
+
+ log.debug("applyVtap vtap={}, osNode={}, install={}", vtap, osNode, install);
+
+ DeviceId deviceId = osNode.intgBridge();
+ for (int idx = 0; idx < VTAP_TABLES.length; idx++) {
+ if ((idx == VTAP_TABLE_INBOUND_IDX &&
+ vtap.type().isValid(Type.VTAP_TX) &&
+ vtap.txDeviceIds().contains(deviceId)) ||
+ (idx != VTAP_TABLE_INBOUND_IDX &&
+ vtap.type().isValid(Type.VTAP_RX) &&
+ vtap.rxDeviceIds().contains(deviceId))) {
+ connectTables(deviceId,
+ VTAP_TABLES[idx][VTAP_TABLE_INPUT_IDX],
+ VTAP_TABLES[idx][VTAP_TABLE_GROUP_IDX],
+ true,
+ vtap.vtapCriterion(), PRIORITY_VTAP_RULE, install);
+ }
+ }
+ }
+
+ private void updateVtap(OpenstackVtap vtap,
+ OpenstackVtap prevVtap) {
+ if (Objects.equals(vtap, prevVtap)) {
+ return;
+ }
+
+ Set<DeviceId> prevTxDeviceIds = (prevVtap != null ? prevVtap.txDeviceIds() : ImmutableSet.of());
+ Set<DeviceId> txDeviceIds = (vtap != null ? vtap.txDeviceIds() : ImmutableSet.of());
+ Set<DeviceId> prevRxDeviceIds = (prevVtap != null ? prevVtap.rxDeviceIds() : ImmutableSet.of());
+ Set<DeviceId> rxDeviceIds = (vtap != null ? vtap.rxDeviceIds() : ImmutableSet.of());
+
+ // Remake all vtap rule
+ if (prevVtap != null) {
+ Set<DeviceId> deviceIds = Sets.newHashSet();
+ deviceIds.addAll(Sets.difference(prevTxDeviceIds, txDeviceIds));
+ deviceIds.addAll(Sets.difference(prevRxDeviceIds, rxDeviceIds));
+ deviceIds.stream()
+ .map(deviceId -> osNodeService.node(deviceId))
+ .filter(osNode -> Objects.nonNull(osNode) &&
+ osNode.type() == COMPUTE)
+ .forEach(osNode -> applyVtap(prevVtap, osNode, false));
+ }
+ if (vtap != null) {
+ Set<DeviceId> deviceIds = Sets.newHashSet();
+ deviceIds.addAll(Sets.difference(txDeviceIds, prevTxDeviceIds));
+ deviceIds.addAll(Sets.difference(rxDeviceIds, prevRxDeviceIds));
+ deviceIds.stream()
+ .map(deviceId -> osNodeService.node(deviceId))
+ .filter(osNode -> Objects.nonNull(osNode) &&
+ osNode.type() == COMPUTE && osNode.state() == COMPLETE)
+ .forEach(osNode -> applyVtap(vtap, osNode, true));
+ }
+ }
+
+ // create/remove tunnel interface and output table
+ private boolean applyVtapNetwork(OpenstackVtapNetwork vtapNetwork,
+ OpenstackNode osNode,
+ boolean install) {
+ if (vtapNetwork == null || osNode == null) {
+ return false;
+ }
+
+ if (install) {
+ if (setTunnelInterface(osNode, vtapNetwork, true)) {
+ setOutputTable(osNode.intgBridge(), vtapNetwork.mode(), vtapNetwork.serverIp(), true);
+ store.addDeviceToVtapNetwork(VTAP_NETWORK_KEY, osNode.intgBridge());
+ return true;
+ }
+ } else {
+ Set<DeviceId> deviceIds = getVtapNetworkDevices();
+ if (deviceIds != null && deviceIds.contains(osNode.intgBridge())) {
+ store.removeDeviceFromVtapNetwork(VTAP_NETWORK_KEY, osNode.intgBridge());
+ setOutputTable(osNode.intgBridge(), vtapNetwork.mode(), vtapNetwork.serverIp(), false);
+ setTunnelInterface(osNode, vtapNetwork, false);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void updateVtapNetwork(OpenstackVtapNetwork network,
+ OpenstackVtapNetwork prevNetwork) {
+ // Remake all output tables
+ if (prevNetwork != null) {
+ osNodeService.completeNodes(COMPUTE)
+ .forEach(osNode -> applyVtapNetwork(prevNetwork, osNode, false));
+ }
+ if (network != null) {
+ osNodeService.completeNodes(COMPUTE).stream()
+ .filter(osNode -> osNode.state() == COMPLETE)
+ .forEach(osNode -> applyVtapNetwork(network, osNode, true));
+ }
+ }
+
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java
index cc5feb7..7790c8a 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/impl/package-info.java
@@ -15,6 +15,6 @@
*/
/**
- * Implementation for Openstack vtap.
+ * Implementation for openstack vtap.
*/
package org.onosproject.openstackvtap.impl;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java
index 1e67693..69919be 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/OpenstackVtapUtil.java
@@ -16,15 +16,31 @@
package org.onosproject.openstackvtap.util;
import org.onlab.packet.IPv4;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.Host;
+import org.onosproject.net.behaviour.TunnelDescription;
import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.GroupKey;
import org.onosproject.openstackvtap.api.OpenstackVtap;
+import org.onosproject.openstackvtap.api.OpenstackVtapCriterion;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.slf4j.Logger;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+
+import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_NETWORK_ID;
+import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_PORT_ID;
/**
- * An utility that used in openstack vTap app.
+ * An utilities that used in openstack vtap app.
*/
public final class OpenstackVtapUtil {
+ private static final String VTAP_TUNNEL_GRE = "vtap_gre";
+ private static final String VTAP_TUNNEL_VXLAN = "vtap_vxlan";
private static final String VTAP_GROUP_KEY = "VTAP_GROUP_KEY";
/**
@@ -34,31 +50,10 @@
}
/**
- * Obtains vTap type from the given string.
- *
- * @param str string
- * @return vTap type
- */
- public static OpenstackVtap.Type getVtapTypeFromString(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;
- case "none":
- return OpenstackVtap.Type.VTAP_NONE;
- default:
- throw new IllegalArgumentException("Invalid vTap type string");
- }
- }
-
- /**
* Obtains IP protocol type from the given string.
*
- * @param str string
- * @return vTap type
+ * @param str protocol string
+ * @return IP protocol number
*/
public static byte getProtocolTypeFromString(String str) {
switch (str) {
@@ -68,12 +63,132 @@
return IPv4.PROTOCOL_UDP;
case "icmp":
return IPv4.PROTOCOL_ICMP;
- default:
+ case "any":
return 0;
+ default:
+ throw new IllegalArgumentException("Invalid vtap protocol string");
}
}
+ /**
+ * Obtains openstack vtap type from the given string.
+ *
+ * @param str vtap type string
+ * @return vtap type
+ */
+ public static OpenstackVtap.Type getVtapTypeFromString(String str) {
+ switch (str) {
+ case "all":
+ return OpenstackVtap.Type.VTAP_ALL;
+ case "rx":
+ return OpenstackVtap.Type.VTAP_RX;
+ case "tx":
+ return OpenstackVtap.Type.VTAP_TX;
+ case "any":
+ return OpenstackVtap.Type.VTAP_ANY;
+ default:
+ throw new IllegalArgumentException("Invalid vtap type string");
+ }
+ }
+
+ /**
+ * Checks whether the given IP address is included in vtap criterion with
+ * TX and RX directions by given vtap type.
+ *
+ * @param type vtap type
+ * @param criterion vtap criterion
+ * @param ip IP address to check
+ * @return true on match address, false otherwise
+ */
+ public static boolean containsIp(OpenstackVtap.Type type, OpenstackVtapCriterion criterion, IpAddress ip) {
+ boolean isTxEdge = type.isValid(OpenstackVtap.Type.VTAP_TX) &&
+ criterion.srcIpPrefix().contains(ip);
+ boolean isRxEdge = type.isValid(OpenstackVtap.Type.VTAP_RX) &&
+ criterion.dstIpPrefix().contains(ip);
+ return isTxEdge || isRxEdge;
+ }
+
+ /**
+ * Checks the host validation from annotation information.
+ *
+ * @param host host to check
+ * @return true on validate, false otherwise
+ */
+ public static boolean isValidHost(Host host) {
+ return !host.ipAddresses().isEmpty() &&
+ host.annotations().value(ANNOTATION_NETWORK_ID) != null &&
+ host.annotations().value(ANNOTATION_PORT_ID) != null;
+ }
+
+ /**
+ * Checks whether the given IP prefix is contained in the first host rather
+ * than in the second host.
+ *
+ * @param host1 first host instance
+ * @param host2 second host instance
+ * @param ipPrefix IP prefix to be looked up
+ * @return a negative integer, zero, or a positive integer as the
+ * first argument is less than, equal to, or greater than the
+ * second.
+ */
+ public static int hostCompareIp(Host host1, Host host2, IpPrefix ipPrefix) {
+ if ((host1 == null || host1.ipAddresses().stream().noneMatch(ipPrefix::contains)) &&
+ (host2 != null || host2.ipAddresses().stream().anyMatch(ipPrefix::contains))) {
+ return -1;
+ } else if ((host1 != null && host1.ipAddresses().stream().anyMatch(ipPrefix::contains)) &&
+ (host2 == null || host2.ipAddresses().stream().noneMatch(ipPrefix::contains))) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * Obtains flow group key from the given id.
+ *
+ * @param groupId flow group identifier
+ * @return flow group key
+ */
public static GroupKey getGroupKey(int groupId) {
return new DefaultGroupKey((VTAP_GROUP_KEY + Integer.toString(groupId)).getBytes());
}
+
+ /**
+ * Obtains tunnel interface name from the given openstack vtap network mode.
+ *
+ * @param mode vtap network mode
+ * @return tunnel interface name
+ */
+ public static String getTunnelName(OpenstackVtapNetwork.Mode mode) {
+ switch (mode) {
+ case GRE:
+ return VTAP_TUNNEL_GRE;
+ case VXLAN:
+ return VTAP_TUNNEL_VXLAN;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Obtains tunnel description type from the given openstack vtap network mode.
+ *
+ * @param mode vtap network mode
+ * @return tunnel description type
+ */
+ public static TunnelDescription.Type getTunnelType(OpenstackVtapNetwork.Mode mode) {
+ return TunnelDescription.Type.valueOf(mode.toString());
+ }
+
+ /**
+ * Print stack trace of given exception.
+ *
+ * @param log logger for using print
+ * @param e exception to print
+ */
+ public static void dumpStackTrace(Logger log, Exception e) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ e.printStackTrace(new PrintStream(outputStream));
+ log.error("\n{}", new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
+ }
+
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java
index 905d1c4..b9a3906 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/util/package-info.java
@@ -15,6 +15,6 @@
*/
/**
- * Openstack vTap utility package.
+ * Utility package that used in openstack vtap app.
*/
package org.onosproject.openstackvtap.util;
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkCodecRegister.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkCodecRegister.java
new file mode 100644
index 0000000..7ac689a
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkCodecRegister.java
@@ -0,0 +1,53 @@
+/*
+ * 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.web;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.codec.CodecService;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.openstackvtap.codec.OpenstackVtapNetworkCodec;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the JSON codec brokering service for openstack vtap network.
+ */
+@Component(immediate = true)
+public class OpenstackVtapNetworkCodecRegister {
+
+ private final org.slf4j.Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CodecService codecService;
+
+ @Activate
+ protected void activate() {
+ codecService.registerCodec(OpenstackVtapNetwork.class, new OpenstackVtapNetworkCodec());
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ codecService.unregisterCodec(OpenstackVtapNetwork.class);
+
+ log.info("Stopped");
+ }
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkWebResource.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkWebResource.java
new file mode 100644
index 0000000..3900bbd
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapNetworkWebResource.java
@@ -0,0 +1,165 @@
+/*
+ * 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.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.openstackvtap.api.OpenstackVtapAdminService;
+import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+import static org.onlab.util.Tools.readTreeFromStream;
+
+/**
+ * Handles REST API call of openstack vtap network.
+ */
+@Path("vtap-network")
+public class OpenstackVtapNetworkWebResource extends AbstractWebResource {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String MESSAGE_NETWORK = "Received openstackVtapNetwork {} request";
+ private static final String ERROR_DUPLICATE = "Already has data {}";
+ private static final String ERROR_NOTFOUND = "No data to update {}";
+ private static final String CREATE = "CREATE";
+ private static final String READ = "READ";
+ private static final String UPDATE = "UPDATE";
+ private static final String DELETE = "DELETE";
+
+ private static final String NETWORK = "network";
+
+ private final OpenstackVtapAdminService vtapAdminService = get(OpenstackVtapAdminService.class);
+
+ /**
+ * Creates a openstack vtap network from the JSON input stream.
+ *
+ * @param input openstack vtap network JSON input stream
+ * @return 200 OK if the JSON is correct
+ * 400 BAD_REQUEST if the JSON is malformed
+ * 409 CONFLICT if already the vtap network exists
+ * @onos.rsModel OpenstackVtapNetwork
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response createNetwork(InputStream input) {
+ log.info(MESSAGE_NETWORK, CREATE);
+
+ OpenstackVtapNetwork vtapNetwork = readNetworkConfiguration(input);
+ if (vtapNetwork == null) {
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
+
+ if (vtapAdminService.createVtapNetwork(vtapNetwork.mode(),
+ vtapNetwork.networkId(), vtapNetwork.serverIp()) == null) {
+ log.warn(ERROR_DUPLICATE, vtapNetwork);
+ return Response.status(Response.Status.CONFLICT).build();
+ }
+ return Response.ok().build();
+ }
+
+ /**
+ * Updates openstack vtap network from the JSON input stream.
+ *
+ * @param input openstack vtap network JSON input stream
+ * @return 200 OK if the JSON is correct
+ * 400 BAD_REQUEST if the JSON is malformed
+ * 404 NOT_FOUND if vtap network is not exists
+ * @onos.rsModel OpenstackVtapNetwork
+ */
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response updateNetwork(InputStream input) {
+ log.info(MESSAGE_NETWORK, UPDATE);
+
+ OpenstackVtapNetwork vtapNetwork = readNetworkConfiguration(input);
+ if (vtapNetwork == null) {
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
+
+ if (vtapAdminService.updateVtapNetwork(vtapNetwork) == null) {
+ log.warn(ERROR_NOTFOUND, vtapNetwork);
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+ return Response.ok().build();
+ }
+
+ /**
+ * Get openstack vtap network.
+ *
+ * @return 200 OK with openstack vtap network
+ * 404 NOT_FOUND if openstackvtap network is not exists
+ * @onos.rsModel OpenstackVtapNetwork
+ */
+ @GET
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getNetwork() {
+ log.info(MESSAGE_NETWORK, READ);
+
+ OpenstackVtapNetwork vtapNetwork = vtapAdminService.getVtapNetwork();
+ if (vtapNetwork == null) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ JsonNode jsonNode = codec(OpenstackVtapNetwork.class).encode(vtapNetwork, this);
+ return Response.ok(jsonNode, MediaType.APPLICATION_JSON_TYPE).build();
+ }
+
+ /**
+ * Removes openstack network.
+ *
+ * @return 200 OK on removing success
+ * 404 NOT_FOUND if openstackvtap network is not exists
+ * @onos.rsModel OpenstackVtapNetwork
+ */
+ @DELETE
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response deleteNetwork() {
+ log.info(MESSAGE_NETWORK, DELETE);
+
+ if (vtapAdminService.removeVtapNetwork() == null) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ return Response.ok().build();
+ }
+
+ private OpenstackVtapNetwork readNetworkConfiguration(InputStream input) {
+ try {
+ JsonNode jsonTree = readTreeFromStream(mapper().enable(INDENT_OUTPUT), input);
+ ObjectNode vtap = (ObjectNode) jsonTree.get(NETWORK);
+ return codec(OpenstackVtapNetwork.class).decode(vtap, this);
+ } catch (Exception e) {
+ log.error(e.toString());
+ return null;
+ }
+ }
+
+}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java
index 5d0caf2..96aa9a7 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebApplication.java
@@ -20,11 +20,12 @@
import java.util.Set;
/**
- * Openstack vTap REST APIs web application.
+ * Openstack vtap REST APIs web application.
*/
public class OpenstackVtapWebApplication extends AbstractWebApplication {
@Override
public Set<Class<?>> getClasses() {
- return getClasses(OpenstackVtapWebResource.class);
+ return getClasses(OpenstackVtapWebResource.class,
+ OpenstackVtapNetworkWebResource.class);
}
}
diff --git a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java
index 89468ac..f4c3084 100644
--- a/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java
+++ b/apps/openstackvtap/app/src/main/java/org/onosproject/openstackvtap/web/OpenstackVtapWebResource.java
@@ -36,8 +36,6 @@
* OpenstackVtapServiceImpl method.
*
* @return 200 OK
- *
- * @onos.rsModel dummy
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
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
index c3fa886..7fd8ccf 100644
--- 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
@@ -42,7 +42,7 @@
</command>
<command>
- <action class="org.onosproject.openstackvtap.cli.OpenstackVtapOutputCommand" />
+ <action class="org.onosproject.openstackvtap.cli.OpenstackVtapNetworkListCommand" />
</command>
</command-bundle>
diff --git a/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.css b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.css
new file mode 100644
index 0000000..2595410
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.css
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- OpenstackVtap -- CSS file
+ */
+
+/* --- Topo Vtap Panel --- */
+#topo-p-vtap {
+ padding: 16px;
+ top: 190px;
+ left: 20px;
+}
+
+.topo-p td input.number-input {
+ width: 50px;
+}
+
+.topo-p div.footer tbody {
+ float: right;
+}
+
+.topo-p div.footer tbody input.button-input {
+ background-color: #5b99d2;
+ border: 0;
+ border-radius: 3px;
+ color: #fff;
+ height: 25px;
+ width: 60px;
+ padding: 1px 0 0 0;
+}
+
+#vtap-dialog {
+ padding: 16px;
+ top: 190px;
+ left: 20px;
+}
diff --git a/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.html b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.html
new file mode 100644
index 0000000..f1a1b72
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.html
@@ -0,0 +1,4 @@
+<!-- partial HTML -->
+<div id="ov-openstackvtap">
+ <p>This is a hidden view .. just a placeholder to house the javascript</p>
+</div>
diff --git a/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.js b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.js
new file mode 100644
index 0000000..9b20eb0
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/app/view/openstackvtap/openstackvtap.js
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Openstack Vtap View Module
+ */
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, tov, ovts, fs, wss, tts, api, gs, ps, ds;
+
+ // constants
+ var pCls = 'topo-p',
+ idVta = 'topo-p-vtap',
+ idVDi = 'vtap-dialog',
+ vtapPanelOpts = {
+ edge: 'left',
+ width: 330, // vtap panel width
+ }
+
+ // panels
+ var vtap;
+
+ // selected info
+ var selectedItem;
+
+ // constants
+ var osvIsActReq = 'openstackVtapIsActivatedRequest',
+ osvIsActResp = 'openstackVtapIsActivatedResponse',
+ osvCreateReq = 'openstackVtapCreateRequest',
+ osvCreateResp = 'openstackVtapCreateResponse';
+
+ // function to be replaced by the localization bundle function
+ var topoLion = function (x) {
+ return '#ttrafov#' + x + '#';
+ };
+
+ var overlay = {
+ overlayId: 'vtap-overlay',
+ glyphId: 'm_details',
+ tooltip: 'Openstack Vtap Overlay',
+
+ activate: function () {
+ $log.debug("Openstack Vtap topology overlay ACTIVATED");
+ },
+ deactivate: function () {
+ destroyVtapPanel();
+ $log.debug("Openstack Vtap topology overlay DEACTIVATED");
+ },
+
+ // detail panel button definitions
+ buttons: {
+ createHostVtapBtn: {
+ gid: 'm_details',
+ tt: 'Create Host-to-Host Vtap',
+ cb: displayVtap
+ },
+ showRelatedTraffic: {
+ gid: 'm_relatedIntents',
+ tt: function () { return topoLion('tr_btn_show_related_traffic'); },
+ cb: function (data) { tts.showRelatedIntents(); },
+ },
+ },
+
+ hooks: {
+ multi: function (selectOrder) {
+ var selectedHost = new Object();
+ for (var index in selectOrder) {
+ if (index == 0) {
+ selectedHost.src = selectOrder[index];
+ } else if (index == 1) {
+ selectedHost.dst = selectOrder[index];
+ }
+ }
+
+ selectedItem = selectedHost;
+
+ tov.addDetailButton('showRelatedTraffic');
+ if(selectOrder.length == 2) {
+ tov.addDetailButton('createHostVtapBtn');
+ }
+ }
+ }
+ };
+
+ // Panel API
+ function createTopoPanel(id, opts) {
+ var p = ps.createPanel(id, opts),
+ pid = id,
+ header, body, footer;
+ p.classed(pCls, true);
+
+ function panel() {
+ return p;
+ }
+
+ function hAppend(x) {
+ return header.append(x);
+ }
+
+ function bAppend(x) {
+ return body.append(x);
+ }
+
+ function fAppend(x) {
+ return footer.append(x);
+ }
+
+ function setup() {
+ p.empty();
+
+ p.append('div').classed('header', true);
+ p.append('div').classed('body', true);
+ p.append('div').classed('footer', true);
+
+ header = p.el().select('.header');
+ body = p.el().select('.body');
+ footer = p.el().select('.footer');
+ }
+
+ function destroy() {
+ ps.destroyPanel(pid);
+ }
+
+ return {
+ panel: panel,
+ setup: setup,
+ destroy: destroy,
+ appendHeader: hAppend,
+ appendBody: bAppend,
+ appendFooter: fAppend,
+ };
+ }
+
+ function hideVtapPanel() {
+ vtap.panel().hide();
+ }
+
+ function destroyVtapPanel() {
+ if(vtap != null) {
+ vtap.destroy();
+ }
+ vtap = null;
+ }
+
+ function addInput(tbody, type, id, label, value) {
+ var tr = tbody.append('tr'),
+ lab;
+ if (typeof label === 'string') {
+ lab = label.replace(/_/g, ' ');
+ } else {
+ lab = label;
+ }
+
+ tr.append('td').attr('class', 'label').text(lab + ' :');
+
+ if (type == 'radio') {
+ var td = tr.append('td');
+ for(var index in value) {
+ if(index == 0) {
+ td.append('input').classed( type + '-input', true)
+ .attr('type', type)
+ .attr('value', value[index])
+ .attr('name', label)
+ .attr('id', id)
+ .attr('checked', 'true');
+ } else {
+ td.append('input').classed( type + '-input', true)
+ .attr('type', type)
+ .attr('name', label)
+ .attr('id', id)
+ .attr('value', value[index]);
+ }
+ td.append('span').text(value[index]);
+ }
+ } else {
+ tr.append('td').append('input').classed(type + '-input', true).attr('type', type)
+ .attr('id', id).attr('value', value);
+ }
+ }
+
+ function addButton(tr, callback, value) {
+ tr.append('td').append('input').classed('button-input', true).attr('type', 'button')
+ .attr('value', value).on('click', callback);
+ }
+
+ function makeButton(callback, text, keyName) {
+ var cb = fs.isF(callback),
+ key = fs.isS(keyName);
+
+ function invoke() {
+ cb && cb();
+ }
+
+ return createDiv('vtap-button')
+ .text(text)
+ .on('click', invoke);
+ }
+
+ function createDiv(cls) {
+ var div = d3.select(document.createElement('div'));
+ if (cls) {
+ div.classed(cls, true);
+ }
+ return div;
+ }
+
+ function addInput(tbody, type, id, label, value) {
+ var tr = tbody.append('tr'),
+ lab;
+ if (typeof label === 'string') {
+ lab = label.replace(/_/g, ' ');
+ } else {
+ lab = label;
+ }
+
+ tr.append('td').attr('class', 'label').text(lab + ' :');
+
+ if (type == 'radio') {
+ var td = tr.append('td');
+ for(var index in value) {
+ if(index == 0) {
+ td.append('input').classed( type + '-input', true)
+ .attr('type', type)
+ .attr('value', value[index])
+ .attr('name', label)
+ .attr('id', id)
+ .attr('checked', 'true');
+ } else {
+ td.append('input').classed( type + '-input', true)
+ .attr('type', type)
+ .attr('name', label)
+ .attr('id', id)
+ .attr('value', value[index]);
+ }
+ td.append('span').text(value[index]);
+ }
+ } else {
+ tr.append('td').append('input').classed(type + '-input', true).attr('type', type)
+ .attr('id', id).attr('value', value);
+ }
+ }
+
+ function addButton(tr, callback, value) {
+ tr.append('td').append('input').classed('button-input', true).attr('type', 'button')
+ .attr('value', value).on('click', callback);
+ }
+
+ function makeButton(callback, text, keyName) {
+ var cb = fs.isF(callback),
+ key = fs.isS(keyName);
+
+ function invoke() {
+ cb && cb();
+ }
+
+ return createDiv('vtap-button')
+ .text(text)
+ .on('click', invoke);
+ }
+
+ function createDiv(cls) {
+ var div = d3.select(document.createElement('div'));
+ if (cls) {
+ div.classed(cls, true);
+ }
+ return div;
+ }
+
+ function displayVtap() {
+ $log.debug("sendEvent openstackVtapIsActivatedRequest: ", selectedItem);
+ wss.sendEvent(osvIsActReq, selectedItem);
+ }
+
+ function respIsActCb(selected) {
+ $log.debug("openstackVtapIsActivatedResponse: ", selected);
+ if(vtap == null) {
+ vtap = createTopoPanel(idVta, vtapPanelOpts);
+ }
+ vtap.setup();
+
+ var svg = vtap.appendHeader('div')
+ .classed('icon', true)
+ .append('svg'),
+ title = vtap.appendHeader('h2'),
+ table = vtap.appendBody('table'),
+ tbody = table.append('tbody'),
+ glyphId = 'm_details';
+
+ gs.addGlyph(svg, glyphId, 30, 0, [1, 1]);
+
+ title.text('Create OpenstackVtap');
+
+ addInput(tbody, 'text', 'srcIp', 'Source IP', selected.srcName);
+ addInput(tbody, 'text', 'dstIp', 'Destination IP', selected.dstName);
+ addInput(tbody, 'radio', 'ipProto', 'Protocol', selected.ipProtoList);
+ addInput(tbody, 'number', 'srcPort', 'Source Port', "");
+ addInput(tbody, 'number', 'dstPort', 'Destination Port', "");
+ addInput(tbody, 'radio', 'vtapType', 'Type', selected.vtapTypeList);
+
+ vtap.appendFooter('hr');
+ var footTr = vtap.appendFooter('table').append('tbody').append('tr');
+
+ addButton(footTr, createVtap, 'Create');
+ addButton(footTr, hideVtapPanel, 'Cancel');
+
+ vtap.panel().show();
+ }
+
+ function createVtap() {
+ var vtapInfo = {};
+
+ vtapInfo.srcIp = document.getElementById('srcIp').value;
+ vtapInfo.dstIp = document.getElementById('dstIp').value;
+ vtapInfo.ipProto = document.querySelector('input[name="Protocol"]:checked').value;
+ vtapInfo.srcPort = document.getElementById('srcPort').value;
+ vtapInfo.dstPort = document.getElementById('dstPort').value;
+ vtapInfo.vtapType = document.querySelector('input[name="Type"]:checked').value;
+
+ if(vtapInfo.srcPort == ""){
+ vtapInfo.srcPort = 0;
+ }
+ if(vtapInfo.dstPort == ""){
+ vtapInfo.dstPort = 0;
+ }
+
+ $log.debug("sendEvent openstackVtapCreateRequest: ", vtapInfo);
+ wss.sendEvent(osvCreateReq, vtapInfo);
+ hideVtapPanel();
+
+ }
+
+ function respCreateCb(result) {
+ $log.debug("respCreateCb: ", result);
+
+ function dOK() {
+ if(result.result == "Failed"){
+ displayVtap(selectedItem);
+ } else {
+ destroyVtapPanel();
+ }
+ }
+
+ function createContent(value) {
+ var content = ds.createDiv();
+ content.append('p').text(value);
+ return content;
+ }
+
+ ds.openDialog(idVDi, vtapPanelOpts)
+ .setTitle("Create Vtap " + result.result)
+ .addContent(createContent(result.value))
+ .addOk(dOK);
+ }
+
+ // invoke code to register with the overlay service
+ angular.module('ovOpenstackvtap', [])
+ .factory('OpenstackVtapTopovService',
+ ['$log', 'FnService', 'WebSocketService', 'GlyphService', 'PanelService', 'DialogService',
+
+ function (_$log_, _fs_, _wss_, _gs_, _ps_, _ds_) {
+ $log = _$log_;
+ fs = _fs_;
+ wss = _wss_;
+ gs = _gs_;
+ ps = _ps_;
+ ds = _ds_;
+
+ var handlers = {},
+ vtapOverlay = 'vtap-overlay',
+ defaultOverlay = 'traffic';
+
+ handlers[osvIsActResp] = respIsActCb;
+ handlers[osvCreateResp] = respCreateCb;
+
+ wss.bindHandlers(handlers);
+
+ return {
+ displayVtap: displayVtap
+ };
+ }])
+ .run(['$log', 'TopoOverlayService', 'OpenstackVtapTopovService', 'TopoTrafficService',
+
+ function (_$log_, _tov_, _ovts_, _tts_) {
+ $log = _$log_;
+ tov = _tov_;
+ ovts = _ovts_;
+ tts = _tts_;
+ tov.register(overlay);
+ }]
+ );
+}());
diff --git a/apps/openstackvtap/app/src/main/resources/definitions/OpenstackVtapNetwork.json b/apps/openstackvtap/app/src/main/resources/definitions/OpenstackVtapNetwork.json
new file mode 100644
index 0000000..32fa001
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/definitions/OpenstackVtapNetwork.json
@@ -0,0 +1,30 @@
+{
+ "type": "object",
+ "required": [
+ "network"
+ ],
+ "properties": {
+ "network": {
+ "type": "object",
+ "required": [
+ "mode",
+ "networkId",
+ "serverIp"
+ ],
+ "properties": {
+ "mode": {
+ "type": "string",
+ "example": "GRE"
+ },
+ "networkId": {
+ "type": "int",
+ "example": 1000
+ },
+ "serverIp": {
+ "type": "string",
+ "example": "10.20.0.1"
+ }
+ }
+ }
+ }
+}
diff --git a/apps/openstackvtap/app/src/main/resources/definitions/dummy.json b/apps/openstackvtap/app/src/main/resources/definitions/dummy.json
deleted file mode 100644
index 7a73a41..0000000
--- a/apps/openstackvtap/app/src/main/resources/definitions/dummy.json
+++ /dev/null
@@ -1,2 +0,0 @@
-{
-}
\ No newline at end of file
diff --git a/apps/openstackvtap/app/src/main/resources/gui/css.html b/apps/openstackvtap/app/src/main/resources/gui/css.html
new file mode 100644
index 0000000..9c1889b
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/gui/css.html
@@ -0,0 +1 @@
+<link rel="stylesheet" href="app/view/openstackvtap/openstackvtap.css">
diff --git a/apps/openstackvtap/app/src/main/resources/gui/js.html b/apps/openstackvtap/app/src/main/resources/gui/js.html
new file mode 100644
index 0000000..46a4bb4
--- /dev/null
+++ b/apps/openstackvtap/app/src/main/resources/gui/js.html
@@ -0,0 +1 @@
+<script src="app/view/openstackvtap/openstackvtap.js"></script>
diff --git a/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml b/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
index 8b44537..109fbe7 100644
--- a/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/openstackvtap/app/src/main/webapp/WEB-INF/web.xml
@@ -18,7 +18,7 @@
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="ONOS" version="2.5">
- <display-name>Openstack vTap REST API v1.0</display-name>
+ <display-name>Openstack Vtap REST API v1.0</display-name>
<security-constraint>
<web-resource-collection>
diff --git a/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java b/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java
index fd9fbf5..412d1d6 100644
--- a/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java
+++ b/apps/openstackvtap/app/src/test/java/org/onosproject/openstackvtap/impl/DefaultOpenstackVtapTest.java
@@ -34,8 +34,8 @@
*/
public class DefaultOpenstackVtapTest {
- private static final OpenstackVtapId VTAP_ID_1 = OpenstackVtapId.vTapId();
- private static final OpenstackVtapId VTAP_ID_2 = OpenstackVtapId.vTapId();
+ private static final OpenstackVtapId VTAP_ID_1 = OpenstackVtapId.vtapId();
+ private static final OpenstackVtapId VTAP_ID_2 = OpenstackVtapId.vtapId();
private static final OpenstackVtap.Type VTAP_TYPE_1 = OpenstackVtap.Type.VTAP_TX;
private static final OpenstackVtap.Type VTAP_TYPE_2 = OpenstackVtap.Type.VTAP_RX;
@@ -74,10 +74,9 @@
vtap1 = builder1
.id(VTAP_ID_1)
.type(VTAP_TYPE_1)
- .vTapCriterion(CRITERION_1)
+ .vtapCriterion(CRITERION_1)
.txDeviceIds(Sets.newHashSet())
.rxDeviceIds(Sets.newHashSet())
- .annotations()
.build();
OpenstackVtap.Builder builder2 = DefaultOpenstackVtap.builder();
@@ -85,10 +84,9 @@
sameAsVtap1 = builder2
.id(VTAP_ID_1)
.type(VTAP_TYPE_1)
- .vTapCriterion(CRITERION_1)
+ .vtapCriterion(CRITERION_1)
.txDeviceIds(Sets.newHashSet())
.rxDeviceIds(Sets.newHashSet())
- .annotations()
.build();
OpenstackVtap.Builder builder3 = DefaultOpenstackVtap.builder();
@@ -96,10 +94,9 @@
vtap2 = builder3
.id(VTAP_ID_2)
.type(VTAP_TYPE_2)
- .vTapCriterion(CRITERION_2)
+ .vtapCriterion(CRITERION_2)
.txDeviceIds(Sets.newHashSet())
.rxDeviceIds(Sets.newHashSet())
- .annotations()
.build();
}
@@ -116,7 +113,7 @@
DefaultOpenstackVtap vtap = (DefaultOpenstackVtap) vtap1;
assertThat(vtap.id(), is(VTAP_ID_1));
- assertThat(vtap.vTapCriterion(), is(CRITERION_1));
+ assertThat(vtap.vtapCriterion(), is(CRITERION_1));
assertThat(vtap.type(), is(VTAP_TYPE_1));
}