ONOS-5304 MDSC TE Tunnel controller

Change-Id: I1edbf3a583966f1389eb167543ced7bd6c4c51b3

ONOS-5304 MDSC TE Tunnel controller

Change-Id: I1edbf3a583966f1389eb167543ced7bd6c4c51b3
diff --git a/apps/actn-mdsc/actn-mdscapp/app.xml b/apps/actn-mdsc/actn-mdscapp/app.xml
new file mode 100644
index 0000000..f97405a
--- /dev/null
+++ b/apps/actn-mdsc/actn-mdscapp/app.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<app name="org.onosproject.actn.mdsc" origin="Huawei" version="${project.version}"
+     category="default" url="http://onosproject.org" title="ACTN MDSC App"
+     featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
+     features="${project.artifactId}">
+    <description>${project.description}</description>
+    <artifact>mvn:${project.groupId}/onos-actn-mdsc-tetunnel-pce/${project.version}</artifact>
+    <artifact>mvn:${project.groupId}/onos-actn-mdsc-tetunnel-ctl/${project.version}</artifact>
+    <apps>org.onosproject.tetopology, org.onosproject.tetunnel</apps>
+</app>
diff --git a/apps/actn-mdsc/actn-mdscapp/features.xml b/apps/actn-mdsc/actn-mdscapp/features.xml
new file mode 100644
index 0000000..a4fe5a7
--- /dev/null
+++ b/apps/actn-mdsc/actn-mdscapp/features.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+    <feature name="${project.artifactId}" version="${project.version}"
+             description="${project.description}">
+        <feature>onos-api</feature>
+        <feature>onos-app-tetopology</feature>
+        <feature>onos-app-tetunnel</feature>
+        <bundle>mvn:${project.groupId}/onos-actn-mdsc-tetunnel-pce/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-actn-mdsc-tetunnel-ctl/${project.version}</bundle>
+    </feature>
+</features>
diff --git a/apps/actn-mdsc/actn-mdscapp/pom.xml b/apps/actn-mdsc/actn-mdscapp/pom.xml
new file mode 100644
index 0000000..6607007
--- /dev/null
+++ b/apps/actn-mdsc/actn-mdscapp/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-actn-mdsc</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.8.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-actn-mdscapp</artifactId>
+    <description>ONOS ACTN MDSC Application</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-actn-mdsc-tetunnel-ctl</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/apps/actn-mdsc/pom.xml b/apps/actn-mdsc/pom.xml
new file mode 100644
index 0000000..e3b6303
--- /dev/null
+++ b/apps/actn-mdsc/pom.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-apps</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.8.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-actn-mdsc</artifactId>
+    <packaging>pom</packaging>
+
+    <description>ONOS ACTN MDSC Application</description>
+
+    <modules>
+        <module>tetunnel-pce</module>
+        <module>tetunnel-ctl</module>
+        <module>actn-mdscapp</module>
+    </modules>
+
+    <properties>
+        <!-- Uncomment to generate ONOS app from this module.
+        <onos.app.name>org.onosproject.actn.mdsc</onos.app.name>
+        <onos.app.origin>Huawei</onos.app.origin>
+        <onos.app.category>default</onos.app.category>
+        <onos.app.url>http://onosproject.org</onos.app.url>
+        <onos.app.title>Foo App</onos.app.title>
+        <onos.app.readme>ONOS OSGi bundle archetype.</onos.app.readme>
+        -->
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/apps/actn-mdsc/tetunnel-ctl/pom.xml b/apps/actn-mdsc/tetunnel-ctl/pom.xml
new file mode 100644
index 0000000..c2f678f
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-ctl/pom.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-actn-mdsc</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.8.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-actn-mdsc-tetunnel-ctl</artifactId>
+    <description>TE Tunnel controller which manages TE tunnel processing</description>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-tetunnel-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-actn-mdsc-tetunnel-pce</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/apps/actn-mdsc/tetunnel-ctl/src/main/java/org/onosproject/actn/mdsc/tetunnelctl/TeTunnelCtl.java b/apps/actn-mdsc/tetunnel-ctl/src/main/java/org/onosproject/actn/mdsc/tetunnelctl/TeTunnelCtl.java
new file mode 100755
index 0000000..5106652
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-ctl/src/main/java/org/onosproject/actn/mdsc/tetunnelctl/TeTunnelCtl.java
@@ -0,0 +1,347 @@
+/*
+ * 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.actn.mdsc.tetunnelctl;
+
+import com.google.common.collect.Lists;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.actn.mdsc.pce.TeTunnelPceService;
+import org.onosproject.incubator.net.tunnel.Tunnel;
+import org.onosproject.incubator.net.tunnel.TunnelAdminService;
+import org.onosproject.incubator.net.tunnel.TunnelEvent;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.incubator.net.tunnel.TunnelListener;
+import org.onosproject.incubator.net.tunnel.TunnelService;
+import org.onosproject.tetopology.management.api.TeTopology;
+import org.onosproject.tetopology.management.api.TeTopologyKey;
+import org.onosproject.tetopology.management.api.TeTopologyService;
+import org.onosproject.tetopology.management.api.node.TeNodeKey;
+import org.onosproject.tetopology.management.api.node.TtpKey;
+import org.onosproject.tetunnel.api.TeTunnelAdminService;
+import org.onosproject.tetunnel.api.TeTunnelService;
+import org.onosproject.tetunnel.api.tunnel.DefaultTeTunnel;
+import org.onosproject.tetunnel.api.tunnel.TeTunnel;
+import org.onosproject.tetunnel.api.tunnel.TeTunnelKey;
+import org.onosproject.tetunnel.api.tunnel.path.TePath;
+import org.onosproject.tetunnel.api.tunnel.path.TeRouteSubobject;
+import org.onosproject.tetunnel.api.tunnel.path.TeRouteUnnumberedLink;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * TE Tunnel controller/processor which manages TE tunnel processing.
+ * <p>
+ * For example, when creating a cross-domain tunnel from a MDSC, the
+ * processor will call a relevant PCE to get an end-to-end cross-domain path,
+ * then spits the path into segment tunnels(domain tunnels), and then informs
+ * PNCs to setup domain tunnels respectively.
+ */
+@Component(immediate = true)
+public class TeTunnelCtl {
+
+    private static final Logger log = LoggerFactory.getLogger(TeTunnelCtl.class);
+
+    private final TunnelListener tunnelListener = new InternalTunnelListener();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TunnelService tunnelService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TunnelAdminService tunnelAdminService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TeTunnelService teTunnelService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TeTunnelAdminService teTunnelAdminService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TeTopologyService teTopologyService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TeTunnelPceService teTunnelPceService;
+
+    @Activate
+    protected void activate() {
+        tunnelService.addListener(tunnelListener);
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        tunnelService.removeListener(tunnelListener);
+
+        log.info("Stopped");
+    }
+
+    private void addTeTunnel(TeTunnel teTunnel) {
+        if (teTunnel == null) {
+            return;
+        }
+
+        Tunnel tunnel = tunnelService.queryTunnel(
+                teTunnelService.getTunnelId(teTunnel.teTunnelKey()));
+        if (tunnel == null) {
+            log.error("tunnel does not exist, {}", teTunnel.teTunnelKey());
+            return;
+        }
+        if (tunnel.state() != Tunnel.State.INIT) {
+            log.error("tunnel state error, {}, {}", teTunnel.teTunnelKey(),
+                      tunnel.state());
+            return;
+        }
+        tunnelAdminService.updateTunnelState(tunnel, Tunnel.State.ESTABLISHING);
+
+        //TODO support multi-thread
+        if (isTeTunnelCrossDomain(teTunnel)) {
+            if (!addCrossDomainTeTunnel(teTunnel)) {
+                tunnelAdminService.updateTunnelState(tunnel, Tunnel.State.FAILED);
+            }
+        }
+        /*
+         * "else" is to do nothing.
+         * When adding a single domain tunnel, the TunnelManager will call
+         * tunnel providers, then the providers will pass the request to
+         * the domain controller. Nothing to do here.
+         */
+    }
+
+    private boolean isTeTunnelCrossDomain(TeTunnel teTunnel) {
+        TeTopology srcTopo = teTopologyService.teTopology(
+                teTopologyService.teNode(teTunnel.srcNode())
+                .underlayTeTopologyId());
+        TeTopology dstTopo = teTopologyService.teTopology(
+                teTopologyService.teNode(teTunnel.dstNode())
+                .underlayTeTopologyId());
+        return (srcTopo != null && dstTopo != null
+                && srcTopo.ownerId().equals(dstTopo.ownerId()));
+    }
+
+    private boolean addCrossDomainTeTunnel(TeTunnel teTunnel) {
+        List<TeRouteSubobject> route = null;
+        TePath primaryPath = teTunnel.primaryPaths().get(0);
+        if (primaryPath != null &&
+                primaryPath.type() == TePath.Type.EXPLICIT) {
+            route = primaryPath.explicitRoute();
+        } else {
+            Collection<List<TeRouteSubobject>> routes =
+                    teTunnelPceService.computePaths(teTunnel);
+            if (routes == null || routes.isEmpty()) {
+                log.error("no available route for {}",
+                          teTunnel.teTunnelKey());
+                return false;
+            }
+
+            //FIXME: try other pce when failed?
+            route = routes.iterator().next();
+        }
+
+        if (route == null) {
+            log.error("no available route for {}",
+                      teTunnel.teTunnelKey());
+            return false;
+        }
+
+        return spitRoute(teTunnel, route);
+    }
+
+    //spits route to segment tunnels
+    private boolean spitRoute(TeTunnel teTunnel, List<TeRouteSubobject> route) {
+        List<TeTunnelKey> segmentTunnels = Lists.newArrayList();
+        boolean success = true;
+        TeNodeKey srcNode = teTunnel.srcNode();
+        TtpKey srcTp = teTunnel.srcTp();
+        TeNodeKey dstNode = null;
+        TtpKey dstTp = null;
+
+        for (TeRouteSubobject teRouteSubobject : route) {
+            if (!(teRouteSubobject instanceof TeRouteUnnumberedLink)) {
+                log.error("unsupported type {}", teRouteSubobject.type());
+                success = false;
+                break;
+            }
+
+            TeRouteUnnumberedLink teRouteUnnumberedLink =
+                    (TeRouteUnnumberedLink) teRouteSubobject;
+            dstNode = teRouteUnnumberedLink.node();
+            dstTp = teRouteUnnumberedLink.ttp();
+            if (Objects.equals(srcNode, dstNode) &&
+                    Objects.equals(srcTp, dstTp)) {
+                continue;
+            }
+            if (Objects.equals(srcNode, dstNode)) {
+                if (!addSegmentTunnel(segmentTunnels, teTunnel,
+                                      srcNode, srcTp, dstNode, dstTp)) {
+                    success = false;
+                    break;
+                }
+            }
+
+            srcNode = dstNode;
+            srcTp = dstTp;
+        }
+
+        if (success && !(Objects.equals(dstNode, teTunnel.dstNode()) &&
+                Objects.equals(dstTp, teTunnel.dstTp()))) {
+            srcNode = dstNode;
+            srcTp = dstTp;
+            dstNode = teTunnel.dstNode();
+            dstTp = teTunnel.dstTp();
+            if (!addSegmentTunnel(segmentTunnels, teTunnel,
+                                  srcNode, srcTp, dstNode, dstTp)) {
+                success = false;
+            }
+        }
+
+        if (!success) {
+            // roll back segment tunnels
+            for (TeTunnelKey key : segmentTunnels) {
+                teTunnelAdminService.removeTeTunnel(key);
+            }
+        } else {
+            teTunnelAdminService.setSegmentTunnel(teTunnel.teTunnelKey(),
+                                                  segmentTunnels);
+        }
+        return success;
+    }
+
+    private boolean addSegmentTunnel(List<TeTunnelKey> segmentTunnels,
+                                     TeTunnel teTunnel,
+                                     TeNodeKey srcNode, TtpKey srcTp,
+                                     TeNodeKey dstNode, TtpKey dstTp) {
+        TeTunnelKey teTunnelKey = getNextTeTunnelKey(srcNode.teTopologyKey());
+        TeTunnel teTunnelSegment = DefaultTeTunnel.builder()
+                .teTunnelKey(teTunnelKey)
+                .srcNode(srcNode)
+                .dstNode(dstNode)
+                .srcTp(srcTp)
+                .dstTp(dstTp)
+                .adminState(teTunnel.adminStatus())
+                .lspProtectionType(teTunnel.lspProtectionType())
+                .type(teTunnel.type())
+                .build();
+        TunnelId tunnelId =
+                teTunnelAdminService.createTeTunnel(teTunnelSegment);
+        if (tunnelId == null) {
+            log.error("failed to create segment tunnel: {},{},{},{}",
+                      srcNode, srcTp, dstNode, dstTp);
+            return false;
+        }
+        segmentTunnels.add(teTunnelKey);
+        return true;
+    }
+
+    private TeTunnelKey getNextTeTunnelKey(TeTopologyKey key) {
+        //FIXME need a better way to get a te tunnel id
+        long teTunnelId = teTunnelService.getTeTunnels(key).size() + 1;
+        return new TeTunnelKey(key, teTunnelId);
+    }
+
+    private void updateTeTunnel(TeTunnel teTunnel, Tunnel tunnel) {
+        if (teTunnel == null) {
+            return;
+        }
+
+        if (tunnel.state() == Tunnel.State.ESTABLISHED) {
+            tunnelEstablished(teTunnel);
+        } else if (tunnel.state() == Tunnel.State.REMOVING) {
+            removingTunnel(teTunnel);
+        }
+
+        //TODO update TE tunnel content
+    }
+
+    private void tunnelEstablished(TeTunnel teTunnel) {
+        TeTunnel e2eTeTunnel = retriveE2eTunnel(teTunnel);
+        if (e2eTeTunnel != null) {
+            boolean goodToContinue = true;
+            for (TeTunnelKey key : e2eTeTunnel.segmentTunnels()) {
+                goodToContinue = checkSegmentTunnel(key);
+                if (!goodToContinue) {
+                    break;
+                }
+            }
+
+            if (goodToContinue) {
+                tunnelAdminService.updateTunnelState(
+                        tunnelService.queryTunnel(
+                                teTunnelService.getTunnelId(
+                                        teTunnel.teTunnelKey())),
+                        Tunnel.State.ESTABLISHED
+                );
+            }
+        }
+    }
+
+    private TeTunnel retriveE2eTunnel(TeTunnel segmentTunnel) {
+        return teTunnelService.getTeTunnel(segmentTunnel.e2eTunnelKey());
+    }
+
+    private boolean checkSegmentTunnel(TeTunnelKey key) {
+        Tunnel segmentTunnel = tunnelService.queryTunnel(
+                teTunnelService.getTunnelId(key));
+        if (segmentTunnel == null ||
+                segmentTunnel.state() != Tunnel.State.ESTABLISHED) {
+            return false;
+        }
+        return true;
+    }
+
+    private void removingTunnel(TeTunnel teTunnel) {
+        List<TeTunnelKey> segmentTunnels = teTunnel.segmentTunnels();
+        if (segmentTunnels != null && !segmentTunnels.isEmpty()) {
+            for (TeTunnelKey key : segmentTunnels) {
+                teTunnelAdminService.removeTeTunnel(key);
+            }
+        }
+    }
+
+    // Listens on tunnel events.
+    private class InternalTunnelListener implements TunnelListener {
+        @Override
+        public void event(TunnelEvent event) {
+            switch (event.type()) {
+                case TUNNEL_ADDED:
+                    addTunnel(event.subject());
+                    break;
+                case TUNNEL_UPDATED:
+                    updateTunnel(event.subject());
+                    break;
+                //TODO: TE Tunnel remove/... event process
+                default:
+                    log.warn("unknown event: {}", event.type());
+                    break;
+            }
+        }
+
+        private void addTunnel(Tunnel tunnel) {
+            addTeTunnel(teTunnelService.getTeTunnel(tunnel.tunnelId()));
+        }
+
+        private void updateTunnel(Tunnel tunnel) {
+            updateTeTunnel(teTunnelService.getTeTunnel(tunnel.tunnelId()),
+                           tunnel);
+        }
+    }
+}
diff --git a/apps/actn-mdsc/tetunnel-ctl/src/main/java/org/onosproject/actn/mdsc/tetunnelctl/package-info.java b/apps/actn-mdsc/tetunnel-ctl/src/main/java/org/onosproject/actn/mdsc/tetunnelctl/package-info.java
new file mode 100644
index 0000000..8de1d14
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-ctl/src/main/java/org/onosproject/actn/mdsc/tetunnelctl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * TE Tunnel controller/processor which manages TE tunnel processing.
+ */
+package org.onosproject.actn.mdsc.tetunnelctl;
\ No newline at end of file
diff --git a/apps/actn-mdsc/tetunnel-pce/pom.xml b/apps/actn-mdsc/tetunnel-pce/pom.xml
new file mode 100755
index 0000000..d5ace69
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-pce/pom.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>onos-actn-mdsc</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.8.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>onos-actn-mdsc-tetunnel-pce</artifactId>
+    <description>TE Tunnel PCE service</description>
+    <packaging>bundle</packaging>
+
+    <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-app-tetunnel-api</artifactId>
+            <version>1.8.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/TeTunnelPce.java b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/TeTunnelPce.java
new file mode 100755
index 0000000..705896f
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/TeTunnelPce.java
@@ -0,0 +1,58 @@
+/*
+ * 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.actn.mdsc.pce;
+
+import org.onosproject.tetunnel.api.tunnel.TeTunnel;
+import org.onosproject.tetunnel.api.tunnel.path.TeRouteSubobject;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * PCE which calculates paths for TE tunnels.
+ */
+public interface TeTunnelPce {
+
+    static final int PRIORITY_HIGHEST = 255;
+    static final int PRIORITY_HIGH = PRIORITY_HIGHEST * 3 / 4;
+    static final int PRIORITY_MEDIUM = PRIORITY_HIGHEST / 2;
+    static final int PRIORITY_LOW = PRIORITY_HIGHEST / 4;
+    static final int PRIORITY_LOWEST = 0;
+
+    /**
+     * Returns priority of this PCE.
+     *
+     * @return priority of this PCE
+     */
+    int getPriority();
+
+    /**
+     * Signifies whether this PCE is suitable for the specified TE tunnel.
+     *
+     * @param teTunnel tunnel to check
+     * @return true if this PCE can calculate path for the TE tunnel
+     */
+    boolean isSuitable(TeTunnel teTunnel);
+
+    /**
+     * Calculates available paths for the specified TE tunnel.
+     *
+     * @param teTunnel tunnel information to be calculated
+     * @return available paths for the specified TE tunnel
+     */
+    Collection<List<TeRouteSubobject>> computePaths(TeTunnel teTunnel);
+}
diff --git a/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/TeTunnelPceService.java b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/TeTunnelPceService.java
new file mode 100755
index 0000000..a3d10f3
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/TeTunnelPceService.java
@@ -0,0 +1,58 @@
+/*
+ * 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.actn.mdsc.pce;
+
+import org.onosproject.tetunnel.api.tunnel.TeTunnel;
+import org.onosproject.tetunnel.api.tunnel.path.TeRouteSubobject;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * TE tunnel PCE management API.
+ */
+public interface TeTunnelPceService {
+
+    /**
+     * Calculates available paths for the specified TE tunnel.
+     * <p>
+     * PCE which is suitable for the specified TE tunnel and with the highest
+     * priority will be chosen for the path calculation.
+     *
+     * @param teTunnel tunnel information to be calculated
+     * @return available paths for the specified TE tunnel
+     */
+    Collection<List<TeRouteSubobject>> computePaths(TeTunnel teTunnel);
+
+    /**
+     * Calculates available paths for the specified TE tunnel with specified
+     * PCE.
+     *
+     * @param teTunnel tunnel information to be calculated
+     * @param pce PCE to be used for path calculation
+     * @return available paths for the specified TE tunnel
+     */
+    Collection<List<TeRouteSubobject>> computePaths(TeTunnel teTunnel,
+                                                    TeTunnelPce pce);
+
+    /**
+     * Registers a new pce.
+     *
+     * @param pce new PCE to be registered.
+     */
+    void registerPce(TeTunnelPce pce);
+}
diff --git a/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/DefaultTeTunnelPce.java b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/DefaultTeTunnelPce.java
new file mode 100755
index 0000000..9afdf89
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/DefaultTeTunnelPce.java
@@ -0,0 +1,45 @@
+/*
+ * 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.actn.mdsc.pce.impl;
+
+import org.onosproject.actn.mdsc.pce.TeTunnelPce;
+import org.onosproject.tetunnel.api.tunnel.TeTunnel;
+import org.onosproject.tetunnel.api.tunnel.path.TeRouteSubobject;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Default implementation of TE tunnel PCE.
+ */
+class DefaultTeTunnelPce implements TeTunnelPce {
+    @Override
+    public int getPriority() {
+        return PRIORITY_LOWEST - 1;
+    }
+
+    @Override
+    public boolean isSuitable(TeTunnel teTunnel) {
+        return true;
+    }
+
+    @Override
+    public Collection<List<TeRouteSubobject>> computePaths(TeTunnel teTunnel) {
+        //TODO
+        return null;
+    }
+}
diff --git a/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/TeTunnelPceManager.java b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/TeTunnelPceManager.java
new file mode 100755
index 0000000..68c2af5
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/TeTunnelPceManager.java
@@ -0,0 +1,86 @@
+/*
+ * 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.actn.mdsc.pce.impl;
+
+import com.google.common.collect.Lists;
+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.Service;
+import org.onosproject.actn.mdsc.pce.TeTunnelPce;
+import org.onosproject.actn.mdsc.pce.TeTunnelPceService;
+import org.onosproject.tetunnel.api.tunnel.TeTunnel;
+import org.onosproject.tetunnel.api.tunnel.path.TeRouteSubobject;
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Implementation of Te Tunnel PCE service.
+ */
+@Component(immediate = true)
+@Service
+public class TeTunnelPceManager implements TeTunnelPceService {
+
+    private static final Logger log = getLogger(TeTunnelPceManager.class);
+
+    private List<TeTunnelPce> pces = Lists.newLinkedList();
+
+    @Activate
+    protected void activate() {
+        pces.add(0, new DefaultTeTunnelPce());
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public Collection<List<TeRouteSubobject>> computePaths(TeTunnel teTunnel) {
+        TeTunnelPce pce = null;
+        synchronized (pces) {
+            for (TeTunnelPce p : pces) {
+                if (p.isSuitable(teTunnel)) {
+                    pce = p;
+                }
+            }
+        }
+        return pce.computePaths(teTunnel);
+    }
+
+    @Override
+    public Collection<List<TeRouteSubobject>> computePaths(TeTunnel teTunnel,
+                                                           TeTunnelPce pce) {
+        return pce == null ? null : pce.computePaths(teTunnel);
+    }
+
+    @Override
+    public void registerPce(TeTunnelPce pce) {
+        synchronized (pces) {
+            int index = 0;
+            while (pces.get(index).getPriority() > pce.getPriority()) {
+                index++;
+            }
+
+            pces.add(index, pce);
+        }
+    }
+}
diff --git a/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/package-info.java b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/package-info.java
new file mode 100755
index 0000000..e39e884
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implementation of TE tunnel PCE service.
+ */
+package org.onosproject.actn.mdsc.pce.impl;
\ No newline at end of file
diff --git a/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/package-info.java b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/package-info.java
new file mode 100644
index 0000000..3f9fb11
--- /dev/null
+++ b/apps/actn-mdsc/tetunnel-pce/src/main/java/org/onosproject/actn/mdsc/pce/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * PCE service which calculates paths for TE tunnels.
+ */
+package org.onosproject.actn.mdsc.pce;
\ No newline at end of file
diff --git a/apps/pom.xml b/apps/pom.xml
index f52b44d..1fe294f 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -81,6 +81,7 @@
         <module>learning-switch</module>
         <module>tenbi</module>
         <module>tetunnel</module>
+        <module>actn-mdsc</module>
     </modules>
 
     <properties>
diff --git a/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/DefaultTeTunnel.java b/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/DefaultTeTunnel.java
index 686731c..c5a5041 100755
--- a/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/DefaultTeTunnel.java
+++ b/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/DefaultTeTunnel.java
@@ -125,13 +125,13 @@
     }
 
     @Override
-    public TeTunnelKey e2eTunnel() {
+    public TeTunnelKey e2eTunnelKey() {
         return e2eTunnel;
     }
 
     @Override
-    public void e2eTunnel(TeTunnelKey e2eTunnel) {
-        this.e2eTunnel = e2eTunnel;
+    public void e2eTunnelKey(TeTunnelKey e2eTunnelKey) {
+        this.e2eTunnel = e2eTunnelKey;
     }
 
     @Override
diff --git a/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/TeTunnel.java b/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/TeTunnel.java
index 0c1bd2f..9afd0d0 100755
--- a/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/TeTunnel.java
+++ b/apps/tetunnel/api/src/main/java/org/onosproject/tetunnel/api/tunnel/TeTunnel.java
@@ -182,14 +182,14 @@
      *
      * @return key of the corresponding E2E TE tunnel
      */
-    TeTunnelKey e2eTunnel();
+    TeTunnelKey e2eTunnelKey();
 
     /**
      * Sets the E2E tunnel of this (segment) tunnel.
      *
-     * @param e2eTunnel key of the corresponding E2E tunnel
+     * @param e2eTunnelKey key of the corresponding E2E tunnel
      */
-    void e2eTunnel(TeTunnelKey e2eTunnel);
+    void e2eTunnelKey(TeTunnelKey e2eTunnelKey);
 
     //TODO: add more required TE attributes
 }
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
index 04cbefc..82ce04f 100755
--- 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
@@ -168,7 +168,7 @@
                                  List<TeTunnelKey> segmentTunnels) {
         TeTunnel e2eTunnel = store.getTeTunnel(e2eTunnelKey);
         if (e2eTunnel == null) {
-            log.error("unknown e2eTunnel: {}", e2eTunnelKey);
+            log.error("unknown e2eTunnelKey: {}", e2eTunnelKey);
             return;
         }
         e2eTunnel.segmentTunnels(segmentTunnels);
@@ -179,7 +179,7 @@
                 log.warn("unknown segmentTunnel: {}", key);
                 continue;
             }
-            segmentTunnel.e2eTunnel(e2eTunnelKey);
+            segmentTunnel.e2eTunnelKey(e2eTunnelKey);
         }
     }
 
@@ -221,7 +221,7 @@
 
     @Override
     public void teTunnelRemoved(TeTunnel teTunnel) {
-        TeTunnelKey e2eTunnelKey = teTunnel.e2eTunnel();
+        TeTunnelKey e2eTunnelKey = teTunnel.e2eTunnelKey();
         store.removeTeTunnel(teTunnel.teTunnelKey());
 
         // it's a segment tunnel