ONOS-5549 TE Tunnel attributes management app implementation
Change-Id: I0d05bfa9ef79311fe4b3baf6b05783a24379ec3a
diff --git a/apps/tetunnel/app/app.xml b/apps/tetunnel/app/app.xml
index 14e55aa..5af373b 100644
--- a/apps/tetunnel/app/app.xml
+++ b/apps/tetunnel/app/app.xml
@@ -17,7 +17,9 @@
-->
<app name="org.onosproject.tetunnel" origin="HUAWEI" version="${project.version}"
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
- features="${project.artifactId}">
+ features="${project.artifactId}"
+ apps="org.onosproject.tetopology">
<description>${project.description}</description>
<artifact>mvn:${project.groupId}/onos-app-tetunnel-api/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
</app>
\ No newline at end of file
diff --git a/apps/tetunnel/app/pom.xml b/apps/tetunnel/app/pom.xml
index 95419f6..2af3a3f 100644
--- a/apps/tetunnel/app/pom.xml
+++ b/apps/tetunnel/app/pom.xml
@@ -25,5 +25,19 @@
</parent>
<artifactId>onos-app-tetunnel</artifactId>
+ <packaging>bundle</packaging>
<description>IETF TE Tunnel attributes management implementation</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-tetunnel-api</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-serializers</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
</project>
\ No newline at end of file
diff --git a/apps/tetunnel/app/src/main/java/org/onosproject/tetunnel/impl/DistributedTeTunnelStore.java b/apps/tetunnel/app/src/main/java/org/onosproject/tetunnel/impl/DistributedTeTunnelStore.java
new file mode 100755
index 0000000..2824007
--- /dev/null
+++ b/apps/tetunnel/app/src/main/java/org/onosproject/tetunnel/impl/DistributedTeTunnelStore.java
@@ -0,0 +1,169 @@
+/*
+ * 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.onosproject.tetunnel.impl;
+
+import com.google.common.collect.ImmutableList;
+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.KryoNamespace;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.LogicalClockService;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.tetopology.management.api.TeTopologyKey;
+import org.onosproject.tetunnel.api.tunnel.TeTunnel;
+import org.onosproject.tetunnel.api.TeTunnelStore;
+import org.onosproject.tetunnel.api.tunnel.TeTunnelKey;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Manages the TE tunnel attributes using an eventually consistent map.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedTeTunnelStore implements TeTunnelStore {
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LogicalClockService clockService;
+
+ private EventuallyConsistentMap<TeTunnelKey, TeTunnel> teTunnels;
+ private EventuallyConsistentMap<TeTunnelKey, TunnelId> tunnelIds;
+
+ @Activate
+ public void activate() {
+ KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
+ .register(TeTunnel.class);
+
+ teTunnels = storageService.<TeTunnelKey, TeTunnel>eventuallyConsistentMapBuilder()
+ .withName("TeTunnelStore")
+ .withSerializer(serializer)
+ .withTimestampProvider((k, v) -> clockService.getTimestamp())
+ .build();
+
+ tunnelIds = storageService.<TeTunnelKey, TunnelId>eventuallyConsistentMapBuilder()
+ .withName("TeTunnelIdStore")
+ .withSerializer(serializer)
+ .withTimestampProvider((k, v) -> clockService.getTimestamp())
+ .build();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ teTunnels.destroy();
+ tunnelIds.destroy();
+
+ log.info("Stopped");
+ }
+
+ @Override
+ public boolean addTeTunnel(TeTunnel teTunnel) {
+ if (teTunnel == null) {
+ log.warn("teTunnel is null");
+ return false;
+ }
+ if (teTunnels.containsKey(teTunnel.teTunnelKey())) {
+ log.warn("teTunnel already exist");
+ return false;
+ }
+ teTunnels.put(teTunnel.teTunnelKey(), teTunnel);
+ return true;
+ }
+
+ @Override
+ public void setTunnelId(TeTunnelKey teTunnelKey, TunnelId tunnelId) {
+ tunnelIds.put(teTunnelKey, tunnelId);
+ }
+
+ @Override
+ public TunnelId getTunnelId(TeTunnelKey teTunnelKey) {
+ return tunnelIds.get(teTunnelKey);
+ }
+
+ @Override
+ public void updateTeTunnel(TeTunnel teTunnel) {
+ if (teTunnel == null) {
+ log.warn("TeTunnel is null");
+ return;
+ }
+ teTunnels.put(teTunnel.teTunnelKey(), teTunnel);
+ }
+
+ @Override
+ public void removeTeTunnel(TeTunnelKey teTunnelKey) {
+ teTunnels.remove(teTunnelKey);
+ tunnelIds.remove(teTunnelKey);
+ }
+
+ @Override
+ public TeTunnel getTeTunnel(TeTunnelKey teTunnelKey) {
+ return teTunnels.get(teTunnelKey);
+ }
+
+ @Override
+ public TeTunnel getTeTunnel(TunnelId tunnelId) {
+ if (tunnelIds.containsValue(tunnelId)) {
+ for (TeTunnel teTunnel : teTunnels.values()) {
+ if (tunnelIds.get(teTunnel.teTunnelKey()).equals(tunnelId)) {
+ return teTunnel;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Collection<TeTunnel> getTeTunnels() {
+ return ImmutableList.copyOf(teTunnels.values());
+ }
+
+ @Override
+ public Collection<TeTunnel> getTeTunnels(TeTunnel.Type type) {
+ return ImmutableList.copyOf(teTunnels.values()
+ .stream()
+ .filter(teTunnel -> teTunnel.type().equals(type))
+ .collect(Collectors.toList()));
+ }
+
+ @Override
+ public Collection<TeTunnel> getTeTunnels(TeTopologyKey teTopologyKey) {
+ return ImmutableList.copyOf(teTunnels.values()
+ .stream()
+ .filter(teTunnel -> teTunnel.teTunnelKey()
+ .teTopologyKey()
+ .equals(teTopologyKey))
+ .collect(Collectors.toList()));
+ }
+}
diff --git a/apps/tetunnel/app/src/main/java/org/onosproject/tetunnel/impl/TeTunnelManager.java b/apps/tetunnel/app/src/main/java/org/onosproject/tetunnel/impl/TeTunnelManager.java
new file mode 100755
index 0000000..04cbefc
--- /dev/null
+++ b/apps/tetunnel/app/src/main/java/org/onosproject/tetunnel/impl/TeTunnelManager.java
@@ -0,0 +1,243 @@
+/*
+ * 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.onosproject.tetunnel.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.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.incubator.net.tunnel.DefaultTunnel;
+import org.onosproject.incubator.net.tunnel.Tunnel;
+import org.onosproject.incubator.net.tunnel.TunnelAdminService;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.incubator.net.tunnel.TunnelName;
+import org.onosproject.incubator.net.tunnel.TunnelService;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.tetopology.management.api.TeTopology;
+import org.onosproject.tetopology.management.api.TeTopologyKey;
+import org.onosproject.tetopology.management.api.TeTopologyService;
+import org.onosproject.tetunnel.api.tunnel.TeTunnel;
+import org.onosproject.tetunnel.api.TeTunnelAdminService;
+import org.onosproject.tetunnel.api.TeTunnelProviderService;
+import org.onosproject.tetunnel.api.TeTunnelService;
+import org.onosproject.tetunnel.api.TeTunnelStore;
+import org.onosproject.tetunnel.api.tunnel.TeTunnelEndpoint;
+import org.onosproject.tetunnel.api.tunnel.TeTunnelKey;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.List;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of TE tunnel attributes management service.
+ */
+@Component(immediate = true)
+@Service
+public class TeTunnelManager implements TeTunnelService, TeTunnelAdminService,
+ TeTunnelProviderService {
+
+ private static final String TE_TUNNEL_APP = "onos-app-tetunnel";
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TeTunnelStore store;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TunnelService tunnelService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TunnelAdminService tunnelAdminService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TeTopologyService teTopologyService;
+
+ private ApplicationId appId;
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication(TE_TUNNEL_APP);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public TunnelId createTeTunnel(TeTunnel teTunnel) {
+ if (!store.addTeTunnel(teTunnel)) {
+ log.error("can not add teTunnel: {}", teTunnel);
+ return null;
+ }
+
+ TunnelId tunnelId = TunnelId.valueOf(teTunnel.teTunnelKey().toString());
+ Tunnel tunnel = new DefaultTunnel(ProviderId.NONE,
+ new TeTunnelEndpoint(teTunnel.srcNode(),
+ teTunnel.srcTp()),
+ new TeTunnelEndpoint(teTunnel.dstNode(),
+ teTunnel.dstTp()),
+ Tunnel.Type.MPLS, new DefaultGroupId(0),
+ tunnelId,
+ TunnelName.tunnelName(teTunnel.name()),
+ null,
+ DefaultAnnotations.builder().build());
+ store.setTunnelId(teTunnel.teTunnelKey(), tunnelId);
+ TeTopology srcTopology = teTopologyService.teTopology(
+ teTopologyService.teNode(teTunnel.srcNode())
+ .underlayTeTopologyId());
+ if (srcTopology == null) {
+ srcTopology = teTopologyService.teTopology(teTunnel.srcNode()
+ .teTopologyKey());
+ }
+ DeviceId domainId = srcTopology.ownerId();
+ TunnelId id = tunnelService.setupTunnel(appId, domainId, tunnel, null);
+ if (id == null) {
+ log.error("can not create tunnel for te {}",
+ teTunnel.teTunnelKey());
+ store.removeTeTunnel(teTunnel.teTunnelKey());
+ return null;
+ }
+ if (!id.equals(tunnelId)) {
+ //this should not happen
+ log.error("tunnelId changed, oldId:{}, newId:{}", tunnelId, id);
+ store.setTunnelId(teTunnel.teTunnelKey(), id);
+ }
+ return id;
+ }
+
+ @Override
+ public void setTunnelId(TeTunnelKey teTunnelKey, TunnelId tunnelId) {
+ store.setTunnelId(teTunnelKey, tunnelId);
+ }
+
+ @Override
+ public void updateTeTunnel(TeTunnel teTunnel) {
+ //TODO: updateTeTunnel
+ }
+
+ @Override
+ public void updateTunnelState(TeTunnelKey key, Tunnel.State state) {
+ tunnelAdminService.updateTunnelState(
+ tunnelService.queryTunnel(getTunnelId(key)), state);
+ }
+
+ @Override
+ public void removeTeTunnel(TeTunnelKey teTunnelKey) {
+ tunnelAdminService.updateTunnelState(
+ tunnelService.queryTunnel(getTunnelId(teTunnelKey)),
+ Tunnel.State.REMOVING);
+ List<TeTunnelKey> segmentTunnels =
+ getTeTunnel(teTunnelKey).segmentTunnels();
+ if (segmentTunnels == null || segmentTunnels.isEmpty()) {
+ // this is a single domain tunnel, removes it right away
+ tunnelAdminService.removeTunnel(getTunnelId(teTunnelKey));
+ }
+ }
+
+ @Override
+ public void setSegmentTunnel(TeTunnelKey e2eTunnelKey,
+ List<TeTunnelKey> segmentTunnels) {
+ TeTunnel e2eTunnel = store.getTeTunnel(e2eTunnelKey);
+ if (e2eTunnel == null) {
+ log.error("unknown e2eTunnel: {}", e2eTunnelKey);
+ return;
+ }
+ e2eTunnel.segmentTunnels(segmentTunnels);
+
+ for (TeTunnelKey key : segmentTunnels) {
+ TeTunnel segmentTunnel = store.getTeTunnel(key);
+ if (segmentTunnel == null) {
+ log.warn("unknown segmentTunnel: {}", key);
+ continue;
+ }
+ segmentTunnel.e2eTunnel(e2eTunnelKey);
+ }
+ }
+
+ @Override
+ public TeTunnel getTeTunnel(TeTunnelKey key) {
+ return store.getTeTunnel(key);
+ }
+
+ @Override
+ public TeTunnel getTeTunnel(TunnelId id) {
+ return store.getTeTunnel(id);
+ }
+
+ @Override
+ public TunnelId getTunnelId(TeTunnelKey key) {
+ return store.getTunnelId(key);
+ }
+
+ @Override
+ public Collection<TeTunnel> getTeTunnels() {
+ return store.getTeTunnels();
+ }
+
+ @Override
+ public Collection<TeTunnel> getTeTunnels(TeTunnel.Type type) {
+ return store.getTeTunnels(type);
+ }
+
+ @Override
+ public Collection<TeTunnel> getTeTunnels(TeTopologyKey key) {
+ return store.getTeTunnels(key);
+ }
+
+ @Override
+ public TunnelId teTunnelAdded(TeTunnel teTunnel) {
+ //TODO teTunnelAdded
+ return null;
+ }
+
+ @Override
+ public void teTunnelRemoved(TeTunnel teTunnel) {
+ TeTunnelKey e2eTunnelKey = teTunnel.e2eTunnel();
+ store.removeTeTunnel(teTunnel.teTunnelKey());
+
+ // it's a segment tunnel
+ if (e2eTunnelKey != null) {
+ boolean finished = true;
+ for (TeTunnelKey key : getTeTunnel(e2eTunnelKey).segmentTunnels()) {
+ if (getTeTunnel(key) != null) {
+ // FIXME need a better way to determine whether a segment tunnel is removed.
+ finished = false;
+ }
+ }
+ if (finished) {
+ // all segment tunnels are removed
+ tunnelAdminService.removeTunnel(getTunnelId(e2eTunnelKey));
+ store.removeTeTunnel(e2eTunnelKey);
+ }
+ }
+ }
+}