CORD-176, CORD-431 Switch to new VTN API
- Implemented VTN store and manager to keep network states
- Implemented the new VTN API for service network and port
Change-Id: Id8f5d0e609fa3deba782ff2265fc0d3175cbcb4c
diff --git a/pom.xml b/pom.xml
index 517b5a8..de815af 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,7 +43,6 @@
org.onosproject.ovsdb-base,
org.onosproject.drivers.ovsdb,
org.onosproject.dhcp,
- org.onosproject.xosclient,
org.opencord.config
</onos.app.requires>
<web.context>/onos/cordvtn</web.context>
@@ -128,14 +127,24 @@
<version>0.1.53</version>
</dependency>
<dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-apps-xosclient</artifactId>
- <version>${onos.version}</version>
- </dependency>
- <dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.pacesys</groupId>
+ <artifactId>openstack4j-core</artifactId>
+ <version>2.11</version>
+ </dependency>
+ <dependency>
+ <groupId>org.pacesys.openstack4j.connectors</groupId>
+ <artifactId>openstack4j-http-connector</artifactId>
+ <version>2.11</version>
+ </dependency>
+ <dependency>
+ <groupId>org.pacesys.openstack4j.connectors</groupId>
+ <artifactId>openstack4j-httpclient</artifactId>
+ <version>2.11</version>
+ </dependency>
<!-- TODO FIX ONOS ROOT POM to split thirdparty and onos dependencies -->
<dependency>
@@ -216,8 +225,16 @@
${project.groupId}.${project.artifactId}
</Bundle-SymbolicName>
<Import-Package>
+ !org.apache.http.*,
+ !com.fasterxml.jackson.dataformat.*,
+ !javax.annotation,
*,org.glassfish.jersey.servlet
</Import-Package>
+ <Embed-Dependency>
+ openstack4j-core,
+ openstack4j-http-connector,
+ openstack4j-httpclient
+ </Embed-Dependency>
<Web-ContextPath>${web.context}</Web-ContextPath>
</instructions>
</configuration>
diff --git a/src/main/java/org/opencord/cordvtn/api/CordVtnAdminService.java b/src/main/java/org/opencord/cordvtn/api/CordVtnAdminService.java
new file mode 100644
index 0000000..afb2a1e
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/CordVtnAdminService.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Subnet;
+
+/**
+ * Service for administering the inventory of virtual network and service network.
+ */
+public interface CordVtnAdminService extends CordVtnService {
+
+ /**
+ * Creates vtn port with given service port information.
+ *
+ * @param servicePort the new service port
+ */
+ void createVtnPort(ServicePort servicePort);
+
+ /**
+ * Updates vtn port with given service port information.
+ *
+ * @param servicePort the updated service port
+ */
+ void updateVtnPort(ServicePort servicePort);
+
+ /**
+ * Removes vtn port with given port id.
+ *
+ * @param portId port id
+ */
+ void removeVtnPort(PortId portId);
+
+ /**
+ * Creates vtn network with given service network information.
+ *
+ * @param serviceNet the new service network
+ */
+ void createVtnNetwork(ServiceNetwork serviceNet);
+
+ /**
+ * Updates the vtn network with given service network information.
+ *
+ * @param serviceNet the updated service network
+ */
+ void updateVtnNetwork(ServiceNetwork serviceNet);
+
+ /**
+ * Removes the vtn network.
+ *
+ * @param netId network id
+ */
+ void removeVtnNetwork(NetworkId netId);
+
+ /**
+ * Creates a port.
+ *
+ * @param port port
+ */
+ void createPort(Port port);
+
+ /**
+ * Updates the port.
+ *
+ * @param port the updated port
+ */
+ void updatePort(Port port);
+
+ /**
+ * Removes the port with the given port id.
+ *
+ * @param portId port id
+ */
+ void removePort(PortId portId);
+
+ /**
+ * Creates a network.
+ *
+ * @param network network
+ */
+ void createNetwork(Network network);
+
+ /**
+ * Updates the network.
+ *
+ * @param network the updated network
+ */
+ void updateNetwork(Network network);
+
+ /**
+ * Removes the network with the given network id.
+ *
+ * @param netId network id
+ */
+ void removeNetwork(NetworkId netId);
+
+ /**
+ * Creates a subnet.
+ *
+ * @param subnet subnet id
+ */
+ void createSubnet(Subnet subnet);
+
+ /**
+ * Updates the subnet.
+ *
+ * @param subnet the updated subnet
+ */
+ void updateSubnet(Subnet subnet);
+
+ /**
+ * Removes the subnet with the given subnet id.
+ *
+ * @param subnetId subnet id
+ */
+ void removeSubnet(SubnetId subnetId);
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java b/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java
index 41e869d..d0a9562 100644
--- a/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java
+++ b/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java
@@ -25,8 +25,6 @@
import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.config.Config;
-import org.onosproject.xosclient.api.OpenStackAccess;
-import org.onosproject.xosclient.api.XosAccess;
import org.slf4j.Logger;
import java.util.Map;
@@ -236,28 +234,5 @@
return publicGateways;
}
- /**
- * Returns XOS access information.
- *
- * @return XOS access, or null
- */
- public XosAccess xosAccess() {
- JsonNode jsonNode = object.get(XOS);
- return new XosAccess(getConfig(jsonNode, ENDPOINT),
- getConfig(jsonNode, USER),
- getConfig(jsonNode, PASSWORD));
- }
-
- /**
- * Returns OpenStack API access information.
- *
- * @return openstack access
- */
- public OpenStackAccess openstackAccess() {
- JsonNode jsonNode = object.get(OPENSTACK);
- return new OpenStackAccess(jsonNode.path(ENDPOINT).asText(),
- jsonNode.path(TENANT).asText(),
- jsonNode.path(USER).asText(),
- jsonNode.path(PASSWORD).asText());
- }
+ // TODO add methods to get XOS and OpenStack API access
}
diff --git a/src/main/java/org/opencord/cordvtn/api/CordVtnService.java b/src/main/java/org/opencord/cordvtn/api/CordVtnService.java
new file mode 100644
index 0000000..5b0849e
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/CordVtnService.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import org.onosproject.event.ListenerService;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Subnet;
+
+import java.util.Set;
+
+/**
+ * Service for interacting with the inventory of VTN network and port.
+ */
+public interface CordVtnService
+ extends ListenerService<VtnNetworkEvent, VtnNetworkListener> {
+
+ /**
+ * Returns the service port with the given port id.
+ *
+ * @param portId port id
+ * @return service port
+ */
+ VtnPort getVtnPort(PortId portId);
+
+ /**
+ * Returns the vtn port with the given port id. It returns the VTN port with
+ * the default settings if no service port exists for the port.
+ *
+ * @param portId port id
+ * @return vtn port for the port, of the default vtn port if no service port
+ * exists for the port
+ */
+ VtnPort getVtnPortOrDefault(PortId portId);
+
+ /**
+ * Returns the VTN port with the given port name.
+ *
+ * @param portName port name
+ * @return vtn port
+ */
+ VtnPort getVtnPort(String portName);
+
+ /**
+ * Returns all service ports.
+ *
+ * @return set of service ports
+ */
+ Set<VtnPort> getVtnPorts();
+
+ /**
+ * Returns the service network with the given network id.
+ *
+ * @param netId network id
+ * @return service network
+ */
+ VtnNetwork getVtnNetwork(NetworkId netId);
+
+ /**
+ * Returns the vtn network with the given network id. It returns the VTN
+ * network with default settings if no service network exists for the network.
+ *
+ * @param netId network id
+ * @return vtn network for the network id, or the default vtn network if no
+ * service network is created for the network
+ */
+ VtnNetwork getVtnNetworkOrDefault(NetworkId netId);
+
+ /**
+ * Returns all service networks.
+ *
+ * @return set of service networks
+ */
+ Set<VtnNetwork> getVtnNetworks();
+
+ /**
+ * Returns the port with the given port id.
+ *
+ * @param portId port id
+ * @return port
+ */
+ Port getPort(PortId portId);
+
+ /**
+ * Returns all ports.
+ *
+ * @return set of ports
+ */
+ Set<Port> getPorts();
+
+ /**
+ * Returns the network with the given network id.
+ *
+ * @param netId network id
+ * @return network
+ */
+ Network getNetwork(NetworkId netId);
+
+ /**
+ * Returns all networks.
+ *
+ * @return set of networks
+ */
+ Set<Network> getNetworks();
+
+ /**
+ * Returns the subnet with the given subnet id.
+ *
+ * @param subnetId subnet id
+ * @return subnet
+ */
+ Subnet getSubnet(SubnetId subnetId);
+
+ /**
+ * Returns all subnets.
+ *
+ * @return set of subnets
+ */
+ Set<Subnet> getSubnets();
+
+ /**
+ * Returns instance attached to the given port.
+ *
+ * @param portId port identifier
+ * @return instance, or null if no instance for the port
+ */
+ Instance getInstance(PortId portId);
+
+ /**
+ * Returns instances in the given network.
+ *
+ * @param netId network identifier
+ * @return set of instances, empty set if no instances in the network
+ */
+ Set<Instance> getInstances(NetworkId netId);
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/CordVtnStore.java b/src/main/java/org/opencord/cordvtn/api/CordVtnStore.java
index d6d7a9b..bfa84f7 100644
--- a/src/main/java/org/opencord/cordvtn/api/CordVtnStore.java
+++ b/src/main/java/org/opencord/cordvtn/api/CordVtnStore.java
@@ -15,77 +15,195 @@
*/
package org.opencord.cordvtn.api;
+import org.onosproject.store.Store;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Subnet;
+
import java.util.Set;
/**
- * Manages VTN service networks and ports.
+ * Manages inventory of virtual and vtn networks; not intended for direct use.
*/
-public interface CordVtnStore {
+public interface CordVtnStore extends Store<VtnNetworkEvent, CordVtnStoreDelegate> {
/**
- * Creates service network.
+ * Creates vtn network.
*
- * @param serviceNet the new service network
+ * @param serviceNet the new vtn network
*/
- void createServiceNetwork(ServiceNetwork serviceNet);
+ void createVtnNetwork(VtnNetwork serviceNet);
/**
- * Updates the service network.
+ * Updates the vtn network.
*
- * @param serviceNet the updated service network
+ * @param serviceNet the updated vtn network
*/
- void updateServiceNetwork(ServiceNetwork serviceNet);
+ void updateVtnNetwork(VtnNetwork serviceNet);
/**
- * Returns the service network with the given network id.
+ * Returns the vtn network with the given network id.
*
* @param netId network id
- * @return service network
+ * @return vtn network
*/
- ServiceNetwork getServiceNetwork(NetworkId netId);
+ VtnNetwork getVtnNetwork(NetworkId netId);
/**
- * Returns all service networks.
+ * Returns all vtn networks.
*
- * @return set of service networks
+ * @return set of vtn networks
*/
- Set<ServiceNetwork> getServiceNetworks();
+ Set<VtnNetwork> getVtnNetworks();
/**
- * Removes the service network.
+ * Removes the vtn network.
*
* @param netId network id
*/
- void removeServiceNetwork(NetworkId netId);
+ void removeVtnNetwork(NetworkId netId);
/**
- * Creates service port.
+ * Creates vtn port.
*
- * @param servicePort the new service port
+ * @param servicePort the new vtn port
*/
- void createServicePort(ServicePort servicePort);
+ void createVtnPort(VtnPort servicePort);
/**
- * Returns the service port with the given port id.
+ * Updates the vtn port.
+ *
+ * @param servicePort vtn port
+ */
+ void updateVtnPort(VtnPort servicePort);
+
+ /**
+ * Returns the vtn port with the given port id.
*
* @param portId port id
- * @return service port
+ * @return vtn port
*/
- ServicePort getServicePort(PortId portId);
+ VtnPort getVtnPort(PortId portId);
/**
- * Returns all service ports.
+ * Returns all vtn ports.
*
- * @return set of service ports
+ * @return set of vtn ports
*/
- Set<ServicePort> getServicePorts();
+ Set<VtnPort> getVtnPorts();
/**
- * Removes service port.
+ * Removes vtn port.
*
* @param portId port id
*/
- void removeServicePort(PortId portId);
+ void removeVtnPort(PortId portId);
- // TODO add apis for the virtual network and port
+ /**
+ * Creates a network.
+ *
+ * @param net network
+ */
+ void createNetwork(Network net);
+
+ /**
+ * Updates the network.
+ *
+ * @param net the updated network
+ */
+ void updateNetwork(Network net);
+
+ /**
+ * Returns the network with the given network id.
+ *
+ * @param netId network id
+ * @return network
+ */
+ Network getNetwork(NetworkId netId);
+
+ /**
+ * Returns all networks.
+ *
+ * @return set of networks
+ */
+ Set<Network> getNetworks();
+
+ /**
+ * Removes the network with the given network id.
+ *
+ * @param netId network id
+ */
+ void removeNetwork(NetworkId netId);
+
+ /**
+ * Creates a port.
+ *
+ * @param port port
+ */
+ void createPort(Port port);
+
+ /**
+ * Updates the port.
+ *
+ * @param port the updated port
+ */
+ void updatePort(Port port);
+
+ /**
+ * Returns the port with the given port id.
+ *
+ * @param portId port id
+ * @return port
+ */
+ Port getPort(PortId portId);
+
+ /**
+ * Returns all ports.
+ *
+ * @return set of ports
+ */
+ Set<Port> getPorts();
+
+ /**
+ * Removes the port with the given port id.
+ *
+ * @param portId port id
+ */
+ void removePort(PortId portId);
+
+ /**
+ * Creates a subnet.
+ *
+ * @param subnet subnet id
+ */
+ void createSubnet(Subnet subnet);
+
+ /**
+ * Updates the subnet.
+ *
+ * @param subnet the updated subnet
+ */
+ void updateSubnet(Subnet subnet);
+
+ /**
+ * Returns the subnet with the given subnet id.
+ *
+ * @param subnetId subnet id
+ * @return subnet
+ */
+ Subnet getSubnet(SubnetId subnetId);
+
+ /**
+ * Returns all subnets.
+ *
+ * @return set of subnets
+ */
+ Set<Subnet> getSubnets();
+
+ /**
+ * Removes the subnet with the given subnet id.
+ *
+ * @param subnetId subnet id
+ */
+ void removeSubnet(SubnetId subnetId);
}
diff --git a/src/main/java/org/opencord/cordvtn/api/CordVtnStoreDelegate.java b/src/main/java/org/opencord/cordvtn/api/CordVtnStoreDelegate.java
new file mode 100644
index 0000000..eb43f92
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/CordVtnStoreDelegate.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * VTN store delegate abstraction.
+ */
+public interface CordVtnStoreDelegate extends StoreDelegate<VtnNetworkEvent> {
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/Dependency.java b/src/main/java/org/opencord/cordvtn/api/Dependency.java
new file mode 100644
index 0000000..bbe7ef5
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/Dependency.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Representation of a dependency between two networks, subscriber and provider.
+ */
+public final class Dependency {
+
+ public enum Type {
+ BIDIRECTIONAL,
+ UNIDIRECTIONAL
+ }
+
+ private final VtnNetwork subscriber;
+ private final VtnNetwork provider;
+ private final Type type;
+
+ private Dependency(VtnNetwork subscriber, VtnNetwork provider, Type type) {
+ this.subscriber = subscriber;
+ this.provider = provider;
+ this.type = type;
+ }
+
+ /**
+ * Returns subscriber network.
+ *
+ * @return vtn network
+ */
+ public VtnNetwork subscriber() {
+ return subscriber;
+ }
+
+ /**
+ * Returns provider network.
+ *
+ * @return vtn network
+ */
+ public VtnNetwork provider() {
+ return provider;
+ }
+
+ /**
+ * Returns direct access type between subscriber and provider networks.
+ *
+ * @return type
+ */
+ public Type type() {
+ return type;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof Dependency) {
+ Dependency that = (Dependency) obj;
+ if (Objects.equals(subscriber, that.subscriber) &&
+ Objects.equals(provider, that.provider) &&
+ Objects.equals(type, that.type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(subscriber, provider, type);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("subscriber", subscriber.id())
+ .add("provider", provider.id())
+ .add("type", type)
+ .toString();
+ }
+
+ /**
+ * Returns new dependency builder instance.
+ *
+ * @return dependency
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of the dependency entities.
+ */
+ public static final class Builder {
+ private VtnNetwork subscriber;
+ private VtnNetwork provider;
+ private Type type;
+
+ private Builder() {
+ }
+
+ /**
+ * Builds an immutable dependency.
+ *
+ * @return dependency instance
+ */
+ public Dependency build() {
+ checkNotNull(subscriber);
+ checkNotNull(provider);
+ checkNotNull(type);
+
+ return new Dependency(subscriber, provider, type);
+ }
+
+ /**
+ * Returns dependency with the supplied subscriber.
+ *
+ * @param subscriber subscriber network
+ * @return dependency builder
+ */
+ public Builder subscriber(VtnNetwork subscriber) {
+ this.subscriber = subscriber;
+ return this;
+ }
+
+ /**
+ * Returns dependency with the supplied provider.
+ *
+ * @param provider provider network
+ * @return dependency builder
+ */
+ public Builder provider(VtnNetwork provider) {
+ this.provider = provider;
+ return this;
+ }
+
+ /**
+ * Returns dependency with the supplied type.
+ *
+ * @param type type
+ * @return dependency builder
+ */
+ public Builder type(Type type) {
+ this.type = type;
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/DependencyService.java b/src/main/java/org/opencord/cordvtn/api/DependencyService.java
index 48905da..08ad58d 100644
--- a/src/main/java/org/opencord/cordvtn/api/DependencyService.java
+++ b/src/main/java/org/opencord/cordvtn/api/DependencyService.java
@@ -15,7 +15,7 @@
*/
package org.opencord.cordvtn.api;
-import org.onosproject.xosclient.api.VtnServiceId;
+import org.opencord.cordvtn.api.Dependency.Type;
/**
* Provides dependency services.
@@ -25,17 +25,17 @@
/**
* Creates dependencies for a given tenant service.
*
- * @param tServiceId id of the service which has a dependency
- * @param pServiceId id of the service which provide dependency
- * @param isBidirectional true to enable bidirectional connectivity between two services
+ * @param subscriber subscriber network id
+ * @param provider provider network id
+ * @param type bidirectional access type
*/
- void createDependency(VtnServiceId tServiceId, VtnServiceId pServiceId, boolean isBidirectional);
+ void createDependency(NetworkId subscriber, NetworkId provider, Type type);
/**
* Removes all dependencies from a given tenant service.
*
- * @param tServiceId id of the service which has a dependency
- * @param pServiceId id of the service which provide dependency
+ * @param subscriber subscriber network id
+ * @param provider provider network id
*/
- void removeDependency(VtnServiceId tServiceId, VtnServiceId pServiceId);
+ void removeDependency(NetworkId subscriber, NetworkId provider);
}
diff --git a/src/main/java/org/opencord/cordvtn/api/Instance.java b/src/main/java/org/opencord/cordvtn/api/Instance.java
index 23841b6..d81440e 100644
--- a/src/main/java/org/opencord/cordvtn/api/Instance.java
+++ b/src/main/java/org/opencord/cordvtn/api/Instance.java
@@ -21,21 +21,19 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.PortNumber;
-import org.onosproject.xosclient.api.VtnPortId;
-import org.onosproject.xosclient.api.VtnServiceApi.ServiceType;
-import org.onosproject.xosclient.api.VtnServiceId;
+import org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
- * Provides methods to help to handle network service instance.
+ * Provides methods to help to handle network network instance.
*/
public final class Instance {
- public static final String SERVICE_ID = "serviceId";
- public static final String SERVICE_TYPE = "serviceType";
- public static final String PORT_ID = "vtnPortId";
+ public static final String NETWORK_ID = "networkId";
+ public static final String NETWORK_TYPE = "networkType";
+ public static final String PORT_ID = "portId";
public static final String CREATE_TIME = "createTime";
public static final String NESTED_INSTANCE = "nestedInstance";
public static final String TRUE = "true";
@@ -68,8 +66,8 @@
*/
public static Instance of(Host host) {
checkNotNull(host);
- checkArgument(!Strings.isNullOrEmpty(host.annotations().value(SERVICE_ID)));
- checkArgument(!Strings.isNullOrEmpty(host.annotations().value(SERVICE_TYPE)));
+ checkArgument(!Strings.isNullOrEmpty(host.annotations().value(NETWORK_ID)));
+ checkArgument(!Strings.isNullOrEmpty(host.annotations().value(NETWORK_TYPE)));
checkArgument(!Strings.isNullOrEmpty(host.annotations().value(PORT_ID)));
checkArgument(!Strings.isNullOrEmpty(host.annotations().value(CREATE_TIME)));
@@ -77,33 +75,33 @@
}
/**
- * Returns service ID of a given host.
+ * Returns network ID of a given host.
*
- * @return vtn service id
+ * @return network id
*/
- public VtnServiceId serviceId() {
- String serviceId = host.annotations().value(SERVICE_ID);
- return VtnServiceId.of(serviceId);
+ public NetworkId netId() {
+ String netId = host.annotations().value(NETWORK_ID);
+ return NetworkId.of(netId);
}
/**
- * Returns service type of a given host.
+ * Returns network type of a given host.
*
- * @return vtn service type
+ * @return network type
*/
- public ServiceType serviceType() {
- String serviceType = host.annotations().value(SERVICE_TYPE);
- return ServiceType.valueOf(serviceType);
+ public ServiceNetworkType netType() {
+ String netType = host.annotations().value(NETWORK_TYPE);
+ return ServiceNetworkType.valueOf(netType);
}
/**
* Returns port ID of a given host.
*
- * @return vtn port id
+ * @return port id
*/
- public VtnPortId portId() {
+ public PortId portId() {
String portId = host.annotations().value(PORT_ID);
- return VtnPortId.of(portId);
+ return PortId.of(portId);
}
/**
diff --git a/src/main/java/org/opencord/cordvtn/api/InstanceHandler.java b/src/main/java/org/opencord/cordvtn/api/InstanceHandler.java
index ea44857..a2364fd 100644
--- a/src/main/java/org/opencord/cordvtn/api/InstanceHandler.java
+++ b/src/main/java/org/opencord/cordvtn/api/InstanceHandler.java
@@ -28,6 +28,13 @@
void instanceDetected(Instance instance);
/**
+ * Handles updated instance.
+ *
+ * @param instance instance
+ */
+ void instanceUpdated(Instance instance);
+
+ /**
* Handles removed instance.
*
* @param instance instance
diff --git a/src/main/java/org/opencord/cordvtn/api/InstanceService.java b/src/main/java/org/opencord/cordvtn/api/InstanceService.java
index a8e0f77..add968f 100644
--- a/src/main/java/org/opencord/cordvtn/api/InstanceService.java
+++ b/src/main/java/org/opencord/cordvtn/api/InstanceService.java
@@ -25,7 +25,8 @@
public interface InstanceService {
/**
- * Adds a service instance on a given connect point.
+ * Adds a service instance on a given connect point. Or updates if the
+ * instance already exists.
*
* @param connectPoint connect point of the instance
*/
diff --git a/src/main/java/org/opencord/cordvtn/api/ProviderNetwork.java b/src/main/java/org/opencord/cordvtn/api/ProviderNetwork.java
new file mode 100644
index 0000000..9caabbd
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/ProviderNetwork.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import com.google.common.base.MoreObjects;
+import org.opencord.cordvtn.api.Dependency.Type;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Representation of a provider network.
+ */
+public final class ProviderNetwork {
+
+ private final NetworkId id;
+ private final Type type;
+
+ private ProviderNetwork(NetworkId id, Type type) {
+ this.id = id;
+ this.type = type;
+ }
+
+ /**
+ * Returns network id.
+ *
+ * @return network id
+ */
+ public NetworkId id() {
+ return id;
+ }
+
+ /**
+ * Returns the direct access type with this provider network.
+ *
+ * @return direct access type
+ */
+ public Type type() {
+ return type;
+ }
+
+ /**
+ * Returns immutable provider network with the supplied network id and type.
+ *
+ * @param id network id
+ * @param type direct access type
+ * @return provider network
+ */
+ public static ProviderNetwork of(NetworkId id, Type type) {
+ checkNotNull(id);
+ checkNotNull(type);
+ return new ProviderNetwork(id, type);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof ProviderNetwork) {
+ ProviderNetwork that = (ProviderNetwork) obj;
+ if (Objects.equals(id, that.id) &&
+ Objects.equals(type, that.type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, type);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("id", id)
+ .add("type", type)
+ .toString();
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/SegmentId.java b/src/main/java/org/opencord/cordvtn/api/SegmentId.java
new file mode 100644
index 0000000..e4101b3
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/SegmentId.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import org.onlab.util.Identifier;
+
+/**
+ * Representation of the network segmentation identifier.
+ */
+public final class SegmentId extends Identifier<Long> {
+
+ /**
+ * Default constructor.
+ *
+ * @param id long segmentation identifier
+ */
+ private SegmentId(Long id) {
+ super(id);
+ }
+
+ /**
+ * Returns the segmentation identifier with the supplied value.
+ *
+ * @param id long segmentation identifier
+ * @return segmentation identifier
+ */
+ public static SegmentId of(Long id) {
+ return new SegmentId(id);
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/ServiceNetwork.java b/src/main/java/org/opencord/cordvtn/api/ServiceNetwork.java
index bc639da..6da6833 100644
--- a/src/main/java/org/opencord/cordvtn/api/ServiceNetwork.java
+++ b/src/main/java/org/opencord/cordvtn/api/ServiceNetwork.java
@@ -16,18 +16,20 @@
package org.opencord.cordvtn.api;
import com.google.common.base.MoreObjects;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
+import com.google.common.collect.ImmutableSet;
-import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of a service network.
*/
-public final class ServiceNetwork {
+public class ServiceNetwork {
+
+ private static final String ERR_ID = "Service network ID cannot be null";
+ private static final String ERR_TYPE = "Service network type cannot be null";
public enum ServiceNetworkType {
PRIVATE,
@@ -38,21 +40,16 @@
ACCESS_AGENT
}
- public enum DirectAccessType {
- BIDIRECTIONAL,
- UNIDIRECTIONAL
- }
+ protected final NetworkId id;
+ protected final ServiceNetworkType type;
+ protected final Set<ProviderNetwork> providers;
- private final NetworkId id;
- private final ServiceNetworkType type;
- private final Map<NetworkId, DirectAccessType> providers;
-
- private ServiceNetwork(NetworkId id,
- ServiceNetworkType type,
- Map<NetworkId, DirectAccessType> providers) {
- this.id = id;
- this.type = type;
- this.providers = providers;
+ public ServiceNetwork(NetworkId id,
+ ServiceNetworkType type,
+ Set<ProviderNetwork> providers) {
+ this.id = checkNotNull(id, ERR_ID);
+ this.type = checkNotNull(type, ERR_TYPE);
+ this.providers = providers == null ? ImmutableSet.of() : providers;
}
/**
@@ -78,10 +75,21 @@
*
* @return provider networks
*/
- public Map<NetworkId, DirectAccessType> providers() {
+ public Set<ProviderNetwork> providers() {
return providers;
}
+ /**
+ * Returns if the given network is the provider of this network or not.
+ *
+ * @param netId network id
+ * @return true if the given network is the provider of this network
+ */
+ public boolean isProvider(NetworkId netId) {
+ return providers.stream().filter(p -> Objects.equals(p.id(), netId))
+ .findAny().isPresent();
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -112,86 +120,4 @@
.add("providers", providers)
.toString();
}
-
- /**
- * Returns new service network builder instance.
- *
- * @return service network builder
- */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Builder of the service network entities.
- */
- public static final class Builder {
- private NetworkId id;
- private ServiceNetworkType type;
- private Map<NetworkId, DirectAccessType> providers = Maps.newHashMap();
-
- private Builder() {
- }
-
- /**
- * Builds an immutable service network.
- *
- * @return service network instance
- */
- public ServiceNetwork build() {
- checkNotNull(id, "Service network id cannot be null");
- checkNotNull(type, "Service network type cannot be null");
- providers = providers == null ? ImmutableMap.of() : providers;
-
- return new ServiceNetwork(id, type, providers);
- }
-
- /**
- * Returns service network builder with the supplied network ID.
- *
- * @param id network id
- * @return service network builder
- */
- public Builder id(NetworkId id) {
- this.id = id;
- return this;
- }
-
- /**
- * Returns service network builder with the supplied service network type.
- *
- * @param type service network type
- * @return service network builder
- */
- public Builder type(ServiceNetworkType type) {
- this.type = type;
- return this;
- }
-
- /**
- * Returns service network builder with the supplied provider service networks.
- *
- * @param providers provider service networks
- * @return service network builder
- */
- public Builder providers(Map<NetworkId, DirectAccessType> providers) {
- this.providers = providers;
- return this;
- }
-
- /**
- * Returns service network builder with the given additional provider network.
- *
- * @param id provider network id
- * @param type direct access type to the provider network
- * @return service network builder
- */
- public Builder addProvider(NetworkId id, DirectAccessType type) {
- checkNotNull(id, "Provider network ID cannot be null");
- checkNotNull(type, "Provider network type cannot be null");
-
- this.providers.put(id, type);
- return this;
- }
- }
}
diff --git a/src/main/java/org/opencord/cordvtn/api/ServicePort.java b/src/main/java/org/opencord/cordvtn/api/ServicePort.java
index 61b0e52..3ed18ee 100644
--- a/src/main/java/org/opencord/cordvtn/api/ServicePort.java
+++ b/src/main/java/org/opencord/cordvtn/api/ServicePort.java
@@ -17,7 +17,6 @@
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
import org.onlab.packet.VlanId;
import java.util.Objects;
@@ -29,18 +28,20 @@
/**
* Representation of a service port.
*/
-public final class ServicePort {
+public class ServicePort {
- private final PortId id;
- private final VlanId vlanId;
- private final Set<AddressPair> addressPairs;
+ private static final String ERR_ID = "Service port ID cannot be null";
- private ServicePort(PortId id,
- VlanId vlanId,
- Set<AddressPair> addressPairs) {
- this.id = id;
+ protected final PortId id;
+ protected final VlanId vlanId;
+ protected final Set<AddressPair> addressPairs;
+
+ public ServicePort(PortId id,
+ VlanId vlanId,
+ Set<AddressPair> addressPairs) {
+ this.id = checkNotNull(id, ERR_ID);
this.vlanId = vlanId;
- this.addressPairs = addressPairs;
+ this.addressPairs = addressPairs == null ? ImmutableSet.of() : addressPairs;
}
/**
@@ -100,83 +101,4 @@
.add("addressPairs", addressPairs)
.toString();
}
-
- /**
- * Returns new service port builder instance.
- *
- * @return service port builder
- */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Builder of the service port entities.
- */
- public static final class Builder {
- private PortId id;
- private VlanId vlanId;
- private Set<AddressPair> addressPairs = Sets.newHashSet();
-
- private Builder() {
- }
-
- /**
- * Builds an immutable service port.
- *
- * @return service port instance
- */
- public ServicePort build() {
- checkNotNull(id, "ServicePort port id cannot be null");
- addressPairs = addressPairs == null ? ImmutableSet.of() : addressPairs;
-
- return new ServicePort(id, vlanId, addressPairs);
- }
-
- /**
- * Returns service port builder with the supplied port port id.
- *
- * @param id port id
- * @return service port builder
- */
- public Builder id(PortId id) {
- this.id = id;
- return this;
- }
-
- /**
- * Returns service port builder with the supplied VLAN ID.
- *
- * @param vlanId vlan id
- * @return service port builder
- */
- public Builder vlanId(VlanId vlanId) {
- this.vlanId = vlanId;
- return this;
- }
-
- /**
- * Returns service port builder with the supplied address pairs.
- *
- * @param addressPairs set of address pairs
- * @return service port builder
- */
- public Builder addressPairs(Set<AddressPair> addressPairs) {
- this.addressPairs = addressPairs;
- return this;
- }
-
- /**
- * Returns service port builder with the given additional address pair.
- *
- * @param addressPair address pair to add
- * @return service port builder
- */
- public Builder addAddressPair(AddressPair addressPair) {
- checkNotNull(addressPair, "ServicePort address pair cannot be null");
-
- this.addressPairs.add(addressPair);
- return this;
- }
- }
}
diff --git a/src/main/java/org/opencord/cordvtn/api/SubnetId.java b/src/main/java/org/opencord/cordvtn/api/SubnetId.java
new file mode 100644
index 0000000..e98ebd8
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/SubnetId.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import org.onlab.util.Identifier;
+
+/**
+ * Representation of the subnet identifier.
+ */
+public final class SubnetId extends Identifier<String> {
+
+ /**
+ * Default constructor.
+ *
+ * @param id string subnet identifier
+ */
+ private SubnetId(String id) {
+ super(id);
+ }
+
+ /**
+ * Returns the subnet identifier with the supplied value.
+ *
+ * @param id string subnet identifier
+ * @return subnet identifier
+ */
+ public static SubnetId of(String id) {
+ return new SubnetId(id);
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/VtnNetwork.java b/src/main/java/org/opencord/cordvtn/api/VtnNetwork.java
new file mode 100644
index 0000000..644a939
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/VtnNetwork.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Subnet;
+
+import java.util.Objects;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.PRIVATE;
+
+/**
+ * Representation of the network containing all network information consumed by
+ * VTN service.
+ */
+public final class VtnNetwork extends ServiceNetwork {
+
+ private static final String ERR_SEGMENT_ID_MISSING = "VTN network segment ID is missing";
+ private static final String ERR_GATEWAY_IP_MISSING = "VTN subnet gateway IP is missing";
+
+ private final SegmentId segmentId;
+ private final IpPrefix subnet;
+ private final IpAddress serviceIp;
+
+ private VtnNetwork(NetworkId id,
+ SegmentId segmentId,
+ IpPrefix subnet,
+ IpAddress serviceIp,
+ ServiceNetworkType type,
+ Set<ProviderNetwork> providers) {
+ super(id, type, providers);
+ this.segmentId = segmentId;
+ this.subnet = subnet;
+ this.serviceIp = serviceIp;
+ }
+
+ /**
+ * Returns the network ID.
+ *
+ * @return network id
+ */
+ public NetworkId id() {
+ return id;
+ }
+
+ /**
+ * Returns the segment ID of this network.
+ *
+ * @return segment id
+ */
+ public SegmentId segmentId() {
+ return segmentId;
+ }
+
+ /**
+ * Returns the subnet used in this network.
+ *
+ * @return subnet
+ */
+ public IpPrefix subnet() {
+ return subnet;
+ }
+
+ /**
+ * Returns the service IP address of this network.
+ *
+ * @return ip address
+ */
+ public IpAddress serviceIp() {
+ return serviceIp;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof VtnNetwork) {
+ VtnNetwork that = (VtnNetwork) obj;
+ if (Objects.equals(id, that.id) &&
+ Objects.equals(segmentId, that.segmentId) &&
+ Objects.equals(subnet, that.subnet) &&
+ Objects.equals(serviceIp, that.serviceIp) &&
+ Objects.equals(type, that.type) &&
+ Objects.equals(providers, that.providers)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, segmentId, subnet, serviceIp, type, providers);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("id", id)
+ .add("segmentId", segmentId)
+ .add("subnet", subnet)
+ .add("serviceIp", serviceIp)
+ .add("type", type)
+ .add("providers", providers)
+ .toString();
+ }
+
+ /**
+ * Returns immutable VTN network with the supplied Neutron network, subnet,
+ * and additional service network information.
+ *
+ * @param network neutron network
+ * @param subnet neutron subnet
+ * @param serviceNet service network
+ * @return vtn network
+ */
+ public static VtnNetwork of(Network network, Subnet subnet, ServiceNetwork serviceNet) {
+ validateNeutronNetwork(network, subnet);
+ if (serviceNet != null) {
+ checkArgument(Objects.equals(network.getId(), serviceNet.id().id()));
+ }
+
+ return builder().id(NetworkId.of(network.getId()))
+ .segmentId(SegmentId.of(Long.valueOf(network.getProviderSegID())))
+ .subnet(IpPrefix.valueOf(subnet.getCidr()))
+ .serviceIp(IpAddress.valueOf(subnet.getGateway()))
+ .type(serviceNet == null ? PRIVATE : serviceNet.type())
+ .providers(serviceNet == null ? ImmutableSet.of() : serviceNet.providers())
+ .build();
+ }
+
+ private static void validateNeutronNetwork(Network network, Subnet subnet) {
+ checkNotNull(network);
+ checkNotNull(subnet);
+ checkArgument(Objects.equals(network.getId(), subnet.getNetworkId()));
+ checkArgument(!Strings.isNullOrEmpty(network.getProviderSegID()), ERR_SEGMENT_ID_MISSING);
+ checkArgument(!Strings.isNullOrEmpty(subnet.getGateway()), ERR_GATEWAY_IP_MISSING);
+ }
+
+ /**
+ * Returns new vtn network builder instance.
+ *
+ * @return vtn network builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Returns new vtn network builder instance with copy of the given vtn network.
+ *
+ * @param vtnNet vtn network
+ * @return vtn network builder
+ */
+ public static Builder builder(VtnNetwork vtnNet) {
+ return new Builder()
+ .id(vtnNet.id())
+ .segmentId(vtnNet.segmentId())
+ .subnet(vtnNet.subnet())
+ .serviceIp(vtnNet.serviceIp())
+ .type(vtnNet.type())
+ .providers(vtnNet.providers());
+ }
+
+ /**
+ * Builder of the vtn network entities.
+ */
+ public static final class Builder {
+ private NetworkId id;
+ private SegmentId segmentId;
+ private IpPrefix subnet;
+ private IpAddress serviceIp;
+ private ServiceNetworkType type;
+ private Set<ProviderNetwork> providers = ImmutableSet.of();
+
+ private Builder() {
+ }
+
+ /**
+ * Builds an immutable vtn network.
+ *
+ * @return vtn network instance
+ */
+ public VtnNetwork build() {
+ checkNotNull(id, "VTN network id cannot be null");
+ checkNotNull(segmentId, "VTN network segment id cannot be null");
+ checkNotNull(subnet, "VTN network subnet cannot be null");
+ checkNotNull(serviceIp, "VTN network service IP cannot be null");
+ checkNotNull(type, "VTN network type cannot be null");
+ providers = providers == null ? ImmutableSet.of() : providers;
+
+ return new VtnNetwork(id, segmentId, subnet, serviceIp, type, providers);
+ }
+
+ /**
+ * Returns vtn network builder with the supplied network ID.
+ *
+ * @param id network id
+ * @return vtn network builder
+ */
+ public Builder id(NetworkId id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Returns vtn network builder with the supplied segment ID.
+ *
+ * @param segmentId segment id
+ * @return vtn network builder
+ */
+ public Builder segmentId(SegmentId segmentId) {
+ this.segmentId = segmentId;
+ return this;
+ }
+
+ /**
+ * Returns vtn network builder with the supplied subnet.
+ *
+ * @param subnet subnet
+ * @return vtn network builder
+ */
+ public Builder subnet(IpPrefix subnet) {
+ this.subnet = subnet;
+ return this;
+ }
+
+ /**
+ * Returns vtn network service IP address.
+ *
+ * @param serviceIp service ip address
+ * @return vtn network builder
+ */
+ public Builder serviceIp(IpAddress serviceIp) {
+ this.serviceIp = serviceIp;
+ return this;
+ }
+
+ /**
+ * Returns vtn network builder with the supplied service network type.
+ *
+ * @param type service network type
+ * @return vtn network builder
+ */
+ public Builder type(ServiceNetworkType type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * Returns vtn network builder with the supplied provider service networks.
+ *
+ * @param providers provider service networks
+ * @return vtn network builder
+ */
+ public Builder providers(Set<ProviderNetwork> providers) {
+ this.providers = providers;
+ return this;
+ }
+
+ /**
+ * Returns vtn network builder with the given additional provider network.
+ *
+ * @param providerId provider network id
+ * @param type direct access type to the provider network
+ * @return vtn network builder
+ */
+ public Builder addProvider(NetworkId providerId, Dependency.Type type) {
+ checkNotNull(providerId, "Provider network ID cannot be null");
+ checkNotNull(type, "Provider network type cannot be null");
+
+ Set<ProviderNetwork> updated = Sets.newHashSet(this.providers);
+ updated.add(ProviderNetwork.of(providerId, type));
+ this.providers = ImmutableSet.copyOf(updated);
+ return this;
+ }
+
+ /**
+ * Returns vtn network builder without the given provider network.
+ *
+ * @param providerId provider network id
+ * @return vtn network builder
+ */
+ public Builder delProvider(NetworkId providerId) {
+ checkNotNull(providerId, "Provider network ID cannot be null");
+
+ ProviderNetwork provider = this.providers.stream()
+ .filter(p -> Objects.equals(p.id(), providerId))
+ .findAny().orElse(null);
+ if (provider != null) {
+ Set<ProviderNetwork> updated = Sets.newHashSet(this.providers);
+ updated.remove(provider);
+ this.providers = ImmutableSet.copyOf(updated);
+ }
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/VtnNetworkEvent.java b/src/main/java/org/opencord/cordvtn/api/VtnNetworkEvent.java
new file mode 100644
index 0000000..c1d6fef
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/VtnNetworkEvent.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import org.joda.time.LocalDateTime;
+import org.onosproject.event.AbstractEvent;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Describes vtn network event.
+ */
+public class VtnNetworkEvent extends AbstractEvent<VtnNetworkEvent.Type, VtnNetwork> {
+
+ private final VtnPort vtnPort;
+
+ /**
+ * Type of vtn network event.
+ */
+ public enum Type {
+ /**
+ * Signifies that a new vtn network has been created.
+ */
+ VTN_NETWORK_CREATED,
+
+ /**
+ * Signifies that some vtn network attributes have changed.
+ */
+ VTN_NETWORK_UPDATED,
+
+ /**
+ * Signifies that a vtn network has been removed.
+ */
+ VTN_NETWORK_REMOVED,
+
+ /**
+ * Signifies that a new vtn port has been created.
+ */
+ VTN_PORT_CREATED,
+
+ /**
+ * Signifies that some vtn port attributes have changed.
+ */
+ VTN_PORT_UPDATED,
+
+ /**
+ * Signifies that a vtn port has been removed.
+ */
+ VTN_PORT_REMOVED
+ }
+
+ /**
+ * Creates an event of a given type and for the specified vtn network and
+ * the current time.
+ *
+ * @param type vtn network event type
+ * @param vtnNet vtn network subject
+ */
+ public VtnNetworkEvent(Type type, VtnNetwork vtnNet) {
+ super(type, vtnNet);
+ this.vtnPort = null;
+ }
+
+ /**
+ * Creates an event of a given type and for the specified vtn network,
+ * port and the current time.
+ *
+ * @param type vtn network event type
+ * @param vtnNet vtn network subject
+ * @param vtnPort optional vtn port subject
+ */
+ public VtnNetworkEvent(Type type, VtnNetwork vtnNet, VtnPort vtnPort) {
+ super(type, vtnNet);
+ this.vtnPort = vtnPort;
+ }
+
+ /**
+ * Returns the vtn port subject.
+ * It returns valid value only with the vtn port events.
+ *
+ * @return vtn port or null if the event is not vtn port specific
+ */
+ public VtnPort vtnPort() {
+ return vtnPort;
+ }
+
+ @Override
+ public String toString() {
+ if (vtnPort == null) {
+ return super.toString();
+ }
+ return toStringHelper(this)
+ .add("time", new LocalDateTime(time()))
+ .add("type", type())
+ .add("vtnNet", subject())
+ .add("vtnPort", vtnPort)
+ .toString();
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/VtnNetworkListener.java b/src/main/java/org/opencord/cordvtn/api/VtnNetworkListener.java
new file mode 100644
index 0000000..be78ef0
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/VtnNetworkListener.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Listener for vtn network event.
+ */
+public interface VtnNetworkListener extends EventListener<VtnNetworkEvent> {
+}
diff --git a/src/main/java/org/opencord/cordvtn/api/VtnPort.java b/src/main/java/org/opencord/cordvtn/api/VtnPort.java
new file mode 100644
index 0000000..a7d8385
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/api/VtnPort.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.api;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.openstack4j.model.network.Port;
+
+import java.util.Objects;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Representation of the port containing all port information consumed by VTN service.
+ */
+public final class VtnPort extends ServicePort {
+
+ private static final String ERR_IP_MISSING = "VTN port IP adderess is missing";
+
+ private final NetworkId netId;
+ private final MacAddress mac;
+ private final IpAddress ip;
+
+ private VtnPort(PortId id,
+ NetworkId netId,
+ MacAddress mac,
+ IpAddress ip,
+ VlanId vlanId,
+ Set<AddressPair> addressPairs) {
+ super(id, vlanId, addressPairs);
+ this.netId = netId;
+ this.mac = mac;
+ this.ip = ip;
+ }
+
+ /**
+ * Returns the network ID of this port.
+ *
+ * @return network id
+ */
+ public NetworkId netId() {
+ return netId;
+ }
+
+ /**
+ * Returns the MAC address of this port.
+ *
+ * @return mac address
+ */
+ public MacAddress mac() {
+ return mac;
+ }
+
+ /**
+ * Returns the IP address of this port.
+ *
+ * @return ip address
+ */
+ public IpAddress ip() {
+ return ip;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof VtnPort) {
+ VtnPort that = (VtnPort) obj;
+ if (Objects.equals(id, that.id) &&
+ Objects.equals(netId, that.netId) &&
+ Objects.equals(mac, that.mac) &&
+ Objects.equals(ip, that.ip) &&
+ Objects.equals(vlanId, that.vlanId) &&
+ Objects.equals(addressPairs, that.addressPairs)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, netId, mac, ip, vlanId, addressPairs);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("id", id)
+ .add("netId", netId)
+ .add("mac", mac)
+ .add("ip", ip)
+ .add("vlanId", vlanId)
+ .add("addressPairs", addressPairs)
+ .toString();
+ }
+
+ /**
+ * Returns the immutable VTN port with the supplied Neutron port with additional
+ * vtn port information.
+ *
+ * @param port neutron port
+ * @param servicePort vtn port
+ * @return vtn port
+ */
+ public static VtnPort of(Port port, ServicePort servicePort) {
+ validateNeutronPort(port);
+ if (servicePort != null) {
+ checkArgument(Objects.equals(port.getId(), servicePort.id().id()));
+ }
+
+ return builder().id(PortId.of(port.getId()))
+ .netId(NetworkId.of(port.getNetworkId()))
+ .mac(MacAddress.valueOf(port.getMacAddress()))
+ .ip(IpAddress.valueOf(port.getFixedIps().iterator().next().getIpAddress()))
+ .vlanId(servicePort == null ? null : servicePort.vlanId().orElse(null))
+ .addressPairs(servicePort == null ? ImmutableSet.of() : servicePort.addressPairs())
+ .build();
+ }
+
+ private static void validateNeutronPort(Port port) {
+ checkNotNull(port);
+ checkArgument(port.getFixedIps().size() > 0, ERR_IP_MISSING);
+ }
+
+ /**
+ * Returns the immutable VTN port with the supplied VTN port with additional
+ * vtn port information.
+ *
+ * @param vtnPort vtn port
+ * @param servicePort vtn port
+ * @return vtn port
+ */
+ public static VtnPort of(VtnPort vtnPort, ServicePort servicePort) {
+ return builder(vtnPort)
+ .vlanId(servicePort.vlanId().orElse(null))
+ .addressPairs(servicePort.addressPairs())
+ .build();
+ }
+
+ /**
+ * Returns new vtn port builder instance.
+ *
+ * @return vtn port builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Returns new vtn port builder instance with copy of the supplied vtn port.
+ *
+ * @param vtnPort vtn port
+ * @return vtn port builder
+ */
+ public static Builder builder(VtnPort vtnPort) {
+ return new Builder().id(vtnPort.id())
+ .netId(vtnPort.netId())
+ .mac(vtnPort.mac())
+ .ip(vtnPort.ip())
+ .vlanId(vtnPort.vlanId().orElse(null))
+ .addressPairs(vtnPort.addressPairs());
+ }
+
+ /**
+ * Builder of the vtn port entities.
+ */
+ public static final class Builder {
+ private PortId id;
+ private NetworkId netId;
+ private MacAddress mac;
+ private IpAddress ip;
+ private VlanId vlanId;
+ private Set<AddressPair> addressPairs = ImmutableSet.of();
+
+ private Builder() {
+ }
+
+ /**
+ * Builds an immutable vtn port.
+ *
+ * @return vtn port instance
+ */
+ public VtnPort build() {
+ checkNotNull(id, "VtnPort port id cannot be null");
+ checkNotNull(netId, "VtnPort network id cannot be null");
+ checkNotNull(mac, "VtnPort mac address cannot be null");
+ checkNotNull(ip, "VtnPort ip address cannot be null");
+ addressPairs = addressPairs == null ? ImmutableSet.of() : addressPairs;
+
+ return new VtnPort(id, netId, mac, ip, vlanId, addressPairs);
+ }
+
+ /**
+ * Returns vtn port builder with the supplied port id.
+ *
+ * @param id port id
+ * @return vtn port builder
+ */
+ public Builder id(PortId id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Returns vtn port builder with the supplied network id.
+ *
+ * @param netId network id
+ * @return vtn port builder
+ */
+ public Builder netId(NetworkId netId) {
+ this.netId = netId;
+ return this;
+ }
+
+ /**
+ * Returns vtn port builder with the supplied mac address.
+ *
+ * @param mac mac address
+ * @return vtn port builder
+ */
+ public Builder mac(MacAddress mac) {
+ this.mac = mac;
+ return this;
+ }
+
+ /**
+ * Returns vtn port builder with the supplied ip address.
+ *
+ * @param ip ip address
+ * @return vtn port builder
+ */
+ public Builder ip(IpAddress ip) {
+ this.ip = ip;
+ return this;
+ }
+
+ /**
+ * Returns vtn port builder with the supplied VLAN ID.
+ *
+ * @param vlanId vlan id
+ * @return vtn port builder
+ */
+ public Builder vlanId(VlanId vlanId) {
+ this.vlanId = vlanId;
+ return this;
+ }
+
+ /**
+ * Returns vtn port builder with the supplied address pairs.
+ *
+ * @param addressPairs set of address pairs
+ * @return vtn port builder
+ */
+ public Builder addressPairs(Set<AddressPair> addressPairs) {
+ this.addressPairs = addressPairs;
+ return this;
+ }
+
+ /**
+ * Returns vtn port builder with the given additional address pair.
+ *
+ * @param addressPair address pair to add
+ * @return vtn port builder
+ */
+ public Builder addAddressPair(AddressPair addressPair) {
+ checkNotNull(addressPair, "VtnPort address pair cannot be null");
+
+ Set<AddressPair> updated = Sets.newHashSet(this.addressPairs);
+ updated.add(addressPair);
+ this.addressPairs = ImmutableSet.copyOf(updated);
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/codec/ServiceNetworkCodec.java b/src/main/java/org/opencord/cordvtn/codec/ServiceNetworkCodec.java
index 52f9a7e..37df2d0 100644
--- a/src/main/java/org/opencord/cordvtn/codec/ServiceNetworkCodec.java
+++ b/src/main/java/org/opencord/cordvtn/codec/ServiceNetworkCodec.java
@@ -17,16 +17,21 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Sets;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
+import org.opencord.cordvtn.api.Dependency;
import org.opencord.cordvtn.api.NetworkId;
+import org.opencord.cordvtn.api.ProviderNetwork;
import org.opencord.cordvtn.api.ServiceNetwork;
-import org.opencord.cordvtn.api.ServiceNetwork.DirectAccessType;
+import org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType;
+
+import java.util.Set;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
-import static org.opencord.cordvtn.api.ServiceNetwork.DirectAccessType.BIDIRECTIONAL;
-import static org.opencord.cordvtn.api.ServiceNetwork.DirectAccessType.UNIDIRECTIONAL;
+import static org.opencord.cordvtn.api.Dependency.Type.BIDIRECTIONAL;
+import static org.opencord.cordvtn.api.Dependency.Type.UNIDIRECTIONAL;
import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.valueOf;
/**
@@ -46,10 +51,10 @@
.put(TYPE, snet.type().name().toLowerCase());
ArrayNode providers = context.mapper().createArrayNode();
- snet.providers().entrySet().forEach(provider -> {
+ snet.providers().forEach(provider -> {
ObjectNode providerJson = context.mapper().createObjectNode()
- .put(ID, provider.getKey().id())
- .put(BIDIRECT, provider.getValue() == BIDIRECTIONAL ? TRUE : FALSE);
+ .put(ID, provider.id().id())
+ .put(BIDIRECT, provider.type() == BIDIRECTIONAL ? TRUE : FALSE);
providers.add(providerJson);
});
@@ -63,18 +68,18 @@
return null;
}
- ServiceNetwork.Builder snetBuilder = ServiceNetwork.builder()
- .id(NetworkId.of(json.get(ID).asText()))
- .type(valueOf(json.get(TYPE).asText().toUpperCase()));
-
+ NetworkId netId = NetworkId.of(json.get(ID).asText());
+ ServiceNetworkType netType = valueOf(json.get(TYPE).asText().toUpperCase());
+ Set<ProviderNetwork> providers = Sets.newHashSet();
if (json.get(PROVIDER_NETWORKS) != null) {
json.get(PROVIDER_NETWORKS).forEach(provider -> {
NetworkId providerId = NetworkId.of(provider.get(ID).asText());
- DirectAccessType type = provider.get(BIDIRECT).asBoolean() ?
+ Dependency.Type type = provider.get(BIDIRECT).asBoolean() ?
BIDIRECTIONAL : UNIDIRECTIONAL;
- snetBuilder.addProvider(providerId, type);
+ providers.add(ProviderNetwork.of(providerId, type));
});
}
- return snetBuilder.build();
+
+ return new ServiceNetwork(netId, netType, providers);
}
}
diff --git a/src/main/java/org/opencord/cordvtn/codec/ServicePortCodec.java b/src/main/java/org/opencord/cordvtn/codec/ServicePortCodec.java
index 9c4343f..91681d0 100644
--- a/src/main/java/org/opencord/cordvtn/codec/ServicePortCodec.java
+++ b/src/main/java/org/opencord/cordvtn/codec/ServicePortCodec.java
@@ -17,6 +17,7 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Sets;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
@@ -26,6 +27,8 @@
import org.opencord.cordvtn.api.PortId;
import org.opencord.cordvtn.api.ServicePort;
+import java.util.Set;
+
/**
* Service port JSON codec.
*/
@@ -62,21 +65,24 @@
return null;
}
- ServicePort.Builder sportBuilder = ServicePort.builder()
- .id(PortId.of(json.get(ID).asText()));
-
+ PortId portId = PortId.of(json.get(ID).asText());
+ VlanId vlanId = null;
if (json.get(VLAN_ID) != null) {
- sportBuilder.vlanId(VlanId.vlanId(json.get(VLAN_ID).asText()));
+ try {
+ vlanId = VlanId.vlanId(json.get(VLAN_ID).asText());
+ } catch (Exception ignore) {
+ }
}
+ Set<AddressPair> addressPairs = Sets.newHashSet();
if (json.get(FLOATING_ADDRESS_PAIRS) != null) {
json.get(FLOATING_ADDRESS_PAIRS).forEach(pair -> {
AddressPair addrPair = AddressPair.of(
IpAddress.valueOf(pair.get(IP_ADDRESS).asText()),
MacAddress.valueOf(pair.get(MAC_ADDRESS).asText()));
- sportBuilder.addAddressPair(addrPair);
+ addressPairs.add(addrPair);
});
}
- return sportBuilder.build();
+ return new ServicePort(portId, vlanId, addressPairs);
}
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/AbstractInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/AbstractInstanceHandler.java
deleted file mode 100644
index ff58107..0000000
--- a/src/main/java/org/opencord/cordvtn/impl/AbstractInstanceHandler.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.opencord.cordvtn.impl;
-
-import org.onlab.osgi.DefaultServiceDirectory;
-import org.onlab.osgi.ServiceDirectory;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.Host;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
-import org.onosproject.xosclient.api.OpenStackAccess;
-import org.onosproject.xosclient.api.VtnPort;
-import org.onosproject.xosclient.api.VtnPortApi;
-import org.onosproject.xosclient.api.VtnPortId;
-import org.onosproject.xosclient.api.VtnService;
-import org.onosproject.xosclient.api.VtnServiceApi;
-import org.onosproject.xosclient.api.VtnServiceApi.ServiceType;
-import org.onosproject.xosclient.api.VtnServiceId;
-import org.onosproject.xosclient.api.XosAccess;
-import org.onosproject.xosclient.api.XosClientService;
-import org.opencord.cordvtn.api.Constants;
-import org.opencord.cordvtn.api.CordVtnConfig;
-import org.opencord.cordvtn.api.Instance;
-import org.opencord.cordvtn.api.InstanceHandler;
-import org.slf4j.Logger;
-
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newSingleThreadExecutor;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.opencord.cordvtn.api.Constants.ERROR_OPENSTACK_ACCESS;
-import static org.opencord.cordvtn.api.Constants.ERROR_XOS_ACCESS;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Provides default virtual network connectivity for service instances.
- */
-public abstract class AbstractInstanceHandler implements InstanceHandler {
-
- protected final Logger log = getLogger(getClass());
-
- protected CoreService coreService;
- protected MastershipService mastershipService;
- protected NetworkConfigRegistry configRegistry;
- protected HostService hostService;
- protected XosClientService xosClient;
-
- protected ApplicationId appId;
- protected Optional<ServiceType> serviceType = Optional.empty();
- protected NetworkConfigListener configListener = new InternalConfigListener();
- protected HostListener hostListener = new InternalHostListener();
-
- private XosAccess xosAccess = null;
- private OpenStackAccess osAccess = null;
- private final ExecutorService eventExecutor = newSingleThreadExecutor(
- groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
-
- protected void activate() {
- ServiceDirectory services = new DefaultServiceDirectory();
- coreService = services.get(CoreService.class);
- configRegistry = services.get(NetworkConfigRegistry.class);
- mastershipService = services.get(MastershipService.class);
- hostService = services.get(HostService.class);
- xosClient = services.get(XosClientService.class);
-
- appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
- hostService.addListener(hostListener);
- configRegistry.addListener(configListener);
-
- log.info("Started");
- }
-
- protected void deactivate() {
- hostService.removeListener(hostListener);
- configRegistry.removeListener(configListener);
- eventExecutor.shutdown();
-
- log.info("Stopped");
- }
-
- protected VtnService getVtnService(VtnServiceId serviceId) {
- checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
- checkNotNull(xosAccess, ERROR_XOS_ACCESS);
-
- // TODO remove openstack access when XOS provides all information
- VtnServiceApi serviceApi = xosClient.getClient(xosAccess).vtnService();
- VtnService service = serviceApi.service(serviceId, osAccess);
- if (service == null) {
- log.warn("Failed to get VtnService for {}", serviceId);
- }
- return service;
- }
-
- protected VtnPort getVtnPort(Instance instance) {
- checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
- checkNotNull(xosAccess, ERROR_XOS_ACCESS);
-
- VtnPortId vtnPortId = instance.portId();
- VtnPortApi portApi = xosClient.getClient(xosAccess).vtnPort();
- VtnPort vtnPort = portApi.vtnPort(vtnPortId, osAccess);
- if (vtnPort == null) {
- log.warn("Failed to get port information of {}", instance);
- return null;
- }
- return vtnPort;
- }
-
- protected Set<Instance> getInstances(VtnServiceId serviceId) {
- return StreamSupport.stream(hostService.getHosts().spliterator(), false)
- .filter(host -> Objects.equals(
- serviceId.id(),
- host.annotations().value(Instance.SERVICE_ID)))
- .map(Instance::of)
- .collect(Collectors.toSet());
- }
-
- protected void readConfiguration() {
- CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
- if (config == null) {
- log.debug("No configuration found");
- return;
- }
- osAccess = config.openstackAccess();
- xosAccess = config.xosAccess();
- }
-
- private class InternalHostListener implements HostListener {
-
- @Override
- public void event(HostEvent event) {
- Host host = event.subject();
- if (!mastershipService.isLocalMaster(host.location().deviceId())) {
- // do not allow to proceed without mastership
- return;
- }
-
- Instance instance = Instance.of(host);
- if (serviceType.isPresent() &&
- !serviceType.get().equals(instance.serviceType())) {
- // not my service instance, do nothing
- return;
- }
-
- switch (event.type()) {
- case HOST_UPDATED:
- case HOST_ADDED:
- eventExecutor.execute(() -> instanceDetected(instance));
- break;
- case HOST_REMOVED:
- eventExecutor.execute(() -> instanceRemoved(instance));
- break;
- default:
- break;
- }
- }
- }
-
- private class InternalConfigListener implements NetworkConfigListener {
-
- @Override
- public void event(NetworkConfigEvent event) {
- if (!event.configClass().equals(CordVtnConfig.class)) {
- return;
- }
-
- switch (event.type()) {
- case CONFIG_ADDED:
- case CONFIG_UPDATED:
- readConfiguration();
- break;
- default:
- break;
- }
- }
- }
-}
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
index d1dfdd2..15269dd 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
@@ -15,8 +15,8 @@
*/
package org.opencord.cordvtn.impl;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -30,8 +30,10 @@
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.packet.PacketProcessor;
-import org.onosproject.xosclient.api.VtnService;
import org.opencord.cordvtn.api.CordVtnConfig;
import org.opencord.cordvtn.api.Instance;
import org.onosproject.net.Host;
@@ -43,6 +45,8 @@
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketService;
+import org.opencord.cordvtn.api.VtnNetwork;
+import org.opencord.cordvtn.impl.handler.AbstractInstanceHandler;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
@@ -51,9 +55,7 @@
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.xosclient.api.VtnServiceApi.NetworkType.PRIVATE;
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.ACCESS_AGENT;
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.MANAGEMENT;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -69,14 +71,21 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnNodeManager nodeManager;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry configRegistry;
+
private final PacketProcessor packetProcessor = new InternalPacketProcessor();
private final Map<Ip4Address, MacAddress> gateways = Maps.newConcurrentMap();
private MacAddress privateGatewayMac = MacAddress.NONE;
+ private NetworkConfigListener configListener = new InternalConfigListener();
@Activate
protected void activate() {
super.activate();
+ configRegistry.addListener(configListener);
+ readConfiguration();
+
packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
requestPacket();
}
@@ -84,6 +93,7 @@
@Deactivate
protected void deactivate() {
packetService.removeProcessor(packetProcessor);
+ configRegistry.removeListener(configListener);
super.deactivate();
}
@@ -158,7 +168,6 @@
return;
}
- log.trace("Send ARP reply for {} with {}", targetIp, replyMac);
Ethernet ethReply = ARP.buildArpReply(
targetIp,
replyMac,
@@ -213,7 +222,7 @@
.findFirst().orElse(null);
if (host == null ||
- !Instance.of(host).serviceType().equals(MANAGEMENT) ||
+ !Instance.of(host).netType().name().contains("MANAGEMENT") ||
hostMgmtPort == null) {
context.block();
return;
@@ -341,20 +350,17 @@
public void instanceDetected(Instance instance) {
// TODO remove this when XOS provides access agent information
// and handle it the same way wit the other instances
- if (instance.serviceType() == ACCESS_AGENT) {
+ if (instance.netType() == ACCESS_AGENT) {
return;
}
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- return;
- }
-
- if (service.networkType().equals(PRIVATE)) {
- log.trace("Added IP:{} MAC:{}", service.serviceIp(), privateGatewayMac);
- addGateway(service.serviceIp(), privateGatewayMac);
+ VtnNetwork vtnNet = getVtnNetwork(instance);
+ if (vtnNet.type() != PUBLIC && vtnNet.type() != MANAGEMENT_HOST &&
+ vtnNet.type() != MANAGEMENT_LOCAL) {
+ log.trace("Added IP:{} MAC:{}", vtnNet.serviceIp(), privateGatewayMac);
+ addGateway(vtnNet.serviceIp(), privateGatewayMac);
// send gratuitous ARP for the existing VMs when ONOS is restarted
- sendGratuitousArp(service.serviceIp(), Sets.newHashSet(instance));
+ sendGratuitousArp(vtnNet.serviceIp(), ImmutableSet.of(instance));
}
}
@@ -362,24 +368,19 @@
public void instanceRemoved(Instance instance) {
// TODO remove this when XOS provides access agent information
// and handle it the same way wit the other instances
- if (instance.serviceType() == ACCESS_AGENT) {
+ if (instance.netType() == ACCESS_AGENT) {
return;
}
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- return;
- }
-
+ VtnNetwork vtnNet = getVtnNetwork(instance);
// remove this network gateway from proxy ARP if no instance presents
- if (service.networkType().equals(PRIVATE) &&
- getInstances(service.id()).isEmpty()) {
- removeGateway(service.serviceIp());
+ if (vtnNet.type() == PRIVATE &&
+ getInstances(vtnNet.id()).isEmpty()) {
+ removeGateway(vtnNet.serviceIp());
}
}
- @Override
- protected void readConfiguration() {
+ private void readConfiguration() {
CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
if (config == null) {
log.debug("No configuration found");
@@ -395,7 +396,24 @@
entry.getKey(), entry.getValue());
});
// TODO send gratuitous arp in case the MAC is changed
+ }
- super.readConfiguration();
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ if (!event.configClass().equals(CordVtnConfig.class)) {
+ return;
+ }
+
+ switch (event.type()) {
+ case CONFIG_ADDED:
+ case CONFIG_UPDATED:
+ readConfiguration();
+ break;
+ default:
+ break;
+ }
+ }
}
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnManager.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnManager.java
new file mode 100644
index 0000000..d645b8f
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnManager.java
@@ -0,0 +1,458 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.impl;
+
+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.apache.felix.scr.annotations.Service;
+import org.onlab.util.Tools;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.host.HostService;
+import org.opencord.cordvtn.api.CordVtnAdminService;
+import org.opencord.cordvtn.api.CordVtnService;
+import org.opencord.cordvtn.api.CordVtnStore;
+import org.opencord.cordvtn.api.CordVtnStoreDelegate;
+import org.opencord.cordvtn.api.Instance;
+import org.opencord.cordvtn.api.NetworkId;
+import org.opencord.cordvtn.api.PortId;
+import org.opencord.cordvtn.api.ServiceNetwork;
+import org.opencord.cordvtn.api.ServicePort;
+import org.opencord.cordvtn.api.SubnetId;
+import org.opencord.cordvtn.api.VtnNetwork;
+import org.opencord.cordvtn.api.VtnNetworkEvent;
+import org.opencord.cordvtn.api.VtnNetworkListener;
+import org.opencord.cordvtn.api.VtnPort;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Subnet;
+import org.slf4j.Logger;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.opencord.cordvtn.api.Instance.NETWORK_ID;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides implementation of administering and interfacing VTN networks.
+ */
+@Component(immediate = true)
+@Service
+public class CordVtnManager extends ListenerRegistry<VtnNetworkEvent, VtnNetworkListener>
+ implements CordVtnAdminService, CordVtnService {
+
+ protected final Logger log = getLogger(getClass());
+
+ private static final String MSG_SERVICE_NET = "VTN network %s %s";
+ private static final String MSG_SERVICE_PORT = "VTN port %s %s";
+ private static final String MSG_NET = "Network %s %s";
+ private static final String MSG_PORT = "Port %s %s";
+ private static final String MSG_SUBNET = "Subnet %s %s";
+
+ private static final String CREATED = "created";
+ private static final String UPDATED = "updated";
+ private static final String REMOVED = "removed";
+
+ private static final String ERR_NULL_SERVICE_PORT = "Service port cannot be null";
+ private static final String ERR_NULL_SERVICE_NET = "Service network cannot be null";
+ private static final String ERR_NULL_PORT = "Port cannot be null";
+ private static final String ERR_NULL_NET = "Network cannot be null";
+ private static final String ERR_NULL_SUBNET = "Subnet cannot be null";
+ private static final String ERR_NULL_PORT_ID = "Port ID cannot be null";
+ private static final String ERR_NULL_NET_ID = "Network ID cannot be null";
+ private static final String ERR_NULL_SUBNET_ID = "Subnet ID cannot be null";
+
+ private static final String ERR_SYNC = "VTN store is out of sync: ";
+ private static final String ERR_NOT_FOUND = " does not exist";
+ private static final String ERR_IN_USE_INSTANCE = "There are instances still in use on the network %s";
+ private static final String ERR_IN_USE_NETWORK = "There are subscribers still in use on the network %s";
+ private static final String ERR_IN_USE_PORT = "There are ports still in use on the network %s";
+ private static final String ERR_SUBNET_DUPLICATE = "Subnet already exists for network %s";
+
+ private static final String PORT = "port ";
+ private static final String NETWORK = "network ";
+ private static final String SUBNET = "subnet for ";
+ private static final String PROVIDER = "provider ";
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnStore store;
+
+ private CordVtnStoreDelegate delegate = new InternalCordVtnStoreDelegate();
+
+ @Activate
+ protected void activate() {
+ store.setDelegate(delegate);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ store.unsetDelegate(delegate);
+ log.info("Stopped");
+ }
+
+ @Override
+ public void createVtnNetwork(ServiceNetwork serviceNet) {
+ checkNotNull(serviceNet, ERR_NULL_SERVICE_NET);
+ synchronized (this) {
+ Network network = store.getNetwork(serviceNet.id());
+ if (network == null) {
+ final String error = ERR_SYNC + NETWORK + serviceNet.id() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+
+ Subnet subnet = getSubnet(serviceNet.id());
+ if (subnet == null) {
+ final String error = ERR_SYNC + SUBNET + serviceNet.id() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+
+ // TODO check VTN network instead of network
+ serviceNet.providers().stream().forEach(provider -> {
+ if (store.getNetwork(provider.id()) == null) {
+ final String error = ERR_SYNC + PROVIDER + provider.id() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+ });
+
+ store.createVtnNetwork(VtnNetwork.of(network, subnet, serviceNet));
+ log.info(String.format(MSG_SERVICE_NET, CREATED, serviceNet.id()));
+ }
+ }
+
+ @Override
+ public void updateVtnNetwork(ServiceNetwork serviceNet) {
+ checkNotNull(serviceNet, ERR_NULL_SERVICE_NET);
+ synchronized (this) {
+ VtnNetwork existing = store.getVtnNetwork(serviceNet.id());
+ if (existing == null) {
+ final String error = ERR_SYNC + NETWORK + serviceNet.id() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+ // only providers update is allowed
+ VtnNetwork updated = VtnNetwork.builder(existing)
+ .providers(serviceNet.providers())
+ .build();
+ store.updateVtnNetwork(updated);
+ log.info(String.format(MSG_SERVICE_NET, UPDATED, serviceNet.id()));
+ }
+ }
+
+ @Override
+ public void removeVtnNetwork(NetworkId netId) {
+ checkNotNull(netId, ERR_NULL_NET_ID);
+ // TODO check if the network still exists?
+ store.removeVtnNetwork(netId);
+ log.info(String.format(MSG_SERVICE_NET, REMOVED, netId));
+ }
+
+ @Override
+ public void createVtnPort(ServicePort servicePort) {
+ checkNotNull(servicePort, ERR_NULL_SERVICE_PORT);
+ synchronized (this) {
+ Port port = store.getPort(servicePort.id());
+ if (port == null) {
+ final String error = ERR_SYNC + PORT + servicePort.id() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+ store.createVtnPort(VtnPort.of(port, servicePort));
+ log.info(String.format(MSG_SERVICE_PORT, CREATED, servicePort.id()));
+ }
+ }
+
+ @Override
+ public void updateVtnPort(ServicePort servicePort) {
+ checkNotNull(servicePort, ERR_NULL_SERVICE_PORT);
+ synchronized (this) {
+ VtnPort vtnPort = store.getVtnPort(servicePort.id());
+ if (vtnPort == null) {
+ final String error = ERR_SYNC + PORT + servicePort.id() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+ store.updateVtnPort(VtnPort.of(vtnPort, servicePort));
+ log.info(String.format(MSG_SERVICE_PORT, UPDATED, servicePort.id()));
+ }
+ }
+
+ @Override
+ public void removeVtnPort(PortId portId) {
+ checkNotNull(portId, ERR_NULL_PORT_ID);
+ store.removeVtnPort(portId);
+ log.info(String.format(MSG_SERVICE_PORT, REMOVED, portId));
+ }
+
+ @Override
+ public void createNetwork(Network network) {
+ checkNotNull(network, ERR_NULL_NET);
+ store.createNetwork(network);
+ log.info(String.format(MSG_NET, CREATED, network.getId()));
+ }
+
+ @Override
+ public void updateNetwork(Network network) {
+ checkNotNull(network, ERR_NULL_NET);
+ store.updateNetwork(network);
+ log.info(String.format(MSG_NET, UPDATED, network.getId()));
+ }
+
+ @Override
+ public void removeNetwork(NetworkId netId) {
+ checkNotNull(netId, ERR_NULL_NET_ID);
+ // FIXME Neutron removes network anyway even if there's an exception here
+ store.removeNetwork(netId);
+ log.info(String.format(MSG_NET, REMOVED, netId));
+ }
+
+ @Override
+ public void createPort(Port port) {
+ checkNotNull(port, ERR_NULL_PORT);
+ synchronized (this) {
+ if (store.getNetwork(NetworkId.of(port.getNetworkId())) == null) {
+ final String error = ERR_SYNC + port.getNetworkId() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+ store.createPort(port);
+ log.info(String.format(MSG_PORT, CREATED, port.getId()));
+ }
+ }
+
+ @Override
+ public void updatePort(Port port) {
+ checkNotNull(port, ERR_NULL_PORT);
+ synchronized (this) {
+ if (store.getNetwork(NetworkId.of(port.getNetworkId())) == null) {
+ final String error = ERR_SYNC + port.getNetworkId() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+ store.updatePort(port);
+ log.info(String.format(MSG_PORT, UPDATED, port.getId()));
+ }
+ }
+
+ @Override
+ public void removePort(PortId portId) {
+ checkNotNull(portId, ERR_NULL_PORT_ID);
+ synchronized (this) {
+ if (getInstance(portId) != null) {
+ final String error = String.format(ERR_IN_USE_PORT, portId);
+ throw new IllegalStateException(error);
+ }
+ removeVtnPort(portId);
+ store.removePort(portId);
+ log.info(String.format(MSG_PORT, REMOVED, portId));
+ }
+ }
+
+ @Override
+ public void createSubnet(Subnet subnet) {
+ checkNotNull(subnet, ERR_NULL_SUBNET);
+ synchronized (this) {
+ if (store.getNetwork(NetworkId.of(subnet.getNetworkId())) == null) {
+ final String error = ERR_SYNC + subnet.getNetworkId() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+
+ if (getSubnet(NetworkId.of(subnet.getNetworkId())) != null) {
+ // CORD does not allow multiple subnets for a network
+ final String error = String.format(ERR_SUBNET_DUPLICATE, subnet.getNetworkId());
+ throw new IllegalStateException(error);
+ }
+ store.createSubnet(subnet);
+ log.info(String.format(MSG_SUBNET, CREATED, subnet.getId()));
+ }
+ }
+
+ @Override
+ public void updateSubnet(Subnet subnet) {
+ checkNotNull(subnet, ERR_NULL_SUBNET);
+ synchronized (this) {
+ if (store.getNetwork(NetworkId.of(subnet.getNetworkId())) == null) {
+ final String error = ERR_SYNC + subnet.getNetworkId() + ERR_NOT_FOUND;
+ throw new IllegalStateException(error);
+ }
+ store.updateSubnet(subnet);
+ log.info(String.format(MSG_SUBNET, UPDATED, subnet.getId()));
+ }
+ }
+
+ @Override
+ public void removeSubnet(SubnetId subnetId) {
+ checkNotNull(subnetId, ERR_NULL_SUBNET_ID);
+ // FIXME Neutron removes network anyway even if there's an exception here
+ synchronized (this) {
+ removeVtnNetwork(NetworkId.of(store.getSubnet(subnetId).getNetworkId()));
+ store.removeSubnet(subnetId);
+ log.info(String.format(MSG_SUBNET, REMOVED, subnetId));
+ }
+ }
+
+ @Override
+ public VtnNetwork getVtnNetwork(NetworkId netId) {
+ checkNotNull(netId, ERR_NULL_NET_ID);
+ return store.getVtnNetwork(netId);
+ }
+
+ @Override
+ public VtnNetwork getVtnNetworkOrDefault(NetworkId netId) {
+ checkNotNull(netId, ERR_NULL_NET_ID);
+
+ // return default VTN network if the network and subnet exist
+ VtnNetwork vtnNet = store.getVtnNetwork(netId);
+ return vtnNet == null ? getDefaultVtnNetwork(netId) : vtnNet;
+ }
+
+ @Override
+ public Set<VtnNetwork> getVtnNetworks() {
+ return store.getVtnNetworks();
+ }
+
+ @Override
+ public VtnPort getVtnPort(PortId portId) {
+ checkNotNull(portId, ERR_NULL_PORT_ID);
+ return store.getVtnPort(portId);
+ }
+
+ @Override
+ public VtnPort getVtnPortOrDefault(PortId portId) {
+ checkNotNull(portId, ERR_NULL_PORT_ID);
+
+ // return default VTN port if the port exists
+ VtnPort vtnPort = store.getVtnPort(portId);
+ return vtnPort == null ? getDefaultPort(portId) : vtnPort;
+ }
+
+ @Override
+ public VtnPort getVtnPort(String portName) {
+ Optional<Port> port = store.getPorts()
+ .stream()
+ .filter(p -> p.getId().contains(portName.substring(3)))
+ .findFirst();
+ if (!port.isPresent()) {
+ return null;
+ }
+ return getVtnPortOrDefault(PortId.of(port.get().getId()));
+ }
+
+ @Override
+ public Set<VtnPort> getVtnPorts() {
+ return store.getVtnPorts();
+ }
+
+ @Override
+ public Network getNetwork(NetworkId netId) {
+ checkNotNull(netId, ERR_NULL_NET_ID);
+ return store.getNetwork(netId);
+ }
+
+ @Override
+ public Set<Network> getNetworks() {
+ return store.getNetworks();
+ }
+
+ @Override
+ public Port getPort(PortId portId) {
+ checkNotNull(portId, ERR_NULL_PORT_ID);
+ return store.getPort(portId);
+ }
+
+ @Override
+ public Set<Port> getPorts() {
+ return store.getPorts();
+ }
+
+ @Override
+ public Subnet getSubnet(SubnetId subnetId) {
+ checkNotNull(subnetId, ERR_NULL_SUBNET_ID);
+ return store.getSubnet(subnetId);
+ }
+
+ @Override
+ public Set<Subnet> getSubnets() {
+ return store.getSubnets();
+ }
+
+ @Override
+ public Instance getInstance(PortId portId) {
+ VtnPort vtnPort = getVtnPortOrDefault(portId);
+ if (vtnPort == null) {
+ final String error = "Failed to build VTN port for " + portId.id();
+ throw new IllegalStateException(error);
+ }
+
+ Host host = hostService.getHost(HostId.hostId(vtnPort.mac()));
+ if (host == null) {
+ return null;
+ }
+ return Instance.of(host);
+ }
+
+ @Override
+ public Set<Instance> getInstances(NetworkId netId) {
+ return Tools.stream(hostService.getHosts())
+ .filter(host -> Objects.equals(
+ host.annotations().value(NETWORK_ID),
+ netId.id()))
+ .map(Instance::of)
+ .collect(Collectors.toSet());
+ }
+
+ private VtnNetwork getDefaultVtnNetwork(NetworkId netId) {
+ Network network = getNetwork(netId);
+ Subnet subnet = getSubnet(netId);
+ if (network == null || subnet == null) {
+ return null;
+ }
+ return VtnNetwork.of(network, subnet, null);
+ }
+
+ private VtnPort getDefaultPort(PortId portId) {
+ Port port = getPort(portId);
+ if (port == null) {
+ return null;
+ }
+ return VtnPort.of(port, null);
+ }
+
+ private Subnet getSubnet(NetworkId netId) {
+ // TODO fix networking-onos to send Network UPDATE when subnet created
+ Optional<Subnet> subnet = getSubnets().stream()
+ .filter(s -> Objects.equals(s.getNetworkId(), netId.id()))
+ .findFirst();
+ return subnet.orElse(null);
+ }
+
+ private class InternalCordVtnStoreDelegate implements CordVtnStoreDelegate {
+
+ @Override
+ public void notify(VtnNetworkEvent event) {
+ if (event != null) {
+ log.trace("send service network event {}", event);
+ process(event);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
index 82bb0a9..ff43f93 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
@@ -34,6 +34,8 @@
import org.onosproject.net.behaviour.InterfaceConfig;
import org.onosproject.net.behaviour.TunnelEndPoints;
import org.onosproject.net.behaviour.TunnelKeys;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.basics.SubjectFactories;
import org.opencord.cordvtn.api.ConnectionHandler;
import org.opencord.cordvtn.api.CordVtnConfig;
import org.opencord.cordvtn.api.CordVtnNode;
@@ -147,6 +149,16 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnPipeline pipeline;
+ private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
+ private final ConfigFactory configFactory =
+ new ConfigFactory<ApplicationId, CordVtnConfig>(
+ SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "cordvtn") {
+ @Override
+ public CordVtnConfig createConfig() {
+ return new CordVtnConfig();
+ }
+ };
+
private final ExecutorService eventExecutor =
newSingleThreadExecutor(groupedThreads("onos/cordvtn-node", "event-handler", log));
@@ -213,8 +225,9 @@
@Activate
protected void activate() {
- appId = coreService.getAppId(CORDVTN_APP_ID);
+ appId = coreService.registerApplication(CORDVTN_APP_ID);
+ configRegistry.registerConfigFactory(configFactory);
localNodeId = clusterService.getLocalNode().id();
leadershipService.runForLeadership(appId.name());
@@ -238,6 +251,7 @@
nodeStore.removeListener(nodeStoreListener);
leadershipService.withdraw(appId.name());
+ configRegistry.unregisterConfigFactory(configFactory);
eventExecutor.shutdown();
log.info("Stopped");
diff --git a/src/main/java/org/opencord/cordvtn/impl/DependencyManager.java b/src/main/java/org/opencord/cordvtn/impl/DependencyManager.java
index c22982b..bb1692c 100644
--- a/src/main/java/org/opencord/cordvtn/impl/DependencyManager.java
+++ b/src/main/java/org/opencord/cordvtn/impl/DependencyManager.java
@@ -15,9 +15,10 @@
*/
package org.opencord.cordvtn.impl;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -27,8 +28,20 @@
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
-import org.onosproject.xosclient.api.VtnServiceApi;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.opencord.cordvtn.api.CordVtnAdminService;
import org.opencord.cordvtn.api.CordVtnNode;
+import org.opencord.cordvtn.api.Dependency;
+import org.opencord.cordvtn.api.Dependency.Type;
import org.opencord.cordvtn.api.DependencyService;
import org.opencord.cordvtn.api.Instance;
import org.onosproject.core.DefaultGroupId;
@@ -50,8 +63,14 @@
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService;
-import org.onosproject.xosclient.api.VtnService;
-import org.onosproject.xosclient.api.VtnServiceId;
+import org.opencord.cordvtn.api.NetworkId;
+import org.opencord.cordvtn.api.ProviderNetwork;
+import org.opencord.cordvtn.api.SegmentId;
+import org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType;
+import org.opencord.cordvtn.api.VtnNetwork;
+import org.opencord.cordvtn.api.VtnNetworkEvent;
+import org.opencord.cordvtn.api.VtnNetworkListener;
+import org.opencord.cordvtn.impl.handler.AbstractInstanceHandler;
import org.slf4j.Logger;
import java.util.List;
@@ -60,6 +79,8 @@
import java.util.Set;
import java.util.stream.Collectors;
+import static org.opencord.cordvtn.api.Dependency.Type.BIDIRECTIONAL;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.ACCESS_AGENT;
import static org.opencord.cordvtn.impl.CordVtnPipeline.*;
import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
import static org.slf4j.LoggerFactory.getLogger;
@@ -73,116 +94,175 @@
protected final Logger log = getLogger(getClass());
+ private static final String ERR_NET_FAIL = "Failed to get VTN network ";
+ private static final String MSG_CREATE = "Created dependency %s";
+ private static final String MSG_REMOVE = "Removed dependency %s";
+ private static final String ADDED = "Added ";
+ private static final String REMOVED = "Removed ";
+
+ private static final KryoNamespace SERIALIZER_DEPENDENCY = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(VtnNetwork.class)
+ .register(NetworkId.class)
+ .register(SegmentId.class)
+ .register(ServiceNetworkType.class)
+ .register(ProviderNetwork.class)
+ .register(Dependency.class)
+ .register(Type.class)
+ .build();
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected GroupService groupService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LeadershipService leadershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnPipeline pipeline;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnNodeManager nodeManager;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnAdminService vtnService;
+
+ private final VtnNetworkListener vtnNetListener = new InternalVtnNetListener();
+ private final MapEventListener<NetworkId, Set<Dependency>> dependencyListener =
+ new DependencyMapListener();
+
+ private ConsistentMap<NetworkId, Set<Dependency>> dependencyStore;
+ private NodeId localNodeId;
+
@Activate
protected void activate() {
super.activate();
+
+ dependencyStore = storageService.<NetworkId, Set<Dependency>>consistentMapBuilder()
+ .withSerializer(Serializer.using(SERIALIZER_DEPENDENCY))
+ .withName("cordvtn-dependencymap")
+ .withApplicationId(appId)
+ .build();
+ dependencyStore.addListener(dependencyListener);
+
+ localNodeId = clusterService.getLocalNode().id();
+ leadershipService.runForLeadership(appId.name());
+ vtnService.addListener(vtnNetListener);
}
@Deactivate
protected void deactivate() {
super.deactivate();
+ dependencyStore.removeListener(dependencyListener);
+ vtnService.removeListener(vtnNetListener);
+ leadershipService.withdraw(appId.name());
}
@Override
- public void createDependency(VtnServiceId tServiceId, VtnServiceId pServiceId,
- boolean isBidirectional) {
- VtnService tService = getVtnService(tServiceId);
- VtnService pService = getVtnService(pServiceId);
-
- if (tService == null || pService == null) {
- log.error("Failed to create dependency between {} and {}",
- tServiceId, pServiceId);
+ public void createDependency(NetworkId subNetId, NetworkId proNetId, Type type) {
+ // FIXME this is not safe
+ VtnNetwork existing = vtnService.getVtnNetworkOrDefault(subNetId);
+ if (existing == null) {
+ log.warn("Failed to create dependency between {} and {}", subNetId, proNetId);
return;
}
-
- log.info("Created dependency between {} and {}", tService.name(), pService.name());
- serviceDependencyRules(tService, pService, isBidirectional, true);
+ vtnService.createVtnNetwork(existing);
+ VtnNetwork updated = VtnNetwork.builder(existing)
+ .addProvider(proNetId, type)
+ .build();
+ vtnService.updateVtnNetwork(updated);
}
@Override
- public void removeDependency(VtnServiceId tServiceId, VtnServiceId pServiceId) {
- VtnService tService = getVtnService(tServiceId);
- VtnService pService = getVtnService(pServiceId);
-
- if (tService == null || pService == null) {
- log.error("Failed to remove dependency between {} and {}",
- tServiceId, pServiceId);
+ public void removeDependency(NetworkId subNetId, NetworkId proNetId) {
+ // FIXME this is not safe
+ VtnNetwork subNet = vtnService.getVtnNetwork(subNetId);
+ if (subNet == null) {
+ log.warn("No dependency exists between {} and {}", subNetId, proNetId);
return;
}
-
- log.info("Removed dependency between {} and {}", tService.name(), pService.name());
- serviceDependencyRules(tService, pService, true, false);
+ VtnNetwork updated = VtnNetwork.builder(subNet)
+ .delProvider(proNetId)
+ .build();
+ vtnService.updateVtnNetwork(updated);
}
@Override
public void instanceDetected(Instance instance) {
// TODO remove this when XOS provides access agent information
// and handle it the same way wit the other instances
- if (instance.serviceType() == VtnServiceApi.ServiceType.ACCESS_AGENT) {
+ if (instance.netType() == ACCESS_AGENT) {
return;
}
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- return;
+ VtnNetwork vtnNet = vtnService.getVtnNetworkOrDefault(instance.netId());
+ if (vtnNet == null) {
+ final String error = ERR_NET_FAIL + instance.netId();
+ throw new IllegalStateException(error);
}
- // TODO get bidirectional information from XOS once XOS supports
- service.tenantServices().stream().forEach(
- tServiceId -> createDependency(tServiceId, service.id(), true));
- service.providerServices().stream().forEach(
- pServiceId -> createDependency(service.id(), pServiceId, true));
-
- updateProviderServiceInstances(service);
+ if (!vtnNet.providers().isEmpty()) {
+ updateSubscriberInstances(vtnNet, instance, true);
+ }
+ // TODO check if subscribers on this network
+ updateProviderInstances(vtnNet);
}
@Override
public void instanceRemoved(Instance instance) {
// TODO remove this when XOS provides access agent information
// and handle it the same way wit the other instances
- if (instance.serviceType() == VtnServiceApi.ServiceType.ACCESS_AGENT) {
+ if (instance.netType() == ACCESS_AGENT) {
return;
}
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- return;
+ VtnNetwork vtnNet = vtnService.getVtnNetworkOrDefault(instance.netId());
+ if (vtnNet == null) {
+ final String error = ERR_NET_FAIL + instance.netId();
+ throw new IllegalStateException(error);
}
- if (!service.providerServices().isEmpty()) {
- removeInstanceFromTenantService(instance, service);
+ if (!vtnNet.providers().isEmpty()) {
+ updateSubscriberInstances(vtnNet, instance, false);
}
- if (!service.tenantServices().isEmpty()) {
- updateProviderServiceInstances(service);
- }
+ // TODO check if subscribers on this network
+ updateProviderInstances(vtnNet);
}
- private void updateProviderServiceInstances(VtnService service) {
- GroupKey groupKey = getGroupKey(service.id());
+ private void dependencyCreated(Dependency dependency) {
+ populateDependencyRules(dependency.subscriber(), dependency.provider(),
+ dependency.type(), true);
+ log.info(String.format(MSG_CREATE, dependency));
+ }
+ private void dependencyRemoved(Dependency dependency) {
+ populateDependencyRules(dependency.subscriber(), dependency.provider(),
+ dependency.type(), false);
+ log.info(String.format(MSG_REMOVE, dependency));
+ }
+
+ private void updateProviderInstances(VtnNetwork provider) {
Set<DeviceId> devices = nodeManager.completeNodes().stream()
.map(CordVtnNode::integrationBridgeId)
.collect(Collectors.toSet());
+ GroupKey groupKey = getGroupKey(provider.id());
for (DeviceId deviceId : devices) {
Group group = groupService.getGroup(deviceId, groupKey);
if (group == null) {
- log.trace("No group exists for service {} in {}", service.id(), deviceId);
continue;
}
List<GroupBucket> oldBuckets = group.buckets().buckets();
- List<GroupBucket> newBuckets = getServiceGroupBuckets(
- deviceId, service.vni(), getInstances(service.id())).buckets();
+ List<GroupBucket> newBuckets = getProviderGroupBuckets(
+ deviceId,
+ provider.segmentId().id(),
+ getInstances(provider.id())).buckets();
if (oldBuckets.equals(newBuckets)) {
continue;
@@ -196,7 +276,8 @@
groupKey,
new GroupBuckets(bucketsToRemove),
groupKey, appId);
- log.debug("Removes instances from {} : {}", service.name(), bucketsToRemove);
+ log.debug("Removed buckets from provider({}) group on {}: {}",
+ provider.id(), deviceId, bucketsToRemove);
}
List<GroupBucket> bucketsToAdd = Lists.newArrayList(newBuckets);
@@ -207,57 +288,67 @@
groupKey,
new GroupBuckets(bucketsToAdd),
groupKey, appId);
- log.debug("Adds instances to {} : {}", service.name(), bucketsToRemove);
+ log.debug("Added buckets to provider({}) group on {}: {}",
+ provider.id(), deviceId, bucketsToAdd);
}
}
}
- private void removeInstanceFromTenantService(Instance instance, VtnService service) {
- service.providerServices().stream().forEach(pServiceId -> {
- Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
- Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
+ private void updateSubscriberInstances(VtnNetwork subscriber, Instance instance,
+ boolean isDetected) {
+ DeviceId deviceId = instance.deviceId();
+ final String isAdded = isDetected ? ADDED : REMOVED;
+ subscriber.providers().stream().forEach(provider -> {
+ populateInPortRule(
+ ImmutableMap.of(deviceId, ImmutableSet.of(instance.portNumber())),
+ ImmutableMap.of(deviceId, getGroupId(provider.id(), deviceId)),
+ isDetected);
- inPorts.put(instance.deviceId(), Sets.newHashSet(instance.portNumber()));
- outGroups.put(instance.deviceId(), getGroupId(pServiceId, instance.deviceId()));
-
- inServiceRule(inPorts, outGroups, false);
+ log.info(isAdded + "subscriber instance({}) for provider({})",
+ instance.host().id(), provider.id());
});
}
- private void serviceDependencyRules(VtnService tService, VtnService pService,
- boolean isBidirectional, boolean install) {
- Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
- Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
+ private void populateDependencyRules(VtnNetwork subscriber,
+ VtnNetwork provider,
+ Type type, boolean install) {
+ Map<DeviceId, GroupId> providerGroups = Maps.newHashMap();
+ Map<DeviceId, Set<PortNumber>> subscriberPorts = Maps.newHashMap();
nodeManager.completeNodes().stream().forEach(node -> {
DeviceId deviceId = node.integrationBridgeId();
- GroupId groupId = createServiceGroup(deviceId, pService);
- outGroups.put(deviceId, groupId);
+ GroupId groupId = getProviderGroup(provider, deviceId);
+ providerGroups.put(deviceId, groupId);
- Set<PortNumber> tServiceInstances = getInstances(tService.id())
+ Set<PortNumber> ports = getInstances(subscriber.id())
.stream()
.filter(instance -> instance.deviceId().equals(deviceId))
.map(Instance::portNumber)
.collect(Collectors.toSet());
- inPorts.put(deviceId, tServiceInstances);
+ subscriberPorts.put(deviceId, ports);
});
- Ip4Prefix srcRange = tService.subnet().getIp4Prefix();
- Ip4Prefix dstRange = pService.subnet().getIp4Prefix();
+ Ip4Prefix subscriberIp = subscriber.subnet().getIp4Prefix();
+ Ip4Prefix providerIp = provider.subnet().getIp4Prefix();
- indirectAccessRule(srcRange, pService.serviceIp().getIp4Address(), outGroups, install);
- directAccessRule(srcRange, dstRange, install);
- if (isBidirectional) {
- directAccessRule(dstRange, srcRange, install);
+ populateInPortRule(subscriberPorts, providerGroups, install);
+ populateIndirectAccessRule(
+ subscriberIp,
+ provider.serviceIp().getIp4Address(),
+ providerGroups,
+ install);
+ populateDirectAccessRule(subscriberIp, providerIp, install);
+ if (type == BIDIRECTIONAL) {
+ populateDirectAccessRule(providerIp, subscriberIp, install);
}
- inServiceRule(inPorts, outGroups, install);
}
- private void indirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
- Map<DeviceId, GroupId> outGroups, boolean install) {
+ private void populateIndirectAccessRule(Ip4Prefix srcIp, Ip4Address serviceIp,
+ Map<DeviceId, GroupId> outGroups,
+ boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPSrc(srcRange)
+ .matchIPSrc(srcIp)
.matchIPDst(serviceIp.toIpPrefix())
.build();
@@ -280,11 +371,11 @@
}
}
- private void directAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange, boolean install) {
+ private void populateDirectAccessRule(Ip4Prefix srcIp, Ip4Prefix dstIp, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPSrc(srcRange)
- .matchIPDst(dstRange)
+ .matchIPSrc(srcIp)
+ .matchIPDst(dstIp)
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
@@ -307,13 +398,14 @@
});
}
- private void inServiceRule(Map<DeviceId, Set<PortNumber>> inPorts,
- Map<DeviceId, GroupId> outGroups, boolean install) {
- for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
+ private void populateInPortRule(Map<DeviceId, Set<PortNumber>> subscriberPorts,
+ Map<DeviceId, GroupId> providerGroups,
+ boolean install) {
+ for (Map.Entry<DeviceId, Set<PortNumber>> entry : subscriberPorts.entrySet()) {
Set<PortNumber> ports = entry.getValue();
DeviceId deviceId = entry.getKey();
- GroupId groupId = outGroups.get(deviceId);
+ GroupId groupId = providerGroups.get(deviceId);
if (groupId == null) {
continue;
}
@@ -342,26 +434,25 @@
}
}
- private GroupId getGroupId(VtnServiceId serviceId, DeviceId deviceId) {
- return new DefaultGroupId(Objects.hash(serviceId, deviceId));
+ private GroupId getGroupId(NetworkId netId, DeviceId deviceId) {
+ return new DefaultGroupId(Objects.hash(netId, deviceId));
}
- private GroupKey getGroupKey(VtnServiceId serviceId) {
- return new DefaultGroupKey(serviceId.id().getBytes());
+ private GroupKey getGroupKey(NetworkId netId) {
+ return new DefaultGroupKey(netId.id().getBytes());
}
- private GroupId createServiceGroup(DeviceId deviceId, VtnService service) {
- GroupKey groupKey = getGroupKey(service.id());
+ private GroupId getProviderGroup(VtnNetwork provider, DeviceId deviceId) {
+ GroupKey groupKey = getGroupKey(provider.id());
Group group = groupService.getGroup(deviceId, groupKey);
- GroupId groupId = getGroupId(service.id(), deviceId);
+ GroupId groupId = getGroupId(provider.id(), deviceId);
if (group != null) {
- log.debug("Group {} is already exist in {}", service.id(), deviceId);
return groupId;
}
- GroupBuckets buckets = getServiceGroupBuckets(
- deviceId, service.vni(), getInstances(service.id()));
+ GroupBuckets buckets = getProviderGroupBuckets(
+ deviceId, provider.segmentId().id(), getInstances(provider.id()));
GroupDescription groupDescription = new DefaultGroupDescription(
deviceId,
GroupDescription.Type.SELECT,
@@ -374,26 +465,135 @@
return groupId;
}
- private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId,
- Set<Instance> instances) {
+ private void removeProviderGroup(NetworkId netId) {
+ GroupKey groupKey = getGroupKey(netId);
+ nodeManager.completeNodes().stream()
+ .forEach(node -> {
+ DeviceId deviceId = node.integrationBridgeId();
+ Group group = groupService.getGroup(deviceId, groupKey);
+ if (group != null) {
+ groupService.removeGroup(deviceId, groupKey, appId);
+ }
+ });
+ log.debug("Removed group for network {}", netId);
+ }
+
+ private GroupBuckets getProviderGroupBuckets(DeviceId deviceId,
+ long tunnelId,
+ Set<Instance> instances) {
List<GroupBucket> buckets = Lists.newArrayList();
instances.stream().forEach(instance -> {
Ip4Address tunnelIp = nodeManager.dataIp(instance.deviceId()).getIp4Address();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
if (deviceId.equals(instance.deviceId())) {
- tBuilder.setEthDst(instance.mac())
- .setOutput(instance.portNumber());
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(instance.mac())
+ .setOutput(instance.portNumber())
+ .build();
+ buckets.add(createSelectGroupBucket(treatment));
} else {
ExtensionTreatment tunnelDst =
pipeline.tunnelDstTreatment(deviceId, tunnelIp);
- tBuilder.setEthDst(instance.mac())
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(instance.mac())
.extension(tunnelDst, deviceId)
.setTunnelId(tunnelId)
- .setOutput(nodeManager.tunnelPort(instance.deviceId()));
+ .setOutput(nodeManager.tunnelPort(instance.deviceId()))
+ .build();
+ buckets.add(createSelectGroupBucket(treatment));
}
- buckets.add(createSelectGroupBucket(tBuilder.build()));
});
return new GroupBuckets(buckets);
}
+
+ private class InternalVtnNetListener implements VtnNetworkListener {
+
+ @Override
+ public void event(VtnNetworkEvent event) {
+ NodeId leader = leadershipService.getLeader(appId.name());
+ if (!Objects.equals(localNodeId, leader)) {
+ // do not allow to proceed without leadership
+ return;
+ }
+
+ switch (event.type()) {
+ case VTN_NETWORK_CREATED:
+ case VTN_NETWORK_UPDATED:
+ log.debug("Processing dependency for {}", event.subject());
+ eventExecutor.execute(() -> updateDependency(event.subject()));
+ break;
+ case VTN_NETWORK_REMOVED:
+ log.debug("Removing dependency for {}", event.subject());
+ NetworkId netId = event.subject().id();
+ eventExecutor.execute(() -> dependencyStore.remove(netId));
+ break;
+ case VTN_PORT_CREATED:
+ case VTN_PORT_UPDATED:
+ case VTN_PORT_REMOVED:
+ default:
+ // do nothing for the other events
+ break;
+ }
+ }
+
+ private void updateDependency(VtnNetwork subscriber) {
+ Set<Dependency> dependencies = subscriber.providers().stream()
+ .map(provider -> Dependency.builder()
+ .subscriber(subscriber)
+ .provider(vtnService.getVtnNetworkOrDefault(provider.id()))
+ .type(provider.type())
+ .build())
+ .collect(Collectors.toSet());
+ dependencyStore.put(subscriber.id(), dependencies);
+ }
+ }
+
+ private class DependencyMapListener implements MapEventListener<NetworkId, Set<Dependency>> {
+
+ @Override
+ public void event(MapEvent<NetworkId, Set<Dependency>> event) {
+ NodeId leader = leadershipService.getLeader(appId.name());
+ if (!Objects.equals(localNodeId, leader)) {
+ // do not allow to proceed without leadership
+ return;
+ }
+
+ switch (event.type()) {
+ case UPDATE:
+ log.debug("Subscriber {} updated", event.key());
+ eventExecutor.execute(() -> dependencyUpdated(
+ event.oldValue().value(),
+ event.newValue().value()
+ ));
+ break;
+ case INSERT:
+ log.debug("Subscriber {} inserted", event.key());
+ eventExecutor.execute(() -> dependencyUpdated(
+ ImmutableSet.of(),
+ event.newValue().value()
+ ));
+ break;
+ case REMOVE:
+ log.debug("Subscriber {} removed", event.key());
+ eventExecutor.execute(() -> dependencyUpdated(
+ event.oldValue().value(),
+ ImmutableSet.of()
+ ));
+ break;
+ default:
+ log.error("Unsupported event type");
+ break;
+ }
+ }
+
+ private void dependencyUpdated(Set<Dependency> oldDeps, Set<Dependency> newDeps) {
+ oldDeps.stream().filter(oldDep -> !newDeps.contains(oldDep))
+ .forEach(DependencyManager.this::dependencyRemoved);
+
+ newDeps.stream().filter(newDep -> !oldDeps.contains(newDep))
+ .forEach(DependencyManager.this::dependencyCreated);
+
+ // TODO remove any group if no subscriber exists
+ }
+ }
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/DistributedCordVtnStore.java b/src/main/java/org/opencord/cordvtn/impl/DistributedCordVtnStore.java
index 11b1e83..3520ba6 100644
--- a/src/main/java/org/opencord/cordvtn/impl/DistributedCordVtnStore.java
+++ b/src/main/java/org/opencord/cordvtn/impl/DistributedCordVtnStore.java
@@ -15,96 +15,441 @@
*/
package org.opencord.cordvtn.impl;
+import com.google.common.collect.ImmutableSet;
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.apache.felix.scr.annotations.Service;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.Versioned;
import org.opencord.cordvtn.api.CordVtnStore;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.opencord.cordvtn.api.AddressPair;
+import org.opencord.cordvtn.api.CordVtnStoreDelegate;
+import org.opencord.cordvtn.api.Dependency;
import org.opencord.cordvtn.api.NetworkId;
import org.opencord.cordvtn.api.PortId;
-import org.opencord.cordvtn.api.ServiceNetwork;
-import org.opencord.cordvtn.api.ServicePort;
+import org.opencord.cordvtn.api.ProviderNetwork;
+import org.opencord.cordvtn.api.SegmentId;
+import org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType;
+import org.opencord.cordvtn.api.SubnetId;
+import org.opencord.cordvtn.api.VtnNetwork;
+import org.opencord.cordvtn.api.VtnNetworkEvent;
+import org.opencord.cordvtn.api.VtnPort;
+import org.openstack4j.model.network.IPVersionType;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.State;
+import org.openstack4j.model.network.Subnet;
+import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
+import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
+import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
+import org.openstack4j.openstack.networking.domain.NeutronIP;
+import org.openstack4j.openstack.networking.domain.NeutronNetwork;
+import org.openstack4j.openstack.networking.domain.NeutronPool;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
+import org.openstack4j.openstack.networking.domain.NeutronSubnet;
import org.slf4j.Logger;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.opencord.cordvtn.api.Constants.CORDVTN_APP_ID;
+import static org.opencord.cordvtn.api.VtnNetworkEvent.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Implementation of the cordvtn service.
+ * Manages the inventory of VTN networks using a {@code ConsistentMap}.
*/
@Component(immediate = true)
@Service
-public class DistributedCordVtnStore implements CordVtnStore {
+public class DistributedCordVtnStore extends AbstractStore<VtnNetworkEvent, CordVtnStoreDelegate>
+ implements CordVtnStore {
+
protected final Logger log = getLogger(getClass());
- private static final String MSG_SERVICE_NET = "Service network %s %s";
- private static final String MSG_SERVICE_PORT = "Service port %s %s";
- private static final String CREATED = "created";
- private static final String UPDATED = "updated";
- private static final String REMOVED = "removed";
+ private static final String ERR_SYNC = "VTN store is out of sync: ";
+ private static final String ERR_NOT_FOUND = " does not exist";
+ private static final String ERR_DUPLICATE = " already exists with different properties";
+
+ private static final KryoNamespace SERIALIZER_SERVICE = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(VtnNetwork.class)
+ .register(NetworkId.class)
+ .register(SegmentId.class)
+ .register(ServiceNetworkType.class)
+ .register(ProviderNetwork.class)
+ .register(Dependency.Type.class)
+ .register(VtnPort.class)
+ .register(PortId.class)
+ .register(AddressPair.class)
+ .build();
+
+ // Use Neutron data model until we need our own abstraction of virtual networks
+ private static final KryoNamespace SERIALIZER_NEUTRON = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(Network.class)
+ .register(NetworkId.class)
+ .register(NeutronNetwork.class)
+ .register(State.class)
+ .register(NetworkType.class)
+ .register(Port.class)
+ .register(PortId.class)
+ .register(NeutronPort.class)
+ .register(NeutronIP.class)
+ .register(NeutronAllowedAddressPair.class)
+ .register(NeutronExtraDhcpOptCreate.class)
+ .register(Subnet.class)
+ .register(SubnetId.class)
+ .register(NeutronSubnet.class)
+ .register(NeutronPool.class)
+ .register(NeutronHostRoute.class)
+ .register(IPVersionType.class)
+ .build();
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ private final MapEventListener<PortId, VtnPort> vtnPortListener = new VtnPortMapListener();
+ private final MapEventListener<NetworkId, VtnNetwork> vtnNetworkListener = new VtnNetworkMapListener();
+ private final ExecutorService eventExecutor = newSingleThreadExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+
+ private ConsistentMap<NetworkId, VtnNetwork> vtnNetworkStore;
+ private ConsistentMap<PortId, VtnPort> vtnPortStore;
+ private ConsistentMap<NetworkId, Network> networkStore;
+ private ConsistentMap<SubnetId, Subnet> subnetStore;
+ private ConsistentMap<PortId, Port> portStore;
@Activate
protected void activate() {
+ ApplicationId appId = coreService.registerApplication(CORDVTN_APP_ID);
+
+ vtnNetworkStore = storageService.<NetworkId, VtnNetwork>consistentMapBuilder()
+ .withSerializer(Serializer.using(SERIALIZER_SERVICE))
+ .withName("cordvtn-vtnnetstore")
+ .withApplicationId(appId)
+ .build();
+ vtnNetworkStore.addListener(vtnNetworkListener);
+
+ vtnPortStore = storageService.<PortId, VtnPort>consistentMapBuilder()
+ .withSerializer(Serializer.using(SERIALIZER_SERVICE))
+ .withName("cordvtn-vtnportstore")
+ .withApplicationId(appId)
+ .build();
+ vtnPortStore.addListener(vtnPortListener);
+
+ networkStore = storageService.<NetworkId, Network>consistentMapBuilder()
+ .withSerializer(Serializer.using(SERIALIZER_NEUTRON))
+ .withName("cordvtn-networkstore")
+ .withApplicationId(appId)
+ .build();
+
+ portStore = storageService.<PortId, Port>consistentMapBuilder()
+ .withSerializer(Serializer.using(SERIALIZER_NEUTRON))
+ .withName("cordvtn-portstore")
+ .withApplicationId(appId)
+ .build();
+
+ subnetStore = storageService.<SubnetId, Subnet>consistentMapBuilder()
+ .withSerializer(Serializer.using(SERIALIZER_NEUTRON))
+ .withName("cordvtn-subnetstore")
+ .withApplicationId(appId)
+ .build();
+
log.info("Started");
}
@Deactivate
protected void deactivate() {
+ vtnNetworkStore.removeListener(vtnNetworkListener);
+ vtnPortStore.removeListener(vtnPortListener);
+
log.info("Stopped");
}
@Override
- public void createServiceNetwork(ServiceNetwork serviceNet) {
- // TODO implement
- log.info(String.format(MSG_SERVICE_NET, CREATED, serviceNet));
+ public void createVtnNetwork(VtnNetwork vtnNet) {
+ vtnNetworkStore.compute(vtnNet.id(), (id, existing) -> {
+ final String error = ERR_SYNC + vtnNet.id().id() + ERR_DUPLICATE;
+ checkArgument(existing == null || existing.equals(vtnNet), error);
+ return vtnNet;
+ });
}
@Override
- public void updateServiceNetwork(ServiceNetwork serviceNet) {
- // TODO implement
- log.info(String.format(MSG_SERVICE_NET, UPDATED, serviceNet));
+ public void updateVtnNetwork(VtnNetwork vtnNet) {
+ vtnNetworkStore.compute(vtnNet.id(), (id, existing) -> {
+ final String error = ERR_SYNC + vtnNet.id().id() + ERR_NOT_FOUND;
+ checkArgument(existing != null, ERR_SYNC + error);
+ return vtnNet;
+ });
}
@Override
- public ServiceNetwork getServiceNetwork(NetworkId netId) {
- // TODO implement
- return null;
+ public void removeVtnNetwork(NetworkId netId) {
+ synchronized (this) {
+ // remove any dependencies that this network involved in
+ vtnNetworkStore.computeIfPresent(netId, (id, existing) ->
+ VtnNetwork.builder(existing)
+ .providers(ImmutableSet.of()).build()
+ );
+ getSubscribers(netId).stream().forEach(subs ->
+ vtnNetworkStore.computeIfPresent(subs.id(), (id, existing) ->
+ VtnNetwork.builder(existing)
+ .delProvider(netId).build())
+ );
+ vtnNetworkStore.remove(netId);
+ }
}
@Override
- public Set<ServiceNetwork> getServiceNetworks() {
- // TODO implement
- return null;
+ public VtnNetwork getVtnNetwork(NetworkId netId) {
+ Versioned<VtnNetwork> versioned = vtnNetworkStore.get(netId);
+ return versioned == null ? null : versioned.value();
}
@Override
- public void removeServiceNetwork(NetworkId netId) {
- // TODO implement
- log.info(String.format(MSG_SERVICE_NET, REMOVED, netId));
+ public Set<VtnNetwork> getVtnNetworks() {
+ return vtnNetworkStore.values().stream().map(Versioned::value)
+ .collect(Collectors.toSet());
}
@Override
- public void createServicePort(ServicePort servicePort) {
- // TODO implement
- log.info(String.format(MSG_SERVICE_PORT, CREATED, servicePort));
+ public void createVtnPort(VtnPort vtnPort) {
+ vtnPortStore.compute(vtnPort.id(), (id, existing) -> {
+ final String error = ERR_SYNC + vtnPort.id().id() + ERR_DUPLICATE;
+ checkArgument(existing == null || existing.equals(vtnPort), error);
+ return vtnPort;
+ });
}
@Override
- public ServicePort getServicePort(PortId portId) {
- // TODO implement
- return null;
+ public void updateVtnPort(VtnPort vtnPort) {
+ vtnPortStore.compute(vtnPort.id(), (id, existing) -> {
+ final String error = ERR_SYNC + vtnPort.id().id() + ERR_NOT_FOUND;
+ checkArgument(existing != null, ERR_SYNC + error);
+ return vtnPort;
+ });
}
@Override
- public Set<ServicePort> getServicePorts() {
- // TODO implement
- return null;
+ public void removeVtnPort(PortId portId) {
+ vtnPortStore.remove(portId);
}
@Override
- public void removeServicePort(PortId portId) {
- // TODO implement
- log.info(String.format(MSG_SERVICE_PORT, REMOVED, portId));
+ public VtnPort getVtnPort(PortId portId) {
+ Versioned<VtnPort> versioned = vtnPortStore.get(portId);
+ return versioned == null ? null : versioned.value();
+ }
+
+ @Override
+ public Set<VtnPort> getVtnPorts() {
+ return vtnPortStore.values().stream().map(Versioned::value)
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public void createNetwork(Network net) {
+ networkStore.compute(NetworkId.of(net.getId()), (id, existing) -> {
+ final String error = ERR_SYNC + net.getId() + ERR_DUPLICATE;
+ checkArgument(existing == null || net.equals(existing), error);
+ return net;
+ });
+ }
+
+ @Override
+ public void updateNetwork(Network net) {
+ networkStore.compute(NetworkId.of(net.getId()), (id, existing) -> {
+ final String error = ERR_SYNC + net.getId() + ERR_NOT_FOUND;
+ checkArgument(existing != null, ERR_SYNC + error);
+ return net;
+ });
+ }
+
+ @Override
+ public void removeNetwork(NetworkId netId) {
+ networkStore.remove(netId);
+ }
+
+ @Override
+ public Network getNetwork(NetworkId netId) {
+ Versioned<Network> versioned = networkStore.get(netId);
+ return versioned == null ? null : versioned.value();
+ }
+
+ @Override
+ public Set<Network> getNetworks() {
+ return networkStore.values().stream().map(Versioned::value)
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public void createPort(Port port) {
+ portStore.compute(PortId.of(port.getId()), (id, existing) -> {
+ final String error = ERR_SYNC + port.getId() + ERR_DUPLICATE;
+ checkArgument(existing == null || port.equals(existing), error);
+ return port;
+ });
+ }
+
+ @Override
+ public void updatePort(Port port) {
+ portStore.compute(PortId.of(port.getId()), (id, existing) -> {
+ final String error = ERR_SYNC + port.getId() + ERR_NOT_FOUND;
+ checkArgument(existing != null, ERR_SYNC + error);
+ return port;
+ });
+ }
+
+ @Override
+ public void removePort(PortId portId) {
+ portStore.remove(portId);
+ }
+
+ @Override
+ public Port getPort(PortId portId) {
+ Versioned<Port> versioned = portStore.get(portId);
+ return versioned == null ? null : versioned.value();
+ }
+
+ @Override
+ public Set<Port> getPorts() {
+ return portStore.values().stream().map(Versioned::value)
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public void createSubnet(Subnet subnet) {
+ subnetStore.compute(SubnetId.of(subnet.getId()), (id, existing) -> {
+ final String error = ERR_SYNC + subnet.getId() + ERR_DUPLICATE;
+ checkArgument(existing == null || subnet.equals(existing), error);
+ return subnet;
+ });
+ }
+
+ @Override
+ public void updateSubnet(Subnet subnet) {
+ subnetStore.compute(SubnetId.of(subnet.getId()), (id, existing) -> {
+ final String error = ERR_SYNC + subnet.getId() + ERR_NOT_FOUND;
+ checkArgument(existing != null, ERR_SYNC + error);
+ return subnet;
+ });
+ }
+
+ @Override
+ public void removeSubnet(SubnetId subnetId) {
+ subnetStore.remove(subnetId);
+ }
+
+ @Override
+ public Subnet getSubnet(SubnetId subnetId) {
+ Versioned<Subnet> versioned = subnetStore.get(subnetId);
+ return versioned == null ? null : versioned.value();
+ }
+
+ @Override
+ public Set<Subnet> getSubnets() {
+ return subnetStore.values().stream().map(Versioned::value)
+ .collect(Collectors.toSet());
+ }
+
+ private Set<VtnNetwork> getSubscribers(NetworkId netId) {
+ return getVtnNetworks().stream().filter(net -> net.isProvider(netId))
+ .collect(Collectors.toSet());
+ }
+
+ private class VtnNetworkMapListener implements MapEventListener<NetworkId, VtnNetwork> {
+
+ @Override
+ public void event(MapEvent<NetworkId, VtnNetwork> event) {
+ switch (event.type()) {
+ case UPDATE:
+ log.debug("VTN network updated {}", event.newValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new VtnNetworkEvent(
+ VTN_NETWORK_UPDATED,
+ event.newValue().value()));
+ });
+ break;
+ case INSERT:
+ log.debug("VTN network created {}", event.newValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new VtnNetworkEvent(
+ VTN_NETWORK_CREATED,
+ event.newValue().value()));
+ });
+ break;
+ case REMOVE:
+ log.debug("VTN network removed {}", event.oldValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new VtnNetworkEvent(
+ VTN_NETWORK_REMOVED,
+ event.oldValue().value()));
+ });
+ break;
+ default:
+ log.error("Unsupported event type");
+ break;
+ }
+ }
+ }
+
+ private class VtnPortMapListener implements MapEventListener<PortId, VtnPort> {
+
+ @Override
+ public void event(MapEvent<PortId, VtnPort> event) {
+ switch (event.type()) {
+ case UPDATE:
+ log.debug("VTN port updated {}", event.newValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new VtnNetworkEvent(
+ VTN_PORT_UPDATED,
+ getVtnNetwork(event.newValue().value().netId()),
+ event.newValue().value()));
+ });
+ break;
+ case INSERT:
+ log.debug("VTN port created {}", event.newValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new VtnNetworkEvent(
+ VTN_PORT_CREATED,
+ getVtnNetwork(event.newValue().value().netId()),
+ event.newValue().value()));
+ });
+ break;
+ case REMOVE:
+ log.debug("VTN port removed {}", event.oldValue());
+ eventExecutor.execute(() -> {
+ notifyDelegate(new VtnNetworkEvent(
+ VTN_PORT_REMOVED,
+ getVtnNetwork(event.oldValue().value().netId()),
+ event.oldValue().value()));
+ });
+ break;
+ default:
+ log.error("Unsupported event type");
+ break;
+ }
+ }
}
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java b/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java
index b02fb52..ba35d9b 100644
--- a/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java
+++ b/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java
@@ -25,9 +25,12 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
import org.opencord.cordconfig.CordConfigService;
import org.opencord.cordconfig.access.AccessAgentData;
-import org.opencord.cordvtn.api.CordVtnConfig;
+import org.opencord.cordvtn.api.CordVtnService;
import org.opencord.cordvtn.api.Instance;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
@@ -39,11 +42,6 @@
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Port;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostDescription;
@@ -53,29 +51,27 @@
import org.onosproject.net.host.HostService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
-import org.onosproject.xosclient.api.OpenStackAccess;
-import org.onosproject.xosclient.api.VtnPort;
-import org.onosproject.xosclient.api.VtnPortApi;
-import org.onosproject.xosclient.api.VtnService;
-import org.onosproject.xosclient.api.VtnServiceApi;
-import org.onosproject.xosclient.api.VtnServiceId;
-import org.onosproject.xosclient.api.XosAccess;
-import org.onosproject.xosclient.api.XosClientService;
import org.opencord.cordvtn.api.InstanceService;
+import org.opencord.cordvtn.api.PortId;
+import org.opencord.cordvtn.api.VtnNetwork;
+import org.opencord.cordvtn.api.VtnNetworkEvent;
+import org.opencord.cordvtn.api.VtnNetworkListener;
+import org.opencord.cordvtn.api.VtnPort;
import org.slf4j.Logger;
import java.util.Date;
+import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
-import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.ACCESS_AGENT;
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.MANAGEMENT;
import static org.opencord.cordvtn.api.Constants.*;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.ACCESS_AGENT;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.MANAGEMENT_HOST;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.MANAGEMENT_LOCAL;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -87,14 +83,13 @@
InstanceService {
protected final Logger log = getLogger(getClass());
+ private static final String ERR_VTN_NETWORK = "Faild to get VTN network for %s";
+ private static final String ERR_VTN_PORT = "Faild to get VTN port for %s";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected NetworkConfigRegistry configRegistry;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostProviderRegistry hostProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -104,33 +99,28 @@
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DhcpService dhcpService;
+ protected LeadershipService leadershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected XosClientService xosClient;
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DhcpService dhcpService;
// TODO get access agent container information from XOS
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordConfigService cordConfig;
- private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
- private final ConfigFactory configFactory =
- new ConfigFactory<ApplicationId, CordVtnConfig>(
- SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "cordvtn") {
- @Override
- public CordVtnConfig createConfig() {
- return new CordVtnConfig();
- }
- };
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnService vtnService;
private final ExecutorService eventExecutor =
newSingleThreadExecutor(groupedThreads(this.getClass().getSimpleName(), "event-handler"));
- private final NetworkConfigListener configListener = new InternalConfigListener();
+ private final VtnNetworkListener vtnNetListener = new InternalVtnNetworkListener();
private ApplicationId appId;
+ private NodeId localNodeId;
private HostProviderService hostProvider;
- private XosAccess xosAccess = null;
- private OpenStackAccess osAccess = null;
/**
* Creates an cordvtn host location provider.
@@ -142,22 +132,22 @@
@Activate
protected void activate() {
appId = coreService.registerApplication(CORDVTN_APP_ID);
+ localNodeId = clusterService.getLocalNode().id();
+ leadershipService.runForLeadership(appId.name());
hostProvider = hostProviderRegistry.register(this);
- configRegistry.registerConfigFactory(configFactory);
- configRegistry.addListener(configListener);
+ vtnService.addListener(vtnNetListener);
log.info("Started");
}
@Deactivate
protected void deactivate() {
+ vtnService.removeListener(vtnNetListener);
hostProviderRegistry.unregister(this);
-
- configRegistry.unregisterConfigFactory(configFactory);
- configRegistry.removeListener(configListener);
-
eventExecutor.shutdown();
+ leadershipService.withdraw(appId.name());
+
log.info("Stopped");
}
@@ -184,24 +174,26 @@
return;
}
- VtnPort vtnPort = getVtnPort(port.annotations().value(PORT_NAME));
+ VtnPort vtnPort = vtnService.getVtnPort(port.annotations().value(PORT_NAME));
if (vtnPort == null) {
+ log.warn(String.format(ERR_VTN_PORT, port));
return;
}
- VtnService vtnService = getVtnService(vtnPort.serviceId());
- if (vtnService == null) {
+ VtnNetwork vtnNet = vtnService.getVtnNetworkOrDefault(vtnPort.netId());
+ if (vtnNet == null) {
+ log.warn(String.format(ERR_VTN_NETWORK, vtnPort));
return;
}
// register DHCP lease for the new instance
- registerDhcpLease(vtnPort.mac(), vtnPort.ip().getIp4Address(), vtnService);
+ registerDhcpLease(vtnPort.mac(), vtnPort.ip().getIp4Address(), vtnNet);
// Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
// existing instances.
DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
- .set(Instance.SERVICE_TYPE, vtnService.serviceType().toString())
- .set(Instance.SERVICE_ID, vtnPort.serviceId().id())
+ .set(Instance.NETWORK_TYPE, vtnNet.type().name())
+ .set(Instance.NETWORK_ID, vtnNet.id().id())
.set(Instance.PORT_ID, vtnPort.id().id())
.set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
@@ -247,54 +239,28 @@
hostProvider.hostVanished(hostId);
}
- private void registerDhcpLease(MacAddress macAddr, Ip4Address ipAddr, VtnService service) {
+ private void registerDhcpLease(MacAddress macAddr, Ip4Address ipAddr, VtnNetwork vtnNet) {
Ip4Address broadcast = Ip4Address.makeMaskedAddress(
ipAddr,
- service.subnet().prefixLength());
+ vtnNet.subnet().prefixLength());
IpAssignment.Builder ipBuilder = IpAssignment.builder()
.ipAddress(ipAddr)
.leasePeriod(DHCP_INFINITE_LEASE)
.timestamp(new Date())
- .subnetMask(Ip4Address.makeMaskPrefix(service.subnet().prefixLength()))
+ .subnetMask(Ip4Address.makeMaskPrefix(vtnNet.subnet().prefixLength()))
.broadcast(broadcast)
.domainServer(DEFAULT_DNS)
.assignmentStatus(Option_RangeNotEnforced);
- if (service.serviceType() != MANAGEMENT) {
- ipBuilder = ipBuilder.routerAddress(service.serviceIp().getIp4Address());
+ if (vtnNet.type() != MANAGEMENT_HOST && vtnNet.type() != MANAGEMENT_LOCAL) {
+ ipBuilder = ipBuilder.routerAddress(vtnNet.serviceIp().getIp4Address());
}
log.debug("Set static DHCP mapping for {} {}", macAddr, ipAddr);
dhcpService.setStaticMapping(macAddr, ipBuilder.build());
}
- private VtnService getVtnService(VtnServiceId serviceId) {
- checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
- checkNotNull(xosAccess, ERROR_XOS_ACCESS);
-
- // TODO remove openstack access when XOS provides all information
- VtnServiceApi serviceApi = xosClient.getClient(xosAccess).vtnService();
- VtnService service = serviceApi.service(serviceId, osAccess);
- if (service == null) {
- log.warn("Failed to get VtnService for {}", serviceId);
- }
- return service;
- }
-
- private VtnPort getVtnPort(String portName) {
- checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
- checkNotNull(xosAccess, ERROR_XOS_ACCESS);
-
- // TODO remove openstack access when XOS provides all information
- VtnPortApi portApi = xosClient.getClient(xosAccess).vtnPort();
- VtnPort vtnPort = portApi.vtnPort(portName, osAccess);
- if (vtnPort == null) {
- log.warn("Failed to get port information of {}", portName);
- }
- return vtnPort;
- }
-
// TODO remove this when XOS provides access agent information
private boolean isAccessAgent(ConnectPoint connectPoint) {
Optional<AccessAgentData> agent = cordConfig.getAccessAgent(connectPoint.deviceId());
@@ -308,8 +274,8 @@
private void addAccessAgentInstance(ConnectPoint connectPoint) {
AccessAgentData agent = cordConfig.getAccessAgent(connectPoint.deviceId()).get();
DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
- .set(Instance.SERVICE_TYPE, ACCESS_AGENT.name())
- .set(Instance.SERVICE_ID, NOT_APPLICABLE)
+ .set(Instance.NETWORK_TYPE, ACCESS_AGENT.name())
+ .set(Instance.NETWORK_ID, NOT_APPLICABLE)
.set(Instance.PORT_ID, NOT_APPLICABLE)
.set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
@@ -324,32 +290,34 @@
hostProvider.hostDetected(hostId, hostDesc, false);
}
- private void readConfiguration() {
- CordVtnConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
- if (config == null) {
- log.debug("No configuration found");
- return;
- }
-
- log.info("Load CORD-VTN configurations");
- xosAccess = config.xosAccess();
- osAccess = config.openstackAccess();
- }
-
- private class InternalConfigListener implements NetworkConfigListener {
+ private class InternalVtnNetworkListener implements VtnNetworkListener {
@Override
- public void event(NetworkConfigEvent event) {
- if (!event.configClass().equals(CONFIG_CLASS)) {
+ public void event(VtnNetworkEvent event) {
+ NodeId leader = leadershipService.getLeader(appId.name());
+ if (!Objects.equals(localNodeId, leader)) {
+ // do not allow to proceed without leadership
return;
}
switch (event.type()) {
- case CONFIG_UPDATED:
- case CONFIG_ADDED:
- readConfiguration();
+ case VTN_PORT_CREATED:
+ case VTN_PORT_UPDATED:
+ log.debug("Processing service port {}", event.vtnPort());
+ PortId portId = event.vtnPort().id();
+ eventExecutor.execute(() -> {
+ Instance instance = vtnService.getInstance(portId);
+ if (instance != null) {
+ addInstance(instance.host().location());
+ }
+ });
break;
+ case VTN_PORT_REMOVED:
+ case VTN_NETWORK_CREATED:
+ case VTN_NETWORK_UPDATED:
+ case VTN_NETWORK_REMOVED:
default:
+ // do nothing for the other events
break;
}
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/handler/AbstractInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/handler/AbstractInstanceHandler.java
new file mode 100644
index 0000000..b75051f
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/impl/handler/AbstractInstanceHandler.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.impl.handler;
+
+import com.google.common.collect.ImmutableSet;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.Host;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.opencord.cordvtn.api.Constants;
+import org.opencord.cordvtn.api.CordVtnService;
+import org.opencord.cordvtn.api.Instance;
+import org.opencord.cordvtn.api.InstanceHandler;
+import org.opencord.cordvtn.api.NetworkId;
+import org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType;
+import org.opencord.cordvtn.api.VtnNetwork;
+import org.opencord.cordvtn.api.VtnPort;
+import org.slf4j.Logger;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides default virtual network connectivity for service instances.
+ */
+public abstract class AbstractInstanceHandler implements InstanceHandler {
+
+ protected final Logger log = getLogger(getClass());
+
+ protected static final String ERR_VTN_NETWORK = "Failed to get VTN network for %s";
+ protected static final String ERR_VTN_PORT = "Failed to get VTN port for %s";
+
+ protected CoreService coreService;
+ protected MastershipService mastershipService;
+ protected HostService hostService;
+ protected CordVtnService vtnService;
+ protected ApplicationId appId;
+ protected Set<ServiceNetworkType> netTypes = ImmutableSet.of();
+
+ protected HostListener hostListener = new InternalHostListener();
+
+ protected final ExecutorService eventExecutor = newSingleThreadExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+
+ protected void activate() {
+ ServiceDirectory services = new DefaultServiceDirectory();
+ coreService = services.get(CoreService.class);
+ mastershipService = services.get(MastershipService.class);
+ hostService = services.get(HostService.class);
+ vtnService = services.get(CordVtnService.class);
+
+ appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
+ hostService.addListener(hostListener);
+
+ log.info("Started");
+ }
+
+ protected void deactivate() {
+ hostService.removeListener(hostListener);
+ eventExecutor.shutdown();
+
+ log.info("Stopped");
+ }
+
+ @Override
+ public void instanceUpdated(Instance instance) {
+ instanceDetected(instance);
+ }
+
+ protected Set<Instance> getInstances(NetworkId netId) {
+ return StreamSupport.stream(hostService.getHosts().spliterator(), false)
+ .filter(host -> Objects.equals(
+ netId.id(),
+ host.annotations().value(Instance.NETWORK_ID)))
+ .map(Instance::of)
+ .collect(Collectors.toSet());
+ }
+
+ protected VtnNetwork getVtnNetwork(Instance instance) {
+ VtnNetwork vtnNet = vtnService.getVtnNetworkOrDefault(instance.netId());
+ if (vtnNet == null) {
+ final String error = String.format(ERR_VTN_NETWORK, instance);
+ throw new IllegalStateException(error);
+ }
+ return vtnNet;
+ }
+
+ protected VtnPort getVtnPort(Instance instance) {
+ VtnPort vtnPort = vtnService.getVtnPortOrDefault(instance.portId());
+ if (vtnPort == null) {
+ final String error = String.format(ERR_VTN_PORT, instance);
+ throw new IllegalStateException(error);
+ }
+ return vtnPort;
+ }
+
+ private class InternalHostListener implements HostListener {
+
+ @Override
+ public void event(HostEvent event) {
+ Host host = event.subject();
+ if (!mastershipService.isLocalMaster(host.location().deviceId())) {
+ // do not allow to proceed without mastership
+ return;
+ }
+
+ Instance instance = Instance.of(host);
+ if (!netTypes.isEmpty() && !netTypes.contains(instance.netType())) {
+ // not my service network instance, do nothing
+ return;
+ }
+
+ switch (event.type()) {
+ case HOST_UPDATED:
+ eventExecutor.execute(() -> instanceUpdated(instance));
+ break;
+ case HOST_ADDED:
+ eventExecutor.execute(() -> instanceDetected(instance));
+ break;
+ case HOST_REMOVED:
+ eventExecutor.execute(() -> instanceRemoved(instance));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/impl/handler/AccessAgentInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/handler/AccessAgentInstanceHandler.java
index b2de2c3..8a818b8 100644
--- a/src/main/java/org/opencord/cordvtn/impl/handler/AccessAgentInstanceHandler.java
+++ b/src/main/java/org/opencord/cordvtn/impl/handler/AccessAgentInstanceHandler.java
@@ -15,6 +15,7 @@
*/
package org.opencord.cordvtn.impl.handler;
+import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -27,15 +28,12 @@
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
-import org.opencord.cordvtn.impl.AbstractInstanceHandler;
import org.opencord.cordvtn.api.Instance;
import org.opencord.cordvtn.api.InstanceHandler;
import org.opencord.cordvtn.impl.CordVtnNodeManager;
import org.opencord.cordvtn.impl.CordVtnPipeline;
-import java.util.Optional;
-
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.ACCESS_AGENT;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.ACCESS_AGENT;
/**
* Provides network connectivity for access agent instances.
@@ -51,7 +49,7 @@
@Activate
protected void activate() {
- serviceType = Optional.of(ACCESS_AGENT);
+ netTypes = ImmutableSet.of(ACCESS_AGENT);
super.activate();
}
@@ -63,16 +61,16 @@
@Override
public void instanceDetected(Instance instance) {
log.info("Access agent instance detected {}", instance);
- accessAgentRules(instance, true);
+ populateAccessAgentRules(instance, true);
}
@Override
public void instanceRemoved(Instance instance) {
log.info("Access agent instance removed {}", instance);
- accessAgentRules(instance, false);
+ populateAccessAgentRules(instance, false);
}
- private void accessAgentRules(Instance instance, boolean install) {
+ private void populateAccessAgentRules(Instance instance, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthDst(instance.mac())
.build();
diff --git a/src/main/java/org/opencord/cordvtn/impl/handler/DefaultInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/handler/DefaultInstanceHandler.java
index 0036578..ce3de31 100644
--- a/src/main/java/org/opencord/cordvtn/impl/handler/DefaultInstanceHandler.java
+++ b/src/main/java/org/opencord/cordvtn/impl/handler/DefaultInstanceHandler.java
@@ -15,6 +15,7 @@
*/
package org.opencord.cordvtn.impl.handler;
+import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -31,17 +32,15 @@
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
-import org.opencord.cordvtn.impl.AbstractInstanceHandler;
+import org.opencord.cordvtn.api.VtnNetwork;
import org.opencord.cordvtn.api.CordVtnNode;
import org.opencord.cordvtn.api.Instance;
import org.opencord.cordvtn.api.InstanceHandler;
-import org.onosproject.xosclient.api.VtnService;
import org.opencord.cordvtn.impl.CordVtnNodeManager;
import org.opencord.cordvtn.impl.CordVtnPipeline;
-import java.util.Optional;
-
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.DEFAULT;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.PRIVATE;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.PUBLIC;
/**
* Provides network connectivity for default service instances.
@@ -57,7 +56,7 @@
@Activate
protected void activate() {
- serviceType = Optional.of(DEFAULT);
+ netTypes = ImmutableSet.of(PRIVATE, PUBLIC);
super.activate();
}
@@ -70,44 +69,36 @@
public void instanceDetected(Instance instance) {
log.info("Instance is detected {}", instance);
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- log.warn("Failed to get VtnService for {}", instance);
- return;
- }
- defaultConnectionRules(instance, service, true);
+ VtnNetwork vtnNet = getVtnNetwork(instance);
+ populateDefaultRules(instance, vtnNet, true);
}
@Override
public void instanceRemoved(Instance instance) {
log.info("Instance is removed {}", instance);
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- log.warn("Failed to get VtnService for {}", instance);
- return;
- }
- defaultConnectionRules(instance, service, false);
+ VtnNetwork vtnNet = getVtnNetwork(instance);
+ populateDefaultRules(instance, vtnNet, false);
}
- private void defaultConnectionRules(Instance instance, VtnService service, boolean install) {
- long vni = service.vni();
- Ip4Prefix serviceIpRange = service.subnet().getIp4Prefix();
+ private void populateDefaultRules(Instance instance, VtnNetwork vtnNet, boolean install) {
+ long vni = vtnNet.segmentId().id();
+ Ip4Prefix serviceIpRange = vtnNet.subnet().getIp4Prefix();
- inPortRule(instance, install);
- dstIpRule(instance, vni, install);
- tunnelInRule(instance, vni, install);
+ populateInPortRule(instance, install);
+ populateDstIpRule(instance, vni, install);
+ populateTunnelInRule(instance, vni, install);
if (install) {
- directAccessRule(serviceIpRange, serviceIpRange, true);
- serviceIsolationRule(serviceIpRange, true);
- } else if (getInstances(service.id()).isEmpty()) {
- directAccessRule(serviceIpRange, serviceIpRange, false);
- serviceIsolationRule(serviceIpRange, false);
+ populateDirectAccessRule(serviceIpRange, serviceIpRange, true);
+ populateServiceIsolationRule(serviceIpRange, true);
+ } else if (getInstances(vtnNet.id()).isEmpty()) {
+ populateDirectAccessRule(serviceIpRange, serviceIpRange, false);
+ populateServiceIsolationRule(serviceIpRange, false);
}
}
- private void inPortRule(Instance instance, boolean install) {
+ private void populateInPortRule(Instance instance, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchInPort(instance.portNumber())
.matchEthType(Ethernet.TYPE_IPV4)
@@ -151,7 +142,7 @@
pipeline.processFlowRule(install, flowRule);
}
- private void dstIpRule(Instance instance, long vni, boolean install) {
+ private void populateDstIpRule(Instance instance, long vni, boolean install) {
Ip4Address tunnelIp = nodeManager.dataIp(instance.deviceId()).getIp4Address();
TrafficSelector selector = DefaultTrafficSelector.builder()
@@ -208,7 +199,7 @@
}
}
- private void tunnelInRule(Instance instance, long vni, boolean install) {
+ private void populateTunnelInRule(Instance instance, long vni, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchTunnelId(vni)
.matchEthDst(instance.mac())
@@ -231,7 +222,7 @@
pipeline.processFlowRule(install, flowRule);
}
- private void directAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange, boolean install) {
+ private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPSrc(srcRange)
@@ -258,7 +249,7 @@
});
}
- private void serviceIsolationRule(Ip4Prefix dstRange, boolean install) {
+ private void populateServiceIsolationRule(Ip4Prefix dstRange, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(dstRange)
diff --git a/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java
index 7e0285e..496ed66 100644
--- a/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java
+++ b/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java
@@ -15,6 +15,7 @@
*/
package org.opencord.cordvtn.impl.handler;
+import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -28,19 +29,18 @@
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.xosclient.api.VtnService;
-import org.opencord.cordvtn.impl.AbstractInstanceHandler;
import org.opencord.cordvtn.api.Instance;
import org.opencord.cordvtn.api.InstanceHandler;
+import org.opencord.cordvtn.api.VtnNetwork;
import org.opencord.cordvtn.impl.CordVtnNodeManager;
import org.opencord.cordvtn.impl.CordVtnPipeline;
-import java.util.Optional;
-
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.MANAGEMENT;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.MANAGEMENT_HOST;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.MANAGEMENT_LOCAL;
/**
- * Provides network connectivity for management network connected instances.
+ * Provides local management network connectivity to the instance. The instance
+ * is only accessible via local management network from the host machine.
*/
@Component(immediate = true)
public class ManagementInstanceHandler extends AbstractInstanceHandler implements InstanceHandler {
@@ -53,7 +53,7 @@
@Activate
protected void activate() {
- serviceType = Optional.of(MANAGEMENT);
+ netTypes = ImmutableSet.of(MANAGEMENT_LOCAL, MANAGEMENT_HOST);
super.activate();
}
@@ -64,20 +64,16 @@
@Override
public void instanceDetected(Instance instance) {
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- log.warn("Failed to get VtnService for {}", instance);
- return;
- }
+ VtnNetwork vtnNet = getVtnNetwork(instance);
- switch (service.networkType()) {
+ switch (vtnNet.type()) {
case MANAGEMENT_LOCAL:
log.info("LOCAL management instance is detected {}", instance);
- localManagementRules(instance, true);
+ populateLocalManagementRules(instance, true);
break;
- case MANAGEMENT_HOSTS:
+ case MANAGEMENT_HOST:
log.info("HOSTS management instance is detected {}", instance);
- hostsManagementRules(instance, true);
+ populateHostsManagementRules(instance, true);
break;
default:
break;
@@ -86,27 +82,23 @@
@Override
public void instanceRemoved(Instance instance) {
- VtnService service = getVtnService(instance.serviceId());
- if (service == null) {
- log.warn("Failed to get VtnService for {}", instance);
- return;
- }
+ VtnNetwork vtnNet = getVtnNetwork(instance);
- switch (service.networkType()) {
+ switch (vtnNet.type()) {
case MANAGEMENT_LOCAL:
log.info("LOCAL management instance removed {}", instance);
- localManagementRules(instance, false);
+ populateLocalManagementRules(instance, false);
break;
- case MANAGEMENT_HOSTS:
+ case MANAGEMENT_HOST:
log.info("HOSTS management instance removed {}", instance);
- hostsManagementRules(instance, false);
+ populateHostsManagementRules(instance, false);
break;
default:
break;
}
}
- private void localManagementRules(Instance instance, boolean install) {
+ private void populateLocalManagementRules(Instance instance, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(instance.ipAddress().toIpPrefix())
@@ -130,7 +122,7 @@
pipeline.processFlowRule(install, flowRule);
}
- private void hostsManagementRules(Instance instance, boolean install) {
+ private void populateHostsManagementRules(Instance instance, boolean install) {
PortNumber hostMgmtPort = nodeManager.hostManagementPort(instance.deviceId());
if (hostMgmtPort == null) {
log.warn("Can not find host management port in {}", instance.deviceId());
diff --git a/src/main/java/org/opencord/cordvtn/impl/handler/VsgInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/handler/VsgInstanceHandler.java
index 298d60a..27ea199 100644
--- a/src/main/java/org/opencord/cordvtn/impl/handler/VsgInstanceHandler.java
+++ b/src/main/java/org/opencord/cordvtn/impl/handler/VsgInstanceHandler.java
@@ -16,20 +16,21 @@
package org.opencord.cordvtn.impl.handler;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
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.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import org.onosproject.net.Host;
+import org.opencord.cordvtn.api.AddressPair;
import org.opencord.cordvtn.api.InstanceService;
-import org.opencord.cordvtn.impl.AbstractInstanceHandler;
import org.opencord.cordvtn.api.Instance;
import org.opencord.cordvtn.api.InstanceHandler;
import org.onosproject.net.DefaultAnnotations;
@@ -49,35 +50,37 @@
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostDescription;
-import org.onosproject.xosclient.api.VtnPort;
+import org.opencord.cordvtn.api.VtnPort;
import org.opencord.cordvtn.impl.CordVtnNodeManager;
import org.opencord.cordvtn.impl.CordVtnPipeline;
-import java.util.Map;
-import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
-import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
-import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.VSG;
+import static org.opencord.cordvtn.api.ServiceNetwork.ServiceNetworkType.VSG;
/**
* Provides network connectivity for vSG instances.
*/
@Component(immediate = true)
-@Service(value = VsgInstanceHandler.class)
public final class VsgInstanceHandler extends AbstractInstanceHandler implements InstanceHandler {
+ private static final String STAG = "stag";
+ private static final String VSG_VM = "vsgVm";
+ private static final String ERR_VSG_VM = "vSG VM does not exist for %s";
+ private static final String MSG_VSG_VM = "vSG VM %s: %s";
+ private static final String MSG_VSG_CONTAINER = "vSG container %s: %s";
+ private static final String MSG_DETECTED = "detected";
+ private static final String MSG_REMOVED = "removed";
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnPipeline pipeline;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnNodeManager nodeManager;
- private static final String STAG = "stag";
- private static final String VSG_VM = "vsgVm";
-
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@@ -86,7 +89,7 @@
@Activate
protected void activate() {
- serviceType = Optional.of(VSG);
+ netTypes = ImmutableSet.of(VSG);
super.activate();
}
@@ -98,124 +101,106 @@
@Override
public void instanceDetected(Instance instance) {
if (isVsgContainer(instance)) {
- log.info("vSG container detected {}", instance);
-
- // find vsg vm for this vsg container
- String vsgVmId = instance.getAnnotation(VSG_VM);
- if (Strings.isNullOrEmpty(vsgVmId)) {
- log.warn("Failed to find vSG VM for {}", instance);
- return;
+ log.info(String.format(MSG_VSG_CONTAINER, MSG_DETECTED, instance));
+ Instance vsgVm = getVsgVm(instance);
+ if (vsgVm == null) {
+ final String error = String.format(ERR_VSG_VM, instance);
+ throw new IllegalStateException(error);
}
- Instance vsgVm = Instance.of(hostService.getHost(HostId.hostId(vsgVmId)));
VtnPort vtnPort = getVtnPort(vsgVm);
- if (vtnPort == null || getStag(vtnPort) == null) {
- log.warn("Failed to get vSG information {}", vsgVm);
- return;
- }
- populateVsgRules(vsgVm, getStag(vtnPort),
- nodeManager.dataPort(vsgVm.deviceId()),
- vtnPort.addressPairs().keySet(),
- true);
-
+ Set<IpAddress> wanIps = vtnPort.addressPairs().stream()
+ .map(AddressPair::ip).collect(Collectors.toSet());
+ populateVsgRules(
+ vsgVm, vtnPort.vlanId().get(),
+ nodeManager.dataPort(vsgVm.deviceId()),
+ wanIps, true);
} else {
- VtnPort vtnPort = getVtnPort(instance);
- if (vtnPort == null || getStag(vtnPort) == null) {
+ log.info(String.format(MSG_VSG_VM, MSG_DETECTED, instance));
+ VtnPort vtnPort = vtnService.getVtnPortOrDefault(instance.portId());
+ if (vtnPort == null || !vtnPort.vlanId().isPresent()) {
+ // service port can be updated after instance is created
return;
}
- log.info("vSG VM detected {}", instance);
// insert vSG containers inside the vSG VM as a host
- vtnPort.addressPairs().entrySet().stream()
- .forEach(pair -> addVsgContainer(
- instance,
- pair.getKey(),
- pair.getValue(),
- getStag(vtnPort).toString()
- ));
+ vtnPort.addressPairs().stream().forEach(pair -> addVsgContainer(
+ instance,
+ pair.ip(),
+ pair.mac(),
+ vtnPort.vlanId().get()));
}
}
@Override
- public void instanceRemoved(Instance instance) {
+ public void instanceUpdated(Instance instance) {
if (!isVsgContainer(instance)) {
- // nothing to do for the vSG VM itself
- return;
+ Set<MacAddress> vsgMacs = getVtnPort(instance).addressPairs().stream()
+ .map(AddressPair::mac)
+ .collect(Collectors.toSet());
+ hostService.getConnectedHosts(instance.host().location()).stream()
+ .filter(h -> !h.mac().equals(instance.mac()))
+ .filter(h -> !vsgMacs.contains(h.mac()))
+ .forEach(h -> instanceService.removeNestedInstance(h.id()));
}
-
- log.info("vSG container vanished {}", instance);
-
- // find vsg vm for this vsg container
- String vsgVmId = instance.getAnnotation(VSG_VM);
- if (Strings.isNullOrEmpty(vsgVmId)) {
- log.warn("Failed to find vSG VM for {}", instance);
- return;
- }
-
- Instance vsgVm = Instance.of(hostService.getHost(HostId.hostId(vsgVmId)));
- VtnPort vtnPort = getVtnPort(vsgVm);
- if (vtnPort == null || getStag(vtnPort) == null) {
- return;
- }
-
- populateVsgRules(vsgVm, getStag(vtnPort),
- nodeManager.dataPort(vsgVm.deviceId()),
- vtnPort.addressPairs().keySet(),
- false);
+ instanceDetected(instance);
}
- /**
- * Updates set of vSGs in a given vSG VM.
- *
- * @param vsgVmId vsg vm host id
- * @param stag stag
- * @param vsgInstances full set of vsg wan ip and mac address pairs in this vsg vm
- */
- public void updateVsgInstances(HostId vsgVmId, String stag, Map<IpAddress, MacAddress> vsgInstances) {
- if (hostService.getHost(vsgVmId) == null) {
- log.debug("vSG VM {} is not added yet, ignore this update", vsgVmId);
- return;
- }
+ @Override
+ public void instanceRemoved(Instance instance) {
+ boolean isVsgContainer = isVsgContainer(instance);
+ log.info(String.format(
+ isVsgContainer ? MSG_VSG_CONTAINER : MSG_VSG_VM,
+ MSG_REMOVED, instance));
- Instance vsgVm = Instance.of(hostService.getHost(vsgVmId));
+ Instance vsgVm = isVsgContainer ? getVsgVm(instance) : instance;
if (vsgVm == null) {
- log.warn("Failed to find existing vSG VM for STAG: {}", stag);
+ // the rules are removed when VM is removed, do nothing
return;
}
- log.info("Updates vSGs in {} with STAG: {}", vsgVm, stag);
+ VtnPort vtnPort = getVtnPort(instance);
+ Set<IpAddress> wanIps = vtnPort.addressPairs().stream()
+ .map(AddressPair::ip).collect(Collectors.toSet());
+ populateVsgRules(
+ vsgVm, vtnPort.vlanId().get(),
+ nodeManager.dataPort(vsgVm.deviceId()),
+ isVsgContainer ? wanIps : ImmutableSet.of(),
+ false);
+ }
- // adds vSGs in the address pair
- vsgInstances.entrySet().stream()
- .filter(addr -> hostService.getHostsByMac(addr.getValue()).isEmpty())
- .forEach(addr -> addVsgContainer(
- vsgVm,
- addr.getKey(),
- addr.getValue(),
- stag));
-
- // removes vSGs not listed in the address pair
- hostService.getConnectedHosts(vsgVm.host().location()).stream()
- .filter(host -> !host.mac().equals(vsgVm.mac()))
- .filter(host -> !vsgInstances.values().contains(host.mac()))
- .forEach(host -> {
- log.info("Removed vSG {}", host.toString());
- instanceService.removeNestedInstance(host.id());
- });
+ @Override
+ protected VtnPort getVtnPort(Instance instance) {
+ VtnPort vtnPort = vtnService.getVtnPortOrDefault(instance.portId());
+ if (vtnPort == null || !vtnPort.vlanId().isPresent()) {
+ final String error = String.format(ERR_VTN_PORT, instance);
+ throw new IllegalStateException(error);
+ }
+ return vtnPort;
}
private boolean isVsgContainer(Instance instance) {
- return !Strings.isNullOrEmpty(instance.host().annotations().value(STAG));
+ return !Strings.isNullOrEmpty(instance.getAnnotation(STAG)) &&
+ !Strings.isNullOrEmpty(instance.getAnnotation(VSG_VM));
+ }
+
+ private Instance getVsgVm(Instance vsgContainer) {
+ String vsgVmId = vsgContainer.getAnnotation(VSG_VM);
+ Host host = hostService.getHost(HostId.hostId(vsgVmId));
+ if (host == null) {
+ return null;
+ }
+ return Instance.of(host);
}
private void addVsgContainer(Instance vsgVm, IpAddress vsgWanIp, MacAddress vsgMac,
- String stag) {
+ VlanId stag) {
HostId hostId = HostId.hostId(vsgMac);
DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
- .set(Instance.SERVICE_TYPE, vsgVm.serviceType().toString())
- .set(Instance.SERVICE_ID, vsgVm.serviceId().id())
+ .set(Instance.NETWORK_TYPE, vsgVm.netType().toString())
+ .set(Instance.NETWORK_ID, vsgVm.netId().id())
.set(Instance.PORT_ID, vsgVm.portId().id())
- .set(STAG, stag)
+ .set(STAG, stag.toString())
.set(VSG_VM, vsgVm.host().id().toString())
.set(Instance.CREATE_TIME, String.valueOf(System.currentTimeMillis()));
@@ -278,10 +263,11 @@
// for traffic coming from WAN, tag 500 and take through the vSG VM
// based on destination ip
- vsgWanIps.stream().forEach(ip -> {
+ vsgWanIps.stream().forEach(wanIp -> {
+ // for traffic coming from WAN, tag 500 and take through the vSG VM
TrafficSelector downstream = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(ip.toIpPrefix())
+ .matchIPDst(wanIp.toIpPrefix())
.build();
TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
@@ -322,18 +308,6 @@
}
}
- // TODO get stag from XOS when XOS provides it, extract if from port name for now
- private VlanId getStag(VtnPort vtnPort) {
- checkNotNull(vtnPort);
-
- String portName = vtnPort.name();
- if (portName != null && portName.startsWith(STAG)) {
- return VlanId.vlanId(portName.split("-")[1]);
- } else {
- return null;
- }
- }
-
private PortNumber getOutputFromTreatment(FlowRule flowRule) {
Instruction instruction = flowRule.treatment().allInstructions().stream()
.filter(inst -> inst instanceof Instructions.OutputInstruction)
@@ -356,11 +330,10 @@
}
private boolean isVlanPushFromTreatment(FlowRule flowRule) {
- Instruction instruction = flowRule.treatment().allInstructions().stream()
+ return flowRule.treatment().allInstructions().stream()
.filter(inst -> inst instanceof L2ModificationInstruction)
.filter(inst -> ((L2ModificationInstruction) inst).subtype().equals(VLAN_PUSH))
.findAny()
- .orElse(null);
- return instruction != null;
+ .isPresent();
}
}
diff --git a/src/main/java/org/opencord/cordvtn/rest/NeutronMl2NetworksWebResource.java b/src/main/java/org/opencord/cordvtn/rest/NeutronMl2NetworksWebResource.java
index 5e0a580..81f82ee 100644
--- a/src/main/java/org/opencord/cordvtn/rest/NeutronMl2NetworksWebResource.java
+++ b/src/main/java/org/opencord/cordvtn/rest/NeutronMl2NetworksWebResource.java
@@ -15,51 +15,182 @@
*/
package org.opencord.cordvtn.rest;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.rest.AbstractWebResource;
+import org.opencord.cordvtn.api.CordVtnAdminService;
+import org.opencord.cordvtn.api.NetworkId;
+import org.openstack4j.core.transport.ObjectMapperSingleton;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.openstack.networking.domain.NeutronNetwork;
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.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
import java.io.InputStream;
+import java.util.Set;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+import static javax.ws.rs.core.Response.*;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
/**
- * Dummy Neutron ML2 mechanism driver.
- * It just returns OK for networks resource requests.
+ * Neutron ML2 mechanism driver implementation for the network resource.
*/
@Path("networks")
public class NeutronMl2NetworksWebResource extends AbstractWebResource {
protected final Logger log = LoggerFactory.getLogger(getClass());
- private static final String NETWORKS_MESSAGE = "Received networks %s";
+ private static final String MESSAGE = "Received networks %s request";
+ private static final String NETWORK = "network";
+ private static final String NETWORKS = "networks";
+
+ private final CordVtnAdminService adminService =
+ DefaultServiceDirectory.getService(CordVtnAdminService.class);
+
+ @Context
+ private UriInfo uriInfo;
+
+ /**
+ * Creates a network from the JSON input stream.
+ *
+ * @param input network JSON input stream
+ * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+ * is invalid or duplicated network already exists
+ */
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createNetwork(InputStream input) {
- log.trace(String.format(NETWORKS_MESSAGE, "create"));
- return Response.status(Response.Status.OK).build();
+ log.trace(String.format(MESSAGE, "CREATE"));
+
+ final NeutronNetwork net = readNetwork(input);
+ adminService.createNetwork(net);
+
+ UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
+ .path(NETWORKS)
+ .path(net.getId());
+
+ return created(locationBuilder.build()).build();
}
+ /**
+ * Updates the network with the specified identifier.
+ *
+ * @param id network identifier
+ * @param input network JSON input stream
+ * @return 200 OK with the updated network, 400 BAD_REQUEST if the requested
+ * network does not exist
+ */
@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updateNetwork(@PathParam("id") String id, InputStream input) {
- log.trace(String.format(NETWORKS_MESSAGE, "update"));
- return Response.status(Response.Status.OK).build();
+ log.trace(String.format(MESSAGE, "UPDATE " + id));
+
+ final NeutronNetwork net = readNetwork(input);
+ adminService.updateNetwork(net);
+
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(NETWORK, writeNetwork(net))).build();
}
+ /**
+ * Returns all networks.
+ *
+ * @return 200 OK with set of networks
+ */
+ @GET
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getNetworks() {
+ log.trace(String.format(MESSAGE, "GET"));
+
+ Set<Network> nets = adminService.getNetworks();
+ ArrayNode arrayNodes = mapper().createArrayNode();
+ nets.stream().forEach(net -> {
+ arrayNodes.add(writeNetwork(net));
+ });
+
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(NETWORKS, arrayNodes)).build();
+ }
+
+ /**
+ * Returns the network with the given network id.
+ *
+ * @param id network id
+ * @return 200 OK with the network, 404 NOT_FOUND if the network does not exist
+ */
+ @GET
+ @Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getNetwork(@PathParam("id") String id) {
+ log.trace(String.format(MESSAGE, "GET " + id));
+
+ Network net = adminService.getNetwork(NetworkId.of(id));
+ if (net == null) {
+ return status(NOT_FOUND).build();
+ }
+
+ ObjectNode result = mapper().createObjectNode();
+ return ok(result.set(NETWORK, writeNetwork(net))).build();
+ }
+
+ /**
+ * Removes the service network.
+ *
+ * @param id network identifier
+ * @return 204 NO_CONTENT, 400 BAD_REQUEST if the network does not exist
+ */
@DELETE
@Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
public Response deleteNetwork(@PathParam("id") String id) {
- log.trace(String.format(NETWORKS_MESSAGE, "delete"));
- return Response.noContent().build();
+ log.trace(String.format(MESSAGE, "DELETE " + id));
+
+ adminService.removeNetwork(NetworkId.of(id));
+ return noContent().build();
+ }
+
+ private NeutronNetwork readNetwork(InputStream input) {
+ try {
+ JsonNode jsonTree = mapper().enable(INDENT_OUTPUT).readTree(input);
+ log.trace(mapper().writeValueAsString(jsonTree));
+ return ObjectMapperSingleton.getContext(NeutronNetwork.class)
+ .readerFor(NeutronNetwork.class)
+ .readValue(jsonTree);
+ } catch (Exception e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private ObjectNode writeNetwork(Network net) {
+ try {
+ String strNet = ObjectMapperSingleton.getContext(NeutronNetwork.class)
+ .writerFor(NeutronNetwork.class)
+ .writeValueAsString(net);
+ log.trace(strNet);
+ return (ObjectNode) mapper().readTree(strNet.getBytes());
+ } catch (Exception e) {
+ throw new IllegalStateException();
+ }
}
}
diff --git a/src/main/java/org/opencord/cordvtn/rest/NeutronMl2PortsWebResource.java b/src/main/java/org/opencord/cordvtn/rest/NeutronMl2PortsWebResource.java
index 560d01d..32417bc 100644
--- a/src/main/java/org/opencord/cordvtn/rest/NeutronMl2PortsWebResource.java
+++ b/src/main/java/org/opencord/cordvtn/rest/NeutronMl2PortsWebResource.java
@@ -16,101 +16,183 @@
package org.opencord.cordvtn.rest;
import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Maps;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.osgi.DefaultServiceDirectory;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.opencord.cordvtn.impl.handler.VsgInstanceHandler;
-import org.onosproject.net.HostId;
+import org.opencord.cordvtn.api.CordVtnAdminService;
+import org.opencord.cordvtn.api.PortId;
import org.onosproject.rest.AbstractWebResource;
+import org.openstack4j.core.transport.ObjectMapperSingleton;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.openstack.networking.domain.NeutronPort;
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.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
import java.io.InputStream;
-import java.util.Map;
+import java.util.Set;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.status;
/**
- * Dummy Neutron ML2 mechanism driver.
- * It just returns OK for ports resource requests except for the port update.
+ * Neutron ML2 mechanism driver implementation for the port resource.
*/
@Path("ports")
public class NeutronMl2PortsWebResource extends AbstractWebResource {
protected final Logger log = LoggerFactory.getLogger(getClass());
- private static final String PORTS_MESSAGE = "Received ports %s";
- private static final String PORT = "port";
- private static final String DEVICE_ID = "device_id";
- private static final String NAME = "name";
- private static final String MAC_ADDRESS = "mac_address";
- private static final String ADDRESS_PAIRS = "allowed_address_pairs";
- private static final String IP_ADDERSS = "ip_address";
- private static final String STAG_PREFIX = "stag-";
- private static final int STAG_BEGIN_INDEX = 5;
+ private static final String MESSAGE = "Received ports %s request";
+ private static final String PORT = "port";
+ private static final String PORTS = "ports";
- private final VsgInstanceHandler service = DefaultServiceDirectory.getService(VsgInstanceHandler.class);
+ private final CordVtnAdminService adminService =
+ DefaultServiceDirectory.getService(CordVtnAdminService.class);
+ @Context
+ private UriInfo uriInfo;
+
+ /**
+ * Creates a port from the JSON input stream.
+ *
+ * @param input port JSON input stream
+ * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+ * is invalid or duplicated port already exists
+ */
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createPorts(InputStream input) {
- log.trace(String.format(PORTS_MESSAGE, "create"));
- return Response.status(Response.Status.OK).build();
+ log.trace(String.format(MESSAGE, "CREATE"));
+
+ final NeutronPort port = readPort(input);
+ adminService.createPort(port);
+ UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
+ .path(PORTS)
+ .path(port.getId());
+
+ return created(locationBuilder.build()).build();
}
+ /**
+ * Updates the port with the specified identifier.
+ *
+ * @param id port identifier
+ * @param input port JSON input stream
+ * @return 200 OK with the updated port, 400 BAD_REQUEST if the requested
+ * port does not exist
+ */
@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- public Response updatePorts(@PathParam("id") String id, InputStream input) {
- log.debug(String.format(PORTS_MESSAGE, "update"));
+ public Response updatePort(@PathParam("id") String id, InputStream input) {
+ log.trace(String.format(MESSAGE, "UPDATE " + id));
- // TODO get vSG updates from XOS to CORD VTN service directly
- try {
- ObjectMapper mapper = new ObjectMapper();
- JsonNode jsonNode = mapper.readTree(input).get(PORT);
- log.trace("{}", jsonNode.toString());
+ final NeutronPort port = readPort(input);
+ adminService.updatePort(port);
- String deviceId = jsonNode.path(DEVICE_ID).asText();
- String name = jsonNode.path(NAME).asText();
- if (deviceId.isEmpty() || name.isEmpty() || !name.startsWith(STAG_PREFIX)) {
- // ignore all updates other than allowed address pairs
- return Response.status(Response.Status.OK).build();
- }
-
- // this is allowed address pairs updates
- MacAddress mac = MacAddress.valueOf(jsonNode.path(MAC_ADDRESS).asText());
- Map<IpAddress, MacAddress> vsgInstances = Maps.newHashMap();
- jsonNode.path(ADDRESS_PAIRS).forEach(addrPair -> {
- IpAddress pairIp = IpAddress.valueOf(addrPair.path(IP_ADDERSS).asText());
- MacAddress pairMac = MacAddress.valueOf(addrPair.path(MAC_ADDRESS).asText());
- vsgInstances.put(pairIp, pairMac);
- });
-
- service.updateVsgInstances(HostId.hostId(mac),
- name.substring(STAG_BEGIN_INDEX),
- vsgInstances);
- } catch (Exception e) {
- return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
- }
-
- return Response.status(Response.Status.OK).build();
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(PORT, writePort(port))).build();
}
+ /**
+ * Returns all ports.
+ *
+ * @return 200 OK with set of ports
+ */
+ @GET
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getPorts() {
+ log.trace(String.format(MESSAGE, "GET"));
+
+ Set<Port> ports = adminService.getPorts();
+ ArrayNode arrayNodes = mapper().createArrayNode();
+ ports.stream().forEach(port -> {
+ arrayNodes.add(writePort(port));
+ });
+
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(PORTS, arrayNodes)).build();
+ }
+
+ /**
+ * Returns the port with the given id.
+ *
+ * @param id port id
+ * @return 200 OK with the port, 404 NOT_FOUND if the port does not exist
+ */
+ @GET
@Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getPort(@PathParam("id") String id) {
+ log.trace(String.format(MESSAGE, "GET " + id));
+
+ Port port = adminService.getPort(PortId.of(id));
+ if (port == null) {
+ return status(NOT_FOUND).build();
+ }
+
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(PORT, writePort(port))).build();
+ }
+
+ /**
+ * Removes the port with the given id.
+ *
+ * @param id port identifier
+ * @return 204 NO_CONTENT, 400 BAD_REQUEST if the port does not exist
+ */
@DELETE
+ @Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
public Response deletePorts(@PathParam("id") String id) {
- log.trace(String.format(PORTS_MESSAGE, "delete"));
- return Response.noContent().build();
+ log.trace(String.format(MESSAGE, "DELETE " + id));
+
+ adminService.removePort(PortId.of(id));
+ return noContent().build();
+ }
+
+ private NeutronPort readPort(InputStream input) {
+ try {
+ JsonNode jsonTree = mapper().enable(INDENT_OUTPUT).readTree(input);
+ log.trace(mapper().writeValueAsString(jsonTree));
+ return ObjectMapperSingleton.getContext(NeutronPort.class)
+ .readerFor(NeutronPort.class)
+ .readValue(jsonTree);
+ } catch (Exception e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private ObjectNode writePort(Port port) {
+ try {
+ String strPort = ObjectMapperSingleton.getContext(NeutronPort.class)
+ .writerFor(NeutronPort.class)
+ .writeValueAsString(port);
+ log.trace(strPort);
+ return (ObjectNode) mapper().readTree(strPort.getBytes());
+ } catch (Exception e) {
+ throw new IllegalStateException();
+ }
}
}
diff --git a/src/main/java/org/opencord/cordvtn/rest/NeutronMl2SubnetsWebResource.java b/src/main/java/org/opencord/cordvtn/rest/NeutronMl2SubnetsWebResource.java
index 71ebbb0..4a57d28 100644
--- a/src/main/java/org/opencord/cordvtn/rest/NeutronMl2SubnetsWebResource.java
+++ b/src/main/java/org/opencord/cordvtn/rest/NeutronMl2SubnetsWebResource.java
@@ -15,53 +15,184 @@
*/
package org.opencord.cordvtn.rest;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.rest.AbstractWebResource;
+import org.opencord.cordvtn.api.CordVtnAdminService;
+import org.opencord.cordvtn.api.SubnetId;
+import org.openstack4j.core.transport.ObjectMapperSingleton;
+import org.openstack4j.model.network.Subnet;
+import org.openstack4j.openstack.networking.domain.NeutronSubnet;
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.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
import java.io.InputStream;
+import java.util.Set;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.status;
/**
- * Dummy Neutron ML2 mechanism driver.
- * It just returns OK for subnets resource requests.
+ * Neutron ML2 mechanism driver implementation for the subnet resource.
*/
@Path("subnets")
public class NeutronMl2SubnetsWebResource extends AbstractWebResource {
protected final Logger log = LoggerFactory.getLogger(getClass());
- private static final String SUBNETS_MESSAGE = "Received subnets %s";
+ private static final String MESSAGE = "Received subnets %s request";
+ private static final String SUBNET = "subnet";
+ private static final String SUBNETS = "subnets";
+
+ private final CordVtnAdminService adminService =
+ DefaultServiceDirectory.getService(CordVtnAdminService.class);
+
+ @Context
+ private UriInfo uriInfo;
+
+ /**
+ * Creates a subnet from the JSON input stream.
+ *
+ * @param input subnet JSON input stream
+ * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+ * is invalid or duplicated subnet already exists
+ */
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createSubnet(InputStream input) {
- log.trace(String.format(SUBNETS_MESSAGE, "create"));
- return Response.status(Response.Status.OK).build();
+ log.trace(String.format(MESSAGE, "CREATE"));
+
+ final NeutronSubnet subnet = readSubnet(input);
+ adminService.createSubnet(subnet);
+ UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
+ .path(SUBNETS)
+ .path(subnet.getId());
+
+ // TODO fix networking-onos to send Network UPDATE when subnet created
+ return created(locationBuilder.build()).build();
}
-
+ /**
+ * Updates the subnet with the specified identifier.
+ *
+ * @param id subnet identifier
+ * @param input subnet JSON input stream
+ * @return 200 OK with the updated subnet, 400 BAD_REQUEST if the requested
+ * subnet does not exist
+ */
@PUT
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response updateSubnet(@PathParam("id") String id, InputStream input) {
- log.trace(String.format(SUBNETS_MESSAGE, "update"));
- return Response.status(Response.Status.OK).build();
+ log.trace(String.format(MESSAGE, "UPDATE " + id));
+ final NeutronSubnet subnet = readSubnet(input);
+ adminService.updateSubnet(subnet);
+
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(SUBNET, writeSubnet(subnet))).build();
}
+ /**
+ * Returns all subnets.
+ *
+ * @return 200 OK with set of subnets
+ */
+ @GET
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getSubnets() {
+ log.trace(String.format(MESSAGE, "GET"));
+
+ Set<Subnet> subnets = adminService.getSubnets();
+ ArrayNode arrayNodes = mapper().createArrayNode();
+ subnets.stream().forEach(subnet -> {
+ arrayNodes.add(writeSubnet(subnet));
+ });
+
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(SUBNETS, arrayNodes)).build();
+ }
+
+ /**
+ * Returns the subnet with the given subnet id.
+ *
+ * @param id subnet id
+ * @return 200 OK with the subnet, 404 NOT_FOUND if the subnet does not exist
+ */
+ @GET
+ @Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getSubnet(@PathParam("id") String id) {
+ log.trace(String.format(MESSAGE, "GET " + id));
+
+ Subnet subnet = adminService.getSubnet(SubnetId.of(id));
+ if (subnet == null) {
+ return status(NOT_FOUND).build();
+ }
+
+ ObjectNode result = this.mapper().createObjectNode();
+ return ok(result.set(SUBNET, writeSubnet(subnet))).build();
+ }
+
+ /**
+ * Removes the subnet.
+ *
+ * @param id subnet identifier
+ * @return 204 NO_CONTENT, 400 BAD_REQUEST if the subnet does not exist
+ */
@DELETE
@Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
public Response deleteSubnet(@PathParam("id") String id) {
- log.trace(String.format(SUBNETS_MESSAGE, "delete"));
- return Response.noContent().build();
+ log.trace(String.format(MESSAGE, "DELETE " + id));
+
+ adminService.removeSubnet(SubnetId.of(id));
+ return noContent().build();
+ }
+
+ private NeutronSubnet readSubnet(InputStream input) {
+ try {
+ JsonNode jsonTree = mapper().enable(INDENT_OUTPUT).readTree(input);
+ log.trace(mapper().writeValueAsString(jsonTree));
+ return ObjectMapperSingleton.getContext(NeutronSubnet.class)
+ .readerFor(NeutronSubnet.class)
+ .readValue(jsonTree);
+ } catch (Exception e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private ObjectNode writeSubnet(Subnet subnet) {
+ try {
+ String strSubnet = ObjectMapperSingleton.getContext(NeutronSubnet.class)
+ .writerFor(NeutronSubnet.class)
+ .writeValueAsString(subnet);
+ log.trace(strSubnet);
+ return (ObjectNode) mapper().readTree(strSubnet.getBytes());
+ } catch (Exception e) {
+ throw new IllegalStateException();
+ }
}
}
diff --git a/src/main/java/org/opencord/cordvtn/rest/ServiceDependencyWebResource.java b/src/main/java/org/opencord/cordvtn/rest/ServiceDependencyWebResource.java
index 9c58757..c194174 100644
--- a/src/main/java/org/opencord/cordvtn/rest/ServiceDependencyWebResource.java
+++ b/src/main/java/org/opencord/cordvtn/rest/ServiceDependencyWebResource.java
@@ -16,8 +16,9 @@
package org.opencord.cordvtn.rest;
import org.onosproject.rest.AbstractWebResource;
-import org.onosproject.xosclient.api.VtnServiceId;
+import org.opencord.cordvtn.api.Dependency.Type;
import org.opencord.cordvtn.api.DependencyService;
+import org.opencord.cordvtn.api.NetworkId;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
@@ -26,10 +27,15 @@
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import java.util.Objects;
+
+import static org.opencord.cordvtn.api.Dependency.Type.BIDIRECTIONAL;
+import static org.opencord.cordvtn.api.Dependency.Type.UNIDIRECTIONAL;
/**
* Manages service dependency.
*/
+@Deprecated
@Path("service-dependency")
public class ServiceDependencyWebResource extends AbstractWebResource {
@@ -48,9 +54,9 @@
@Produces(MediaType.APPLICATION_JSON)
public Response createServiceDependency(@PathParam("tenantServiceId") String tServiceId,
@PathParam("providerServiceId") String pServiceId) {
- service.createDependency(VtnServiceId.of(tServiceId),
- VtnServiceId.of(pServiceId),
- false);
+ service.createDependency(NetworkId.of(tServiceId),
+ NetworkId.of(pServiceId),
+ UNIDIRECTIONAL);
return Response.status(Response.Status.OK).build();
}
@@ -68,9 +74,10 @@
public Response createServiceDependency(@PathParam("tenantServiceId") String tServiceId,
@PathParam("providerServiceId") String pServiceId,
@PathParam("direction") String direction) {
- service.createDependency(VtnServiceId.of(tServiceId),
- VtnServiceId.of(pServiceId),
- direction.equals(BIDIRECTION));
+ Type type = Objects.equals(direction, BIDIRECTION) ? BIDIRECTIONAL : UNIDIRECTIONAL;
+ service.createDependency(NetworkId.of(tServiceId),
+ NetworkId.of(pServiceId),
+ type);
return Response.status(Response.Status.OK).build();
}
@@ -85,7 +92,7 @@
@Path("{tenantServiceId}/{providerServiceId}")
public Response removeServiceDependency(@PathParam("tenantServiceId") String tServiceId,
@PathParam("providerServiceId") String pServiceId) {
- service.removeDependency(VtnServiceId.of(tServiceId), VtnServiceId.of(pServiceId));
+ service.removeDependency(NetworkId.of(tServiceId), NetworkId.of(pServiceId));
return Response.noContent().build();
}
}
diff --git a/src/main/java/org/opencord/cordvtn/rest/ServiceNetworkWebResource.java b/src/main/java/org/opencord/cordvtn/rest/ServiceNetworkWebResource.java
index fbd6ddd..a376a55 100644
--- a/src/main/java/org/opencord/cordvtn/rest/ServiceNetworkWebResource.java
+++ b/src/main/java/org/opencord/cordvtn/rest/ServiceNetworkWebResource.java
@@ -19,7 +19,7 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.rest.AbstractWebResource;
-import org.opencord.cordvtn.api.CordVtnStore;
+import org.opencord.cordvtn.api.CordVtnAdminService;
import org.opencord.cordvtn.api.NetworkId;
import org.opencord.cordvtn.api.ServiceNetwork;
import org.slf4j.Logger;
@@ -40,7 +40,8 @@
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.io.InputStream;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
@@ -56,10 +57,11 @@
protected final Logger log = LoggerFactory.getLogger(getClass());
private static final String MESSAGE = "Received service network ";
- private static final String SERVICE_NETWORK = "ServiceNetwork";
+ private static final String SERVICE_NETWORK = "ServiceNetwork";
private static final String SERVICE_NETWORKS = "ServiceNetworks";
- private final CordVtnStore service = DefaultServiceDirectory.getService(CordVtnStore.class);
+ private final CordVtnAdminService adminService =
+ DefaultServiceDirectory.getService(CordVtnAdminService.class);
@Context
private UriInfo uriInfo;
@@ -85,7 +87,7 @@
}
final ServiceNetwork snet = codec(ServiceNetwork.class).decode(snetJson, this);
- service.createServiceNetwork(snet);
+ adminService.createVtnNetwork(snet);
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path(SERVICE_NETWORKS)
@@ -100,7 +102,8 @@
/**
* Updates the service network with the specified identifier.
*
- * @param id network identifier
+ * @param id network identifier
+ * @param input service network JSON stream
* @return 200 OK with a service network, 400 BAD_REQUEST if the requested
* network does not exist
*/
@@ -119,7 +122,7 @@
}
final ServiceNetwork snet = codec(ServiceNetwork.class).decode(snetJson, this);
- service.updateServiceNetwork(snet);
+ adminService.updateVtnNetwork(snet);
ObjectNode result = this.mapper().createObjectNode();
result.set(SERVICE_NETWORK, codec(ServiceNetwork.class).encode(snet, this));
@@ -140,7 +143,7 @@
public Response getServiceNetworks() {
log.trace(MESSAGE + "GET");
- Set<ServiceNetwork> snets = service.getServiceNetworks();
+ List<ServiceNetwork> snets = new ArrayList<>(adminService.getVtnNetworks());
return ok(encodeArray(ServiceNetwork.class, SERVICE_NETWORKS, snets)).build();
}
@@ -158,13 +161,15 @@
public Response getServiceNetwork(@PathParam("id") String id) {
log.trace(MESSAGE + "GET " + id);
- ServiceNetwork snet = service.getServiceNetwork(NetworkId.of(id));
+ ServiceNetwork snet = adminService.getVtnNetwork(NetworkId.of(id));
if (snet == null) {
+ log.trace("Returned NOT_FOUND");
return status(NOT_FOUND).build();
}
ObjectNode result = this.mapper().createObjectNode();
result.set(SERVICE_NETWORK, codec(ServiceNetwork.class).encode(snet, this));
+ log.trace("Returned OK {}", result);
return ok(result).build();
}
@@ -181,7 +186,7 @@
public Response deleteServiceNetwork(@PathParam("id") String id) {
log.trace(MESSAGE + "DELETE " + id);
- service.removeServiceNetwork(NetworkId.of(id));
+ adminService.removeVtnNetwork(NetworkId.of(id));
return noContent().build();
}
}
diff --git a/src/main/java/org/opencord/cordvtn/rest/ServicePortWebResource.java b/src/main/java/org/opencord/cordvtn/rest/ServicePortWebResource.java
index 7b18e10..4300fb0 100644
--- a/src/main/java/org/opencord/cordvtn/rest/ServicePortWebResource.java
+++ b/src/main/java/org/opencord/cordvtn/rest/ServicePortWebResource.java
@@ -19,7 +19,7 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.rest.AbstractWebResource;
-import org.opencord.cordvtn.api.CordVtnStore;
+import org.opencord.cordvtn.api.CordVtnAdminService;
import org.opencord.cordvtn.api.PortId;
import org.opencord.cordvtn.api.ServicePort;
import org.slf4j.Logger;
@@ -29,6 +29,7 @@
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.PathParam;
import javax.ws.rs.Produces;
@@ -39,7 +40,8 @@
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.io.InputStream;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
@@ -55,10 +57,11 @@
protected final Logger log = LoggerFactory.getLogger(getClass());
private static final String MESSAGE = "Received service port ";
- private static final String SERVICE_PORT = "ServicePort";
+ private static final String SERVICE_PORT = "ServicePort";
private static final String SERVICE_PORTS = "ServicePorts";
- private final CordVtnStore service = DefaultServiceDirectory.getService(CordVtnStore.class);
+ private final CordVtnAdminService adminService =
+ DefaultServiceDirectory.getService(CordVtnAdminService.class);
@Context
private UriInfo uriInfo;
@@ -84,7 +87,7 @@
}
final ServicePort sport = codec(ServicePort.class).decode(portJson, this);
- service.createServicePort(sport);
+ adminService.createVtnPort(sport);
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path(SERVICE_PORTS)
@@ -97,6 +100,39 @@
}
/**
+ * Updates the service port with the given identifier.
+ *
+ * @param id port identifier
+ * @param input service port JSON stream
+ * @return 200 OK with a service port, 400 BAD_REQUEST if the requested
+ * port does not exist
+ */
+ @PUT
+ @Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateServicePort(@PathParam("id") String id, InputStream input) {
+ try {
+ JsonNode jsonTree = mapper().enable(INDENT_OUTPUT).readTree(input);
+ log.trace(MESSAGE + "UPDATE " + mapper().writeValueAsString(jsonTree));
+
+ ObjectNode sportJson = (ObjectNode) jsonTree.get(SERVICE_PORT);
+ if (sportJson == null) {
+ throw new IllegalArgumentException();
+ }
+
+ final ServicePort sport = codec(ServicePort.class).decode(sportJson, this);
+ adminService.updateVtnPort(sport);
+
+ ObjectNode result = this.mapper().createObjectNode();
+ result.set(SERVICE_PORT, codec(ServicePort.class).encode(sport, this));
+ return ok(result).build();
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
* Returns all service ports.
*
* @return 200 OK with set of service ports
@@ -105,9 +141,9 @@
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response getServicePorts() {
- log.debug(MESSAGE + "GET");
+ log.trace(MESSAGE + "GET");
- Set<ServicePort> sports = service.getServicePorts();
+ List<ServicePort> sports = new ArrayList<>(adminService.getVtnPorts());
return ok(encodeArray(ServicePort.class, SERVICE_PORTS, sports)).build();
}
@@ -123,15 +159,17 @@
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response getServicePort(@PathParam("id") String id) {
- log.debug(MESSAGE + "GET " + id);
+ log.trace(MESSAGE + "GET " + id);
- ServicePort sport = service.getServicePort(PortId.of(id));
+ ServicePort sport = adminService.getVtnPort(PortId.of(id));
if (sport == null) {
+ log.trace("Returned NOT_FOUND");
return status(NOT_FOUND).build();
}
ObjectNode result = this.mapper().createObjectNode();
result.set(SERVICE_PORT, codec(ServicePort.class).encode(sport, this));
+ log.trace("Returned OK {}", result);
return ok(result).build();
}
@@ -146,9 +184,9 @@
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response deleteServicePort(@PathParam("id") String id) {
- log.debug(MESSAGE + "DELETE " + id);
+ log.trace(MESSAGE + "DELETE " + id);
- service.removeServicePort(PortId.of(id));
+ adminService.removeVtnPort(PortId.of(id));
return noContent().build();
}
}