ONOS-6903 Move EVPN from incubator to apps

Change-Id: Id84c59e28f2591535b0726afbc1a2fa3caf07db5
diff --git a/apps/dhcprelay/pom.xml b/apps/dhcprelay/pom.xml
index 782e1b0..5e9d68e 100644
--- a/apps/dhcprelay/pom.xml
+++ b/apps/dhcprelay/pom.xml
@@ -81,13 +81,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-incubator-api</artifactId>
-            <version>${project.version}</version>
-            <classifier>tests</classifier>
-        </dependency>
-
-        <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.scr.annotations</artifactId>
             <scope>provided</scope>
diff --git a/apps/evpn-route-service/BUCK b/apps/evpn-route-service/BUCK
new file mode 100644
index 0000000..5c8b037
--- /dev/null
+++ b/apps/evpn-route-service/BUCK
@@ -0,0 +1,11 @@
+BUNDLES = [
+    '//apps/evpn-route-service/api:onos-apps-evpn-route-service-api',
+    '//apps/evpn-route-service/app:onos-apps-evpn-route-service-app',
+]
+
+onos_app (
+    title = 'EVPN Routing App',
+    category = 'Utility',
+    url = 'http://onosproject.org',
+    included_bundles = BUNDLES,
+)
diff --git a/apps/evpn-route-service/api/BUCK b/apps/evpn-route-service/api/BUCK
new file mode 100644
index 0000000..68eeacf
--- /dev/null
+++ b/apps/evpn-route-service/api/BUCK
@@ -0,0 +1,13 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+]
+
+TEST_DEPS = [
+    '//lib:TEST',
+    '//core/api:onos-api-tests',
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+)
diff --git a/apps/evpn-route-service/api/pom.xml b/apps/evpn-route-service/api/pom.xml
new file mode 100644
index 0000000..25113e7
--- /dev/null
+++ b/apps/evpn-route-service/api/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-present Open Networking Foundation
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<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-app-evpn-route-service</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.11.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-app-evpn-route-service-api</artifactId>
+    <packaging>bundle</packaging>
+
+    <url>http://onosproject.org</url>
+
+    <description>EVPN Routing Application API</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+
+</project>
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstance.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstance.java
new file mode 100644
index 0000000..5288db7
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstance.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a evpn instance.
+ */
+public final class EvpnInstance {
+
+    private final RouteDistinguisher rd;
+    private final List<VpnRouteTarget> importRtList;
+    private final List<VpnRouteTarget> exportRtList;
+    private final EvpnInstanceName evpnName;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param rd           route distinguisher
+     * @param importRtList import rotue targets
+     * @param exportRtList export rotue targets
+     * @param evpnName     vpn instance name
+     */
+    private EvpnInstance(RouteDistinguisher rd,
+                         List<VpnRouteTarget> importRtList,
+                         List<VpnRouteTarget> exportRtList,
+                         EvpnInstanceName evpnName) {
+        checkNotNull(rd);
+        //checkNotNull(rt);
+        checkNotNull(evpnName);
+        this.rd = rd;
+        this.importRtList = importRtList;
+        this.exportRtList = exportRtList;
+        this.evpnName = evpnName;
+    }
+
+    /**
+     * Creats the instance of EvpnInstance.
+     *
+     * @param rd           route distinguisher
+     * @param importRtList import rotue targets
+     * @param exportRtList export rotue targets
+     * @param evpnName     vpn instance name
+     * @return EvpnInstance
+     */
+    public static EvpnInstance evpnInstance(RouteDistinguisher rd,
+                                            List<VpnRouteTarget> importRtList,
+                                            List<VpnRouteTarget> exportRtList,
+                                            EvpnInstanceName evpnName) {
+        return new EvpnInstance(rd, importRtList, exportRtList, evpnName);
+    }
+
+    /**
+     * Getter of RouteDistinguisher.
+     *
+     * @return RouteDistinguisher
+     */
+    public RouteDistinguisher routeDistinguisher() {
+        return rd;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+
+    public List<VpnRouteTarget> importRouteTarget() {
+        return importRtList;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+    public List<VpnRouteTarget> exportRouteTarget() {
+        return exportRtList;
+    }
+
+    /**
+     * Getter of vpn instance name.
+     *
+     * @return evpnName
+     */
+    public EvpnInstanceName evpnName() {
+        return evpnName;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(rd, importRtList, exportRtList, evpnName);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnInstance)) {
+            return false;
+        }
+
+        EvpnInstance that = (EvpnInstance) other;
+
+        return Objects.equals(this.evpnName, that.evpnName)
+                && Objects.equals(this.rd, that.rd)
+                && Objects.equals(this.importRtList, that.importRtList)
+                && Objects.equals(this.exportRtList, that.exportRtList);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("evpnName", this.evpnName)
+                .add("rd", this.rd).add("import rt", this.importRtList)
+                .add("export rt", this.exportRtList).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceName.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceName.java
new file mode 100644
index 0000000..f1ea22a
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceName.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Represents the EvpnInstanceName.
+ */
+public final class EvpnInstanceName {
+    private final String evpnName;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param evpnName EvpnInstanceName
+     */
+    private EvpnInstanceName(String evpnName) {
+        this.evpnName = evpnName;
+    }
+
+    /**
+     * Creates instance of EvpnInstanceName.
+     *
+     * @param evpnName evpnName
+     * @return evpnInstanceName
+     */
+    public static EvpnInstanceName evpnName(String evpnName) {
+        return new EvpnInstanceName(evpnName);
+    }
+
+    /**
+     * Get vpn instance name.
+     *
+     * @return evpnName
+     */
+    public String getEvpnName() {
+        return evpnName;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(evpnName);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof EvpnInstanceName) {
+            EvpnInstanceName other = (EvpnInstanceName) obj;
+            return Objects.equals(this.evpnName, other.evpnName);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("evpnName", evpnName).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceNextHop.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceNextHop.java
new file mode 100644
index 0000000..49ad2c5
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceNextHop.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Represents a evpn instance nexthop.
+ */
+public final class EvpnInstanceNextHop {
+
+    private final IpAddress nextHop;
+    private final Label label;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param nextHop nexthop
+     * @param label   label
+     */
+    private EvpnInstanceNextHop(IpAddress nextHop, Label label) {
+        this.nextHop = nextHop;
+        this.label = label;
+    }
+
+    /**
+     * creates instance of EvpnInstanceNextHop.
+     *
+     * @param nextHop nexthop
+     * @param label   label
+     * @return evpnInstanceNexthop
+     */
+    public static EvpnInstanceNextHop evpnNextHop(IpAddress nextHop,
+                                                  Label label) {
+        return new EvpnInstanceNextHop(nextHop, label);
+    }
+
+    /**
+     * Returns the next hop IP address.
+     *
+     * @return next hop
+     */
+    public IpAddress nextHop() {
+        return nextHop;
+    }
+
+    /**
+     * Returns the label.
+     *
+     * @return Label
+     */
+    public Label label() {
+        return label;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(nextHop, label);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnInstanceNextHop)) {
+            return false;
+        }
+
+        EvpnInstanceNextHop that = (EvpnInstanceNextHop) other;
+
+        return Objects.equals(this.nextHop(), that.nextHop())
+                && Objects.equals(this.label, that.label);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("nextHop", this.nextHop())
+                .add("label", this.label).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstancePrefix.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstancePrefix.java
new file mode 100644
index 0000000..2f30538
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstancePrefix.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a evpn instance prefix.
+ */
+public final class EvpnInstancePrefix {
+
+    private final MacAddress macAddress;
+    private final IpPrefix ipPrefix;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param macAddress Mac address
+     * @param ipPrefix   IP address
+     */
+    private EvpnInstancePrefix(MacAddress macAddress,
+                               IpPrefix ipPrefix) {
+        checkNotNull(macAddress);
+        this.macAddress = macAddress;
+        this.ipPrefix = ipPrefix;
+    }
+
+    /**
+     * Creates the instance of EvpnInstancePrefix.
+     *
+     * @param macAddress Mac address
+     * @param ipPrefix   IP address
+     * @return Evpn instance prefix
+     */
+    public static EvpnInstancePrefix evpnPrefix(MacAddress macAddress,
+                                                IpPrefix ipPrefix) {
+        return new EvpnInstancePrefix(macAddress, ipPrefix);
+    }
+
+    /**
+     * Returns the MAC of the route.
+     *
+     * @return MAC address
+     */
+    public MacAddress macAddress() {
+        return macAddress;
+    }
+
+    /**
+     * Returns the IP prefix of the route.
+     *
+     * @return IP prefix
+     */
+    public IpPrefix ipPrefix() {
+        return ipPrefix;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(macAddress);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnInstancePrefix)) {
+            return false;
+        }
+
+        EvpnInstancePrefix that = (EvpnInstancePrefix) other;
+
+        return Objects.equals(this.macAddress, that.macAddress)
+                && Objects.equals(this.ipPrefix, that.ipPrefix);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("macAddress", this.macAddress)
+                .add("ipAddress", this.ipPrefix).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceRoute.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceRoute.java
new file mode 100644
index 0000000..3e98531
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInstanceRoute.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a evpn instance route.
+ */
+public class EvpnInstanceRoute {
+
+    private final EvpnInstanceName evpnName;
+    private final RouteDistinguisher rd;
+    private List<VpnRouteTarget> importRtList;
+    private List<VpnRouteTarget> exportRtList;
+    private final EvpnInstancePrefix evpnInstancePrefix;
+    private final EvpnInstanceNextHop evpnInstanceNextHop;
+    private final IpPrefix prefix;
+    private final IpAddress nextHop;
+    private final Label label;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param evpnName            vpn instance name
+     * @param rd                  route distinguisher
+     * @param importRtList        import route targets
+     * @param exportRtList        export route targets
+     * @param evpnInstancePrefix  evpn intance prefix
+     * @param evpnInstanceNextHop evpn instance nexthop
+     * @param prefix              evpn prefix
+     * @param nextHop             evpn nexthop
+     * @param label               label
+     */
+    public EvpnInstanceRoute(EvpnInstanceName evpnName,
+                             RouteDistinguisher rd,
+                             List<VpnRouteTarget> importRtList,
+                             List<VpnRouteTarget> exportRtList,
+                             EvpnInstancePrefix evpnInstancePrefix,
+                             EvpnInstanceNextHop evpnInstanceNextHop,
+                             IpPrefix prefix,
+                             IpAddress nextHop,
+                             Label label) {
+        checkNotNull(evpnName);
+        checkNotNull(prefix);
+        //checkNotNull(nextHop); //can be NULL in MP un reach
+        checkNotNull(rd);
+
+        this.evpnName = evpnName;
+        this.rd = rd;
+        this.importRtList = importRtList;
+        this.exportRtList = exportRtList;
+        this.prefix = prefix;
+        this.nextHop = nextHop;
+        this.evpnInstancePrefix = evpnInstancePrefix;
+        this.evpnInstanceNextHop = evpnInstanceNextHop;
+        this.label = label;
+    }
+
+    /**
+     * Returns the evpnName.
+     *
+     * @return EvpnInstanceName
+     */
+    public EvpnInstanceName evpnInstanceName() {
+        return evpnName;
+    }
+
+    /**
+     * Returns the route distinguisher.
+     *
+     * @return RouteDistinguisher
+     */
+    public RouteDistinguisher routeDistinguisher() {
+        return rd;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+
+    public List<VpnRouteTarget> importRouteTarget() {
+        return importRtList;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+    public List<VpnRouteTarget> exportRouteTarget() {
+        return exportRtList;
+    }
+
+    /**
+     * Set import list.
+     *
+     * @param importRtList import list
+     */
+    public void setImportRtList(List<VpnRouteTarget> importRtList) {
+        this.importRtList = importRtList;
+    }
+
+    /**
+     * Set export list.
+     *
+     * @param exportRtList export list
+     */
+    public void setExportRtList(List<VpnRouteTarget> exportRtList) {
+        this.exportRtList = exportRtList;
+    }
+
+    /**
+     * Returns EvpnInstancePrefix of the evpn private route.
+     *
+     * @return EvpnInstancePrefix
+     */
+
+    public EvpnInstancePrefix getevpnInstancePrefix() {
+        return evpnInstancePrefix;
+    }
+
+    /**
+     * Returns EvpnInstanceNextHop of the evpn private route.
+     *
+     * @return EvpnInstancePrefix
+     */
+
+    public EvpnInstanceNextHop getEvpnInstanceNextHop() {
+        return evpnInstanceNextHop;
+    }
+
+    /**
+     * Returns prefix of the evpn private route.
+     *
+     * @return EvpnInstancePrefix
+     */
+    public IpPrefix prefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the label.
+     *
+     * @return EvpnInstanceName
+     */
+    public Label getLabel() {
+        return label;
+    }
+
+    /**
+     * Returns the label.
+     *
+     * @return EvpnInstanceName
+     */
+    public IpAddress getNextHopl() {
+        return nextHop;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(evpnName, prefix, nextHop,
+                            rd, importRtList, exportRtList);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnInstanceRoute)) {
+            return false;
+        }
+
+        EvpnInstanceRoute that = (EvpnInstanceRoute) other;
+
+        return Objects.equals(prefix, prefix)
+                && Objects.equals(nextHop, that.nextHop)
+                && Objects.equals(evpnName, that.evpnName)
+                && Objects.equals(rd, that.rd)
+                && Objects.equals(importRtList, that.importRtList)
+                && Objects.equals(exportRtList, that.exportRtList);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("prefix", prefix)
+                .add("nextHop", nextHop)
+                .add("rd", rd)
+                .add("import rt", importRtList)
+                .add("export rt", exportRtList)
+                .add("evpnName", evpnName)
+                .toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInternalRouteEvent.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInternalRouteEvent.java
new file mode 100644
index 0000000..7a71875
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnInternalRouteEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Route event for signalling between the store and the manager.
+ */
+public class EvpnInternalRouteEvent extends
+        AbstractEvent<EvpnInternalRouteEvent.Type, EvpnRouteSet> {
+
+    /**
+     * Internal route event type.
+     */
+    public enum Type {
+        /**
+         * Indicates a route was added to the store.
+         */
+        ROUTE_ADDED,
+
+        /**
+         * Indicates a route was removed from the store.
+         */
+        ROUTE_REMOVED
+    }
+
+    /**
+     * Creates a new internal route event.
+     *
+     * @param type    route event type
+     * @param subject route set
+     */
+    public EvpnInternalRouteEvent(Type type, EvpnRouteSet subject) {
+        super(type, subject);
+    }
+
+    public EvpnInternalRouteEvent(Type type, EvpnRouteSet subject, long time) {
+        super(type, subject, time);
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnNextHop.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnNextHop.java
new file mode 100644
index 0000000..ac1e06b
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnNextHop.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Represents a evpn next hop.
+ */
+public final class EvpnNextHop {
+
+    private final IpAddress nextHop;
+    private final List<VpnRouteTarget> importRtList;
+    private final List<VpnRouteTarget> exportRtList;
+    private final Label label;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param nextHop      evpn next hop
+     * @param importRtList import route targets
+     * @param importRtList export route targets
+     * @param label        label
+     */
+    private EvpnNextHop(IpAddress nextHop, List<VpnRouteTarget> importRtList, List<VpnRouteTarget> exportRtList,
+                        Label label) {
+        this.nextHop = nextHop;
+        this.importRtList = importRtList;
+        this.exportRtList = exportRtList;
+        this.label = label;
+    }
+
+    /**
+     * Creates the Evpn Next hop with given parameters.
+     *
+     * @param nextHop      Next  hop of the route
+     * @param importRtList route target import list
+     * @param exportRtList route target export list
+     * @param label        label of evpn route
+     * @return EvpnNextHop
+     */
+    public static EvpnNextHop evpnNextHop(IpAddress nextHop, List<VpnRouteTarget> importRtList,
+                                          List<VpnRouteTarget> exportRtList,
+                                          Label label) {
+        return new EvpnNextHop(nextHop, importRtList, exportRtList, label);
+    }
+
+    /**
+     * Returns the next hop IP address.
+     *
+     * @return next hop
+     */
+    public IpAddress nextHop() {
+        return nextHop;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+
+    public List<VpnRouteTarget> importRouteTarget() {
+        return importRtList;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+    public List<VpnRouteTarget> exportRouteTarget() {
+        return exportRtList;
+    }
+
+    /**
+     * Returns the label of evpn route.
+     *
+     * @return Label
+     */
+    public Label label() {
+        return label;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(nextHop, importRtList, exportRtList, label);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnNextHop)) {
+            return false;
+        }
+
+        EvpnNextHop that = (EvpnNextHop) other;
+
+        return Objects.equals(this.nextHop(), that.nextHop())
+                && Objects.equals(this.importRtList, that.importRtList)
+                && Objects.equals(this.exportRtList, that.exportRtList)
+                && Objects.equals(this.label, that.label);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("nextHop", this.nextHop())
+                .add("import rt list", this.importRtList).add("export rt list", this.exportRtList)
+                .add("label", this.label).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnPrefix.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnPrefix.java
new file mode 100644
index 0000000..3f70ef5
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnPrefix.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a evpn prefix.
+ */
+public final class EvpnPrefix {
+
+    private final RouteDistinguisher rd;
+    private final MacAddress macAddress;
+    private final IpPrefix ipAddress;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param rd         route distinguisher
+     * @param macAddress mac address
+     * @param ipAddress  IP address
+     */
+    public EvpnPrefix(RouteDistinguisher rd, MacAddress macAddress,
+                      IpPrefix ipAddress) {
+        checkNotNull(rd);
+        checkNotNull(macAddress);
+        checkNotNull(ipAddress);
+        this.rd = rd;
+        this.macAddress = macAddress;
+        this.ipAddress = ipAddress;
+    }
+
+    /**
+     * Creates the evpn prefix by given parameters.
+     *
+     * @param rd         route distinguisher
+     * @param macAddress mac address
+     * @param ipAddress  ip address
+     * @return EvpnPrefix
+     */
+    public static EvpnPrefix evpnPrefix(RouteDistinguisher rd,
+                                        MacAddress macAddress,
+                                        IpPrefix ipAddress) {
+        return new EvpnPrefix(rd, macAddress, ipAddress);
+    }
+
+    /**
+     * Returns the route distinguisher.
+     *
+     * @return RouteDistinguisher
+     */
+    public RouteDistinguisher routeDistinguisher() {
+        return rd;
+    }
+
+    /**
+     * Returns the mac address.
+     *
+     * @return MacAddress
+     */
+    public MacAddress macAddress() {
+        return macAddress;
+    }
+
+    /**
+     * Returns the IP address.
+     *
+     * @return Ip4Address
+     */
+    public IpPrefix ipAddress() {
+        return ipAddress;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(rd, macAddress, ipAddress);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnPrefix)) {
+            return false;
+        }
+
+        EvpnPrefix that = (EvpnPrefix) other;
+
+        return Objects.equals(this.macAddress(), that.macAddress())
+                && Objects.equals(this.ipAddress, that.ipAddress)
+                && Objects.equals(this.rd, that.rd);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("macAddress", this.macAddress())
+                .add("ipAddress", this.ipAddress()).add("rd", this.rd)
+                .toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRoute.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRoute.java
new file mode 100644
index 0000000..9449093
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRoute.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a evpn route.
+ */
+public class EvpnRoute {
+
+
+    /**
+     * Source of the route.
+     */
+    public enum Source {
+        /**
+         * Route came from app source.
+         */
+        LOCAL,
+
+        /**
+         * Route came from remote bgp peer source.
+         */
+        REMOTE,
+    }
+
+    private final Source source;
+    private final MacAddress prefixMac;
+    private final IpPrefix prefix;
+    private final IpAddress nextHop;
+    private final RouteDistinguisher rd;
+    private List<VpnRouteTarget> importRtList;
+    private List<VpnRouteTarget> exportRtList;
+    private final Label label;
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param source       route source
+     * @param prefixMac    mac address
+     * @param prefix       ip address
+     * @param nextHop      evpn nexthop
+     * @param rd           route distinguisher
+     * @param importRtList import route targets
+     * @param exportRtList export route targets
+     * @param label        evpn route label
+     */
+    public EvpnRoute(Source source,
+                     MacAddress prefixMac,
+                     IpPrefix prefix,
+                     IpAddress nextHop,
+                     RouteDistinguisher rd,
+                     List<VpnRouteTarget> importRtList,
+                     List<VpnRouteTarget> exportRtList,
+                     Label label) {
+
+        checkNotNull(prefixMac);
+        checkNotNull(prefix);
+        //checkNotNull(nextHop);//next hop can be null in case of MP un reach.
+        checkNotNull(rd);
+        checkNotNull(label);
+        this.source = checkNotNull(source);
+        this.prefix = prefix;
+        this.prefixMac = prefixMac;
+        this.nextHop = nextHop;
+        this.rd = rd;
+        this.importRtList = importRtList;
+        this.exportRtList = exportRtList;
+        this.label = label;
+    }
+
+    /**
+     * Constructor to initialize the parameters.
+     *
+     * @param source       route source
+     * @param prefixMac    mac address
+     * @param prefix       ip address
+     * @param nextHop      evpn nexthop
+     * @param rdToString   route distinguisher
+     * @param importRtList import route targets
+     * @param exportRtList export route targets
+     * @param labelToInt   evpn route label
+     */
+    public EvpnRoute(Source source,
+                     MacAddress prefixMac,
+                     IpPrefix prefix,
+                     IpAddress nextHop,
+                     String rdToString,
+                     List<VpnRouteTarget> importRtList,
+                     List<VpnRouteTarget> exportRtList,
+                     int labelToInt) {
+        checkNotNull(prefixMac);
+        checkNotNull(prefix);
+        //checkNotNull(nextHop); //next hop can be null in case of MP un reach.
+        checkNotNull(labelToInt);
+        this.source = checkNotNull(source);
+        this.prefix = prefix;
+        this.prefixMac = prefixMac;
+        this.nextHop = nextHop;
+        this.rd = RouteDistinguisher.routeDistinguisher(rdToString);
+        this.importRtList = importRtList;
+        this.exportRtList = exportRtList;
+        this.label = Label.label(labelToInt);
+    }
+
+    /**
+     * Returns the route source.
+     *
+     * @return route source
+     */
+    public Source source() {
+        return source;
+    }
+
+    /**
+     * Returns the address.
+     *
+     * @return MacAddress
+     */
+    public MacAddress prefixMac() {
+        return prefixMac;
+    }
+
+    /**
+     * Returns the IPv4 address.
+     *
+     * @return Ip4Address
+     */
+    public IpPrefix prefixIp() {
+        return prefix;
+    }
+
+    /**
+     * Returns the IPv4 address.
+     *
+     * @return Ip4Address
+     */
+    public EvpnPrefix evpnPrefix() {
+        return new EvpnPrefix(rd, prefixMac,
+                              prefix);
+    }
+
+
+    /**
+     * Returns the next hop IP address.
+     *
+     * @return Ip4Address
+     */
+    public IpAddress ipNextHop() {
+        return nextHop;
+    }
+
+    public EvpnNextHop nextHop() {
+        return EvpnNextHop.evpnNextHop(nextHop,
+                                       importRtList,
+                                       exportRtList,
+                                       label);
+    }
+
+    /**
+     * Returns the routeDistinguisher.
+     *
+     * @return RouteDistinguisher
+     */
+    public RouteDistinguisher routeDistinguisher() {
+        return rd;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+
+    public List<VpnRouteTarget> importRouteTarget() {
+        return importRtList;
+    }
+
+    /**
+     * Returns the Route targets.
+     *
+     * @return RouteTarget List
+     */
+    public List<VpnRouteTarget> exportRouteTarget() {
+        return exportRtList;
+    }
+
+    /**
+     * Set import list.
+     *
+     * @param importRtList import list
+     */
+    public void setImportRtList(List<VpnRouteTarget> importRtList) {
+        this.importRtList = importRtList;
+    }
+
+    /**
+     * Set export list.
+     *
+     * @param exportRtList export list
+     */
+    public void setExportRtList(List<VpnRouteTarget> exportRtList) {
+        this.exportRtList = exportRtList;
+    }
+
+    /**
+     * Returns the label.
+     *
+     * @return Label
+     */
+    public Label label() {
+        return label;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(prefixMac,
+                            prefix,
+                            nextHop,
+                            rd,
+                            importRtList,
+                            exportRtList,
+                            label);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnRoute)) {
+            return false;
+        }
+
+        EvpnRoute that = (EvpnRoute) other;
+
+        return Objects.equals(prefixMac, prefixMac)
+                && Objects.equals(prefix, that.prefix)
+                && Objects.equals(nextHop, that.nextHop)
+                && Objects.equals(this.rd, that.rd)
+                && Objects.equals(this.importRtList, that.importRtList)
+                && Objects.equals(this.exportRtList, that.exportRtList)
+                && Objects.equals(this.label, that.label);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("prefixMac", prefixMac)
+                .add("prefix", prefix)
+                .add("nextHop", nextHop)
+                .add("rd", this.rd)
+                .add("import rt", this.importRtList)
+                .add("export rt", this.exportRtList)
+                .add("label", this.label)
+                .toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteAdminService.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteAdminService.java
new file mode 100644
index 0000000..cc9e200
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteAdminService.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Collection;
+
+/**
+ * Service allowing mutation of EVPN routing state.
+ */
+public interface EvpnRouteAdminService extends EvpnRouteService {
+
+    /**
+     * Updates the given routes in the route service.
+     *
+     * @param routes collection of routes to update
+     */
+    void update(Collection<EvpnRoute> routes);
+
+    /**
+     * Withdraws the given routes from the route service.
+     *
+     * @param routes collection of routes to withdraw
+     */
+    void withdraw(Collection<EvpnRoute> routes);
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteEvent.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteEvent.java
new file mode 100644
index 0000000..ae3d93a
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteEvent.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+import org.joda.time.LocalDateTime;
+import org.onosproject.event.AbstractEvent;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Describes an event about a route.
+ */
+public class EvpnRouteEvent extends AbstractEvent<EvpnRouteEvent.Type,
+        EvpnRoute> {
+
+    private final EvpnRoute prevSubject;
+    private final Collection<EvpnRoute> alternativeRoutes;
+
+    /**
+     * Route event type.
+     */
+    public enum Type {
+
+        /**
+         * Route is new and the next hop is resolved.
+         * <p>
+         * The subject of this event should be the route being added.
+         * The prevSubject of this event should be null.
+         * </p>
+         */
+        ROUTE_ADDED,
+
+        /**
+         * Route has updated information.
+         * <p>
+         * The subject of this event should be the new route.
+         * The prevSubject of this event should be the old route.
+         * </p>
+         */
+        ROUTE_UPDATED,
+
+        /**
+         * Route was removed or the next hop becomes unresolved.
+         * <p>
+         * The subject of this event should be the route being removed.
+         * The prevSubject of this event should be null.
+         * </p>
+         */
+        ROUTE_REMOVED,
+
+        /**
+         * The set of alternative routes for the subject's prefix has changed,
+         * but the best route is still the same.
+         * <p>
+         * The subject is the best route for the prefix (which has already been
+         * notified in a previous event).
+         * The prevSubject of this event is null.
+         * The alternatives contains the new set of alternative routes.
+         * </p>
+         */
+        ALTERNATIVE_ROUTES_CHANGED
+    }
+
+    /**
+     * Creates a new route event without specifying previous subject.
+     *
+     * @param type    event type
+     * @param subject event subject
+     */
+    public EvpnRouteEvent(Type type, EvpnRoute subject) {
+        this(type, subject, null, Collections.emptySet());
+    }
+
+    /**
+     * Creates a new route event without specifying previous subject.
+     *
+     * @param type         event type
+     * @param subject      event subject
+     * @param alternatives alternative routes for subject's prefix
+     */
+    public EvpnRouteEvent(Type type, EvpnRoute subject,
+                          Collection<EvpnRoute> alternatives) {
+        this(type, subject, null, alternatives);
+    }
+
+    /**
+     * Creates a new route event.
+     *
+     * @param type    event type
+     * @param subject event subject
+     * @param time    event time
+     */
+    protected EvpnRouteEvent(Type type, EvpnRoute subject, long time) {
+        super(type, subject, time);
+        this.prevSubject = null;
+
+        this.alternativeRoutes = Collections.emptySet();
+    }
+
+    /**
+     * Creates a new route event with previous subject.
+     *
+     * @param type        event type
+     * @param subject     event subject
+     * @param prevSubject previous subject
+     */
+    public EvpnRouteEvent(Type type, EvpnRoute subject, EvpnRoute prevSubject) {
+        this(type, subject, prevSubject, Collections.emptySet());
+    }
+
+    /**
+     * Creates a new route event with a previous subject and alternative routes.
+     *
+     * @param type         event type
+     * @param subject      event subject
+     * @param prevSubject  previous subject
+     * @param alternatives alternative routes for subject's prefix
+     */
+    public EvpnRouteEvent(Type type, EvpnRoute subject, EvpnRoute prevSubject,
+                          Collection<EvpnRoute> alternatives) {
+        super(type, subject);
+        this.prevSubject = prevSubject;
+        this.alternativeRoutes = alternatives;
+    }
+
+    /**
+     * Returns the previous subject of the event.
+     *
+     * @return previous subject to which this event pertains
+     */
+    public EvpnRoute prevSubject() {
+        return prevSubject;
+    }
+
+    /**
+     * Returns the set of alternative routes for the subject's prefix.
+     *
+     * @return alternative routes
+     */
+    public Collection<EvpnRoute> alternatives() {
+        return alternativeRoutes;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(subject(), type(), prevSubject(), alternativeRoutes);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnRouteEvent)) {
+            return false;
+        }
+
+        EvpnRouteEvent that = (EvpnRouteEvent) other;
+
+        return Objects.equals(this.subject(), that.subject()) &&
+                Objects.equals(this.type(), that.type()) &&
+                Objects.equals(this.prevSubject, that.prevSubject) &&
+                Objects.equals(this.alternativeRoutes, that.alternativeRoutes);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("time", new LocalDateTime(time()))
+                .add("type", type())
+                .add("subject", subject())
+                .add("prevSubject", prevSubject)
+                .add("alternatives", alternativeRoutes)
+                .toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteListener.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteListener.java
new file mode 100644
index 0000000..32a35c2
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteListener.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Listener for route events.
+ */
+public interface EvpnRouteListener extends EventListener<EvpnRouteEvent> {
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteService.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteService.java
new file mode 100644
index 0000000..ca9c031
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteService.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Collection;
+
+import org.onosproject.event.ListenerService;
+
+/**
+ * EVPN route service.
+ */
+public interface EvpnRouteService extends ListenerService<EvpnRouteEvent,
+        EvpnRouteListener> {
+
+
+    /**
+     * Returns the set of route tables in the system.
+     *
+     * @return collection of route table IDs.
+     */
+    Collection<EvpnRouteTableId> getRouteTables();
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteSet.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteSet.java
new file mode 100644
index 0000000..707df22
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteSet.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A set of routes for a particular prefix in a route table.
+ */
+public class EvpnRouteSet {
+    private final EvpnRouteTableId tableId;
+
+    private final EvpnPrefix prefix;
+    private final Set<EvpnRoute> routes;
+
+    /**
+     * Creates a new route set.
+     *
+     * @param tableId route table ID
+     * @param prefix  IP prefix
+     * @param routes  routes for the given prefix
+     */
+    public EvpnRouteSet(EvpnRouteTableId tableId, EvpnPrefix prefix, Set<EvpnRoute>
+            routes) {
+        this.tableId = checkNotNull(tableId);
+        this.prefix = checkNotNull(prefix);
+        this.routes = ImmutableSet.copyOf(checkNotNull(routes));
+    }
+
+    /**
+     * Returns the route table ID.
+     *
+     * @return route table ID
+     */
+    public EvpnRouteTableId tableId() {
+        return tableId;
+    }
+
+    /**
+     * Returns the IP prefix.
+     *
+     * @return IP prefix
+     */
+    public EvpnPrefix prefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the set of routes.
+     *
+     * @return routes
+     */
+    public Set<EvpnRoute> routes() {
+        return routes;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(tableId, prefix, routes);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof EvpnRouteSet)) {
+            return false;
+        }
+
+        EvpnRouteSet that = (EvpnRouteSet) other;
+
+        return Objects.equals(this.tableId, that.tableId) &&
+                Objects.equals(this.prefix, that.prefix) &&
+                Objects.equals(this.routes, that.routes);
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteStore.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteStore.java
new file mode 100644
index 0000000..c06704f
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteStore.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.store.Store;
+
+/**
+ * EVPN route store.
+ */
+public interface EvpnRouteStore extends Store<EvpnInternalRouteEvent,
+        EvpnRouteStoreDelegate> {
+
+    /**
+     * Adds or updates the given route in the store.
+     *
+     * @param route route to add or update
+     */
+    void updateRoute(EvpnRoute route);
+
+    /**
+     * Removes the given route from the store.
+     *
+     * @param route route to remove
+     */
+    void removeRoute(EvpnRoute route);
+
+    /**
+     * Returns the IDs for all route tables in the store.
+     *
+     * @return route table IDs
+     */
+    Set<EvpnRouteTableId> getRouteTables();
+
+    /**
+     * Returns the routes in the given route table, grouped by prefix.
+     *
+     * @param table route table ID
+     * @return routes
+     */
+    Collection<EvpnRouteSet> getRoutes(EvpnRouteTableId table);
+
+    /**
+     * Returns the routes that point to the given next hop IP address.
+     *
+     * @param ip IP address of the next hop
+     * @return routes for the given next hop
+     */
+    // TODO think about including route table info
+    Collection<EvpnRoute> getRoutesForNextHop(IpAddress ip);
+
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteStoreDelegate.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteStoreDelegate.java
new file mode 100644
index 0000000..d714adc
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteStoreDelegate.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Route store delegate abstraction.
+ */
+public interface EvpnRouteStoreDelegate extends
+        StoreDelegate<EvpnInternalRouteEvent> {
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteTableId.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteTableId.java
new file mode 100644
index 0000000..846a8d1
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnRouteTableId.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+/**
+ * Identifier for an EVPN routing table.
+ */
+public class EvpnRouteTableId {
+    private final String name;
+
+    /**
+     * Creates a new route table ID.
+     *
+     * @param name unique name for the route table
+     */
+    public EvpnRouteTableId(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of the route table.
+     *
+     * @return table name
+     */
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof EvpnRouteTableId) {
+            EvpnRouteTableId that = (EvpnRouteTableId) obj;
+
+            return Objects.equals(this.name, that.name);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name);
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnTable.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnTable.java
new file mode 100755
index 0000000..0b3379f
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/EvpnTable.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Collection;
+
+import org.onlab.packet.IpAddress;
+
+/**
+ * Represents a route table that stores routes.
+ */
+public interface EvpnTable {
+
+    /**
+     * Adds a route to the route table.
+     *
+     * @param route route
+     */
+    void update(EvpnRoute route);
+
+    /**
+     * Removes a route from the route table.
+     *
+     * @param route route
+     */
+    void remove(EvpnRoute route);
+
+    /**
+     * Returns the route table ID.
+     *
+     * @return route table ID
+     */
+    EvpnRouteTableId id();
+
+    /**
+     * Returns all routes in the route table.
+     *
+     * @return collection of routes, grouped by prefix
+     */
+    Collection<EvpnRouteSet> getRoutes();
+
+    /**
+     * Returns the routes in this table pertaining to a given prefix.
+     *
+     * @param prefix IP prefix
+     * @return routes for the prefix
+     */
+    EvpnRouteSet getRoutes(EvpnPrefix prefix);
+
+    /**
+     * Returns all routes that have the given next hop.
+     *
+     * @param nextHop next hop IP address
+     * @return collection of routes
+     */
+    Collection<EvpnRoute> getRoutesForNextHop(IpAddress nextHop);
+
+    /**
+     * Releases route table resources held locally.
+     */
+    void shutdown();
+
+    /**
+     * Releases route table resources across the entire cluster.
+     */
+    void destroy();
+
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/Label.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/Label.java
new file mode 100644
index 0000000..8d90611
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/Label.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Represents label of the route.
+ */
+public final class Label {
+    private final int label;
+
+    /**
+     * Constructor to initialize parameters.
+     *
+     * @param label route label
+     */
+    private Label(int label) {
+        this.label = label;
+    }
+
+    /**
+     * Creates the label for evpn route.
+     *
+     * @param label label of evpn route
+     * @return Label
+     */
+    public static Label label(int label) {
+        return new Label(label);
+    }
+
+    /**
+     * Returns the label.
+     *
+     * @return label
+     */
+    public int getLabel() {
+        return label;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(label);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof Label) {
+            Label other = (Label) obj;
+            return Objects.equals(label, other.label);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("label", label).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/RouteDistinguisher.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/RouteDistinguisher.java
new file mode 100644
index 0000000..ca217b6
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/RouteDistinguisher.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents Route Distinguisher of device in the network.
+ */
+public final class RouteDistinguisher {
+    private final String routeDistinguisher;
+
+    /**
+     * Constructor to initialize parameters.
+     *
+     * @param routeDistinguisher route distinguisher
+     */
+    private RouteDistinguisher(String routeDistinguisher) {
+        this.routeDistinguisher = routeDistinguisher;
+    }
+
+    /**
+     * Creates the route distinguisher.
+     *
+     * @param routeDistinguisher route distinguisher
+     * @return RouteDistinguisher
+     */
+    public static RouteDistinguisher routeDistinguisher(String routeDistinguisher) {
+        checkNotNull(routeDistinguisher);
+        return new RouteDistinguisher(routeDistinguisher);
+    }
+
+    /**
+     * get route distinguisher.
+     *
+     * @return distinguisher
+     */
+    public String getRouteDistinguisher() {
+        return routeDistinguisher;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(routeDistinguisher);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof RouteDistinguisher) {
+            RouteDistinguisher other = (RouteDistinguisher) obj;
+            return Objects.equals(this.routeDistinguisher, other.routeDistinguisher);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("routeDistinguisher", this.routeDistinguisher).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/VpnRouteTarget.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/VpnRouteTarget.java
new file mode 100644
index 0000000..51a9a59
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/VpnRouteTarget.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Represents Route target of vpn instance.
+ */
+public final class VpnRouteTarget {
+    private final String routeTarget;
+
+    /**
+     * Constructor to initialize parameters.
+     *
+     * @param routeTarget route target
+     */
+    private VpnRouteTarget(String routeTarget) {
+        this.routeTarget = routeTarget;
+    }
+
+    /**
+     * Creates the vpn route target.
+     *
+     * @param routeTarget route target
+     * @return route target
+     */
+    public static VpnRouteTarget routeTarget(String routeTarget) {
+        return new VpnRouteTarget(routeTarget);
+    }
+
+    /**
+     * get the route target.
+     *
+     * @return route target
+     */
+    public String getRouteTarget() {
+        return routeTarget;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(routeTarget);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof VpnRouteTarget) {
+            VpnRouteTarget other = (VpnRouteTarget) obj;
+            return Objects.equals(routeTarget, other.routeTarget);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("routeTarget", routeTarget).toString();
+    }
+}
diff --git a/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/package-info.java b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/package-info.java
new file mode 100644
index 0000000..3514c80
--- /dev/null
+++ b/apps/evpn-route-service/api/src/main/java/org/onosproject/evpnrouteservice/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Unicast routing service.
+ */
+package org.onosproject.evpnrouteservice;
diff --git a/apps/evpn-route-service/app/BUCK b/apps/evpn-route-service/app/BUCK
new file mode 100644
index 0000000..1231207
--- /dev/null
+++ b/apps/evpn-route-service/app/BUCK
@@ -0,0 +1,16 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//utils/misc:onlab-misc',
+    '//core/store/serializers:onos-core-serializers',
+    '//apps/evpn-route-service/api:onos-apps-evpn-route-service-api',
+]
+
+TEST_DEPS = [
+    '//lib:TEST',
+    '//core/api:onos-api-tests',
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+)
diff --git a/apps/evpn-route-service/app/pom.xml b/apps/evpn-route-service/app/pom.xml
new file mode 100644
index 0000000..780a9db
--- /dev/null
+++ b/apps/evpn-route-service/app/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-present Open Networking Foundation
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<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-app-evpn-route-service</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.11.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-app-evpn-route-service-app</artifactId>
+    <packaging>bundle</packaging>
+
+    <url>http://onosproject.org</url>
+
+    <description>EVPN Routing Application Implementation</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-evpn-route-service-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+    </dependencies>
+
+
+</project>
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnListenerQueue.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnListenerQueue.java
new file mode 100644
index 0000000..ce3d012
--- /dev/null
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnListenerQueue.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice.impl;
+
+import org.onosproject.evpnrouteservice.EvpnRouteEvent;
+
+/**
+ * Queues updates for a route listener to ensure they are received in the
+ * correct order.
+ */
+interface EvpnListenerQueue {
+
+    /**
+     * Posts an event to the listener.
+     *
+     * @param event event
+     */
+    void post(EvpnRouteEvent event);
+
+    /**
+     * Initiates event delivery to the listener.
+     */
+    void start();
+
+    /**
+     * Halts event delivery to the listener.
+     */
+    void stop();
+}
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnRouteManager.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnRouteManager.java
new file mode 100644
index 0000000..19e6311
--- /dev/null
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/EvpnRouteManager.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice.impl;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+
+import javax.annotation.concurrent.GuardedBy;
+
+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.evpnrouteservice.EvpnInternalRouteEvent;
+import org.onosproject.evpnrouteservice.EvpnRoute;
+import org.onosproject.evpnrouteservice.EvpnRouteAdminService;
+import org.onosproject.evpnrouteservice.EvpnRouteEvent;
+import org.onosproject.evpnrouteservice.EvpnRouteListener;
+import org.onosproject.evpnrouteservice.EvpnRouteService;
+import org.onosproject.evpnrouteservice.EvpnRouteSet;
+import org.onosproject.evpnrouteservice.EvpnRouteStore;
+import org.onosproject.evpnrouteservice.EvpnRouteStoreDelegate;
+import org.onosproject.evpnrouteservice.EvpnRouteTableId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+
+/**
+ * Implementation of the EVPN route service.
+ */
+@Service
+@Component
+public class EvpnRouteManager implements EvpnRouteService,
+        EvpnRouteAdminService {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EvpnRouteStore evpnRouteStore;
+
+    @GuardedBy(value = "this")
+    private Map<EvpnRouteListener, EvpnListenerQueue> listeners = new
+            HashMap<>();
+
+    private ThreadFactory threadFactory;
+
+    private EvpnRouteStoreDelegate evpnRouteStoreDelegate = new
+            InternalEvpnRouteStoreDelegate();
+
+    @Activate
+    protected void activate() {
+        threadFactory = groupedThreads("onos/route", "listener-%d", log);
+        evpnRouteStore.setDelegate(evpnRouteStoreDelegate);
+
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        evpnRouteStore.unsetDelegate(evpnRouteStoreDelegate);
+        listeners.values().forEach(EvpnListenerQueue::stop);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * In a departure from other services in ONOS, calling addListener will
+     * cause all current routes to be pushed to the listener before any new
+     * events are sent. This allows a listener to easily get the exact set of
+     * routes without worrying about missing any.
+     *
+     * @param listener listener to be added
+     */
+    @Override
+    public void addListener(EvpnRouteListener listener) {
+        synchronized (this) {
+            EvpnListenerQueue l = createListenerQueue(listener);
+
+            evpnRouteStore.getRouteTables().forEach(routeTableId
+                                                            -> {
+                Collection<EvpnRouteSet> routes
+                        = evpnRouteStore.getRoutes(routeTableId);
+                if (routes != null) {
+                    routes.forEach(route -> {
+                        Collection<EvpnRoute> evpnRoutes = route.routes();
+                        for (EvpnRoute evpnRoute : evpnRoutes) {
+                            l.post(new EvpnRouteEvent(
+                                    EvpnRouteEvent.Type.ROUTE_ADDED,
+                                    evpnRoute,
+                                    route.routes()));
+                        }
+                    });
+                }
+            });
+            listeners.put(listener, l);
+
+            l.start();
+            log.debug("Route synchronization complete");
+        }
+    }
+
+    @Override
+    public void removeListener(EvpnRouteListener listener) {
+        synchronized (this) {
+            EvpnListenerQueue l = listeners.remove(listener);
+            if (l != null) {
+                l.stop();
+            }
+        }
+    }
+
+    /**
+     * Posts an event to all listeners.
+     *
+     * @param event event
+     */
+
+    private void post(EvpnRouteEvent event) {
+        if (event != null) {
+            log.debug("Sending event {}", event);
+            synchronized (this) {
+                listeners.values().forEach(l -> l.post(event));
+            }
+        }
+    }
+
+
+    public Collection<EvpnRouteTableId> getRouteTables() {
+        return evpnRouteStore.getRouteTables();
+    }
+
+    @Override
+    public void update(Collection<EvpnRoute> routes) {
+        synchronized (this) {
+            routes.forEach(route -> {
+                log.debug("Received update {}", route);
+                evpnRouteStore.updateRoute(route);
+            });
+        }
+    }
+
+    @Override
+    public void withdraw(Collection<EvpnRoute> routes) {
+        synchronized (this) {
+            routes.forEach(route -> {
+                log.debug("Received withdraw {}", route);
+                evpnRouteStore.removeRoute(route);
+            });
+        }
+    }
+
+    /**
+     * Creates a new listener queue.
+     *
+     * @param listener route listener
+     * @return listener queue
+     */
+    DefaultListenerQueue createListenerQueue(EvpnRouteListener listener) {
+        return new DefaultListenerQueue(listener);
+    }
+
+    /**
+     * Default route listener queue.
+     */
+    private class DefaultListenerQueue implements EvpnListenerQueue {
+
+        private final ExecutorService executorService;
+        private final BlockingQueue<EvpnRouteEvent> queue;
+        private final EvpnRouteListener listener;
+
+        /**
+         * Creates a new listener queue.
+         *
+         * @param listener route listener to queue updates for
+         */
+        public DefaultListenerQueue(EvpnRouteListener listener) {
+            this.listener = listener;
+            queue = new LinkedBlockingQueue<>();
+            executorService = newSingleThreadExecutor(threadFactory);
+        }
+
+        @Override
+        public void post(EvpnRouteEvent event) {
+            queue.add(event);
+        }
+
+        @Override
+        public void start() {
+            executorService.execute(this::poll);
+        }
+
+        @Override
+        public void stop() {
+            executorService.shutdown();
+        }
+
+        private void poll() {
+            while (true) {
+                try {
+                    listener.event(queue.take());
+                } catch (InterruptedException e) {
+                    log.info("Route listener event thread shutting down: {}", e.getMessage());
+                    break;
+                } catch (Exception e) {
+                    log.warn("Exception during route event handler", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Delegate to receive events from the route store.
+     */
+    private class InternalEvpnRouteStoreDelegate implements
+            EvpnRouteStoreDelegate {
+        EvpnRouteSet routes;
+
+        @Override
+        public void notify(EvpnInternalRouteEvent event) {
+            switch (event.type()) {
+                case ROUTE_ADDED:
+                    routes = event.subject();
+                    if (routes != null) {
+                        Collection<EvpnRoute> evpnRoutes = routes.routes();
+                        for (EvpnRoute evpnRoute : evpnRoutes) {
+                            post(new EvpnRouteEvent(
+                                    EvpnRouteEvent.Type.ROUTE_ADDED,
+                                    evpnRoute,
+                                    routes.routes()));
+                        }
+                    }
+                    break;
+                case ROUTE_REMOVED:
+                    routes = event.subject();
+                    if (routes != null) {
+                        Collection<EvpnRoute> evpnRoutes = routes.routes();
+                        for (EvpnRoute evpnRoute : evpnRoutes) {
+                            post(new EvpnRouteEvent(
+                                    EvpnRouteEvent.Type.ROUTE_REMOVED,
+                                    evpnRoute,
+                                    routes.routes()));
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+}
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/package-info.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/package-info.java
new file mode 100644
index 0000000..80892c9
--- /dev/null
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implementation of route service.
+ */
+package org.onosproject.evpnrouteservice.impl;
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/DistributedEvpnRouteStore.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/DistributedEvpnRouteStore.java
new file mode 100644
index 0000000..de1dbd6
--- /dev/null
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/DistributedEvpnRouteStore.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice.store;
+
+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.onlab.packet.IpAddress;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.evpnrouteservice.EvpnInternalRouteEvent;
+import org.onosproject.evpnrouteservice.EvpnRoute;
+import org.onosproject.evpnrouteservice.EvpnRouteSet;
+import org.onosproject.evpnrouteservice.EvpnRouteStore;
+import org.onosproject.evpnrouteservice.EvpnRouteStoreDelegate;
+import org.onosproject.evpnrouteservice.EvpnRouteTableId;
+import org.onosproject.evpnrouteservice.EvpnTable;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.service.DistributedSet;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.SetEvent;
+import org.onosproject.store.service.SetEventListener;
+import org.onosproject.store.service.StorageService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onlab.util.Tools.groupedThreads;
+
+/**
+ * Route store based on distributed storage.
+ */
+@Service
+@Component
+public class DistributedEvpnRouteStore extends
+        AbstractStore<EvpnInternalRouteEvent,
+                EvpnRouteStoreDelegate>
+        implements EvpnRouteStore {
+
+    private static final Logger log = LoggerFactory
+            .getLogger(DistributedEvpnRouteStore.class);
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    public StorageService storageService;
+
+    private static final EvpnRouteTableId EVPN_IPV4 = new EvpnRouteTableId("evpn_ipv4");
+    private static final EvpnRouteTableId EVPN_IPV6 = new EvpnRouteTableId("evpn_ipv6");
+
+    private final SetEventListener<EvpnRouteTableId> masterRouteTableListener =
+            new MasterRouteTableListener();
+    private final EvpnRouteStoreDelegate ourDelegate = new
+            InternalEvpnRouteStoreDelegate();
+
+    // Stores the route tables that have been created
+    public DistributedSet<EvpnRouteTableId> masterRouteTable;
+    // Local memory map to store route table object
+    public Map<EvpnRouteTableId, EvpnTable> routeTables;
+
+    private ExecutorService executor;
+
+
+    /**
+     * Sets up distributed route store.
+     */
+    @Activate
+    public void activate() {
+        routeTables = new ConcurrentHashMap<>();
+        executor = Executors.newSingleThreadExecutor(groupedThreads("onos/route", "store", log));
+
+        KryoNamespace masterRouteTableSerializer = KryoNamespace.newBuilder()
+                .register(EvpnRouteTableId.class)
+                .build();
+
+        masterRouteTable = storageService.<EvpnRouteTableId>setBuilder()
+                .withName("onos-master-route-table")
+                .withSerializer(Serializer.using(masterRouteTableSerializer))
+                .build()
+                .asDistributedSet();
+
+        masterRouteTable.forEach(this::createRouteTable);
+
+        masterRouteTable.addListener(masterRouteTableListener);
+
+        // Add default tables (add is idempotent)
+        masterRouteTable.add(EVPN_IPV4);
+        masterRouteTable.add(EVPN_IPV6);
+
+        log.info("Started");
+    }
+
+    /**
+     * Cleans up distributed route store.
+     */
+    @Deactivate
+    public void deactivate() {
+        masterRouteTable.removeListener(masterRouteTableListener);
+
+        routeTables.values().forEach(EvpnTable::shutdown);
+
+        log.info("Stopped");
+    }
+
+    @Override
+    public void updateRoute(EvpnRoute route) {
+        getDefaultRouteTable(route).update(route);
+    }
+
+    @Override
+    public void removeRoute(EvpnRoute route) {
+        getDefaultRouteTable(route).remove(route);
+    }
+
+    @Override
+    public Set<EvpnRouteTableId> getRouteTables() {
+        return ImmutableSet.copyOf(masterRouteTable);
+    }
+
+    @Override
+    public Collection<EvpnRouteSet> getRoutes(EvpnRouteTableId table) {
+        EvpnTable routeTable = routeTables.get(table);
+        if (routeTable == null) {
+            return Collections.emptySet();
+        } else {
+            return ImmutableSet.copyOf(routeTable.getRoutes());
+        }
+    }
+
+    @Override
+    public Collection<EvpnRoute> getRoutesForNextHop(IpAddress ip) {
+        return getDefaultRouteTable(ip).getRoutesForNextHop(ip);
+    }
+
+    private void createRouteTable(EvpnRouteTableId tableId) {
+        routeTables.computeIfAbsent(tableId, id -> new EvpnRouteTable(id,
+                                                                      ourDelegate, storageService, executor));
+    }
+
+    private void destroyRouteTable(EvpnRouteTableId tableId) {
+        EvpnTable table = routeTables.remove(tableId);
+        if (table != null) {
+            table.destroy();
+        }
+    }
+
+    private EvpnTable getDefaultRouteTable(EvpnRoute route) {
+        return getDefaultRouteTable(route.prefixIp().address());
+    }
+
+    private EvpnTable getDefaultRouteTable(IpAddress ip) {
+        EvpnRouteTableId routeTableId = (ip.isIp4()) ? EVPN_IPV4 : EVPN_IPV6;
+        return routeTables.getOrDefault(routeTableId, EmptyEvpnRouteTable
+                .instance());
+    }
+
+    private class InternalEvpnRouteStoreDelegate implements
+            EvpnRouteStoreDelegate {
+        @Override
+        public void notify(EvpnInternalRouteEvent event) {
+            executor.execute(() -> DistributedEvpnRouteStore
+                    .this.notifyDelegate(event));
+        }
+    }
+
+    private class MasterRouteTableListener implements SetEventListener<EvpnRouteTableId> {
+        @Override
+        public void event(SetEvent<EvpnRouteTableId> event) {
+            switch (event.type()) {
+                case ADD:
+                    executor.execute(() -> createRouteTable(event.entry()));
+                    break;
+                case REMOVE:
+                    executor.execute(() -> destroyRouteTable(event.entry()));
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/EmptyEvpnRouteTable.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/EmptyEvpnRouteTable.java
new file mode 100644
index 0000000..f49a174
--- /dev/null
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/EmptyEvpnRouteTable.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice.store;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.evpnrouteservice.EvpnPrefix;
+import org.onosproject.evpnrouteservice.EvpnRoute;
+import org.onosproject.evpnrouteservice.EvpnRouteSet;
+import org.onosproject.evpnrouteservice.EvpnRouteTableId;
+import org.onosproject.evpnrouteservice.EvpnTable;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Route table that contains no routes.
+ */
+public final class EmptyEvpnRouteTable implements EvpnTable {
+
+    private final EvpnRouteTableId id = new EvpnRouteTableId("empty");
+
+    private static final EmptyEvpnRouteTable INSTANCE = new EmptyEvpnRouteTable();
+
+    /**
+     * Returns the instance of the empty route table.
+     *
+     * @return empty route table
+     */
+    public static EmptyEvpnRouteTable instance() {
+        return INSTANCE;
+    }
+
+    private EmptyEvpnRouteTable() {
+    }
+
+    @Override
+    public void update(EvpnRoute route) {
+
+    }
+
+    @Override
+    public void remove(EvpnRoute route) {
+
+    }
+
+    @Override
+    public EvpnRouteTableId id() {
+        return id;
+    }
+
+    @Override
+    public Collection<EvpnRouteSet> getRoutes() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public EvpnRouteSet getRoutes(EvpnPrefix prefix) {
+        return null;
+    }
+
+    @Override
+    public Collection<EvpnRoute> getRoutesForNextHop(IpAddress nextHop) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void shutdown() {
+
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/EvpnRouteTable.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/EvpnRouteTable.java
new file mode 100644
index 0000000..2c3e07b
--- /dev/null
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/EvpnRouteTable.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.evpnrouteservice.store;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.evpnrouteservice.EvpnInternalRouteEvent;
+import org.onosproject.evpnrouteservice.EvpnPrefix;
+import org.onosproject.evpnrouteservice.EvpnRoute;
+import org.onosproject.evpnrouteservice.EvpnRouteSet;
+import org.onosproject.evpnrouteservice.EvpnRouteStoreDelegate;
+import org.onosproject.evpnrouteservice.EvpnRouteTableId;
+import org.onosproject.evpnrouteservice.EvpnTable;
+import org.onosproject.evpnrouteservice.Label;
+import org.onosproject.evpnrouteservice.RouteDistinguisher;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.DistributedPrimitive;
+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.onosproject.store.service.Versioned;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default implementation of a route table based on a consistent map.
+ */
+public class EvpnRouteTable implements EvpnTable {
+
+    private final EvpnRouteTableId id;
+    private final ConsistentMap<EvpnPrefix, Set<EvpnRoute>> routes;
+    private final EvpnRouteStoreDelegate delegate;
+    private final ExecutorService executor;
+    private final RouteTableListener listener = new RouteTableListener();
+
+    private final Consumer<DistributedPrimitive.Status> statusChangeListener;
+
+    /**
+     * Creates a new route table.
+     *
+     * @param id             route table ID
+     * @param delegate       route store delegate to notify of events
+     * @param storageService storage service
+     * @param executor       executor service
+     */
+    public EvpnRouteTable(EvpnRouteTableId id, EvpnRouteStoreDelegate delegate,
+                          StorageService storageService, ExecutorService executor) {
+        this.delegate = checkNotNull(delegate);
+        this.id = checkNotNull(id);
+        this.routes = buildRouteMap(checkNotNull(storageService));
+        this.executor = checkNotNull(executor);
+
+        statusChangeListener = status -> {
+            if (status.equals(DistributedPrimitive.Status.ACTIVE)) {
+                executor.execute(this::notifyExistingRoutes);
+            }
+        };
+        routes.addStatusChangeListener(statusChangeListener);
+
+        notifyExistingRoutes();
+
+        routes.addListener(listener);
+    }
+
+    private void notifyExistingRoutes() {
+        routes.entrySet().stream()
+                .map(e -> new EvpnInternalRouteEvent(
+                        EvpnInternalRouteEvent.Type.ROUTE_ADDED,
+                        new EvpnRouteSet(id, e.getKey(), e.getValue().value())))
+                .forEach(delegate::notify);
+    }
+
+    private ConsistentMap<EvpnPrefix, Set<EvpnRoute>> buildRouteMap(StorageService
+                                                                            storageService) {
+        KryoNamespace routeTableSerializer = KryoNamespace.newBuilder()
+                .register(KryoNamespaces.API)
+                .register(KryoNamespaces.MISC)
+                .register(EvpnRoute.class)
+                .register(EvpnPrefix.class)
+                .register(RouteDistinguisher.class)
+                .register(MacAddress.class)
+                .register(IpPrefix.class)
+                .register(EvpnRoute.Source.class)
+                .register(IpAddress.class)
+                .register(VpnRouteTarget.class)
+                .register(Label.class)
+                .register(EvpnRouteTableId.class)
+                .build();
+        return storageService.<EvpnPrefix, Set<EvpnRoute>>consistentMapBuilder()
+                .withName("onos-evpn-routes-" + id.name())
+                .withRelaxedReadConsistency()
+                .withSerializer(Serializer.using(routeTableSerializer))
+                .build();
+    }
+
+    @Override
+    public EvpnRouteTableId id() {
+        return id;
+    }
+
+    @Override
+    public void shutdown() {
+        routes.removeStatusChangeListener(statusChangeListener);
+        routes.removeListener(listener);
+    }
+
+    @Override
+    public void destroy() {
+        shutdown();
+        routes.destroy();
+    }
+
+    @Override
+    public void update(EvpnRoute route) {
+        routes.compute(route.evpnPrefix(), (prefix, set) -> {
+            if (set == null) {
+                set = new HashSet<>();
+            }
+            set.add(route);
+            return set;
+        });
+    }
+
+    @Override
+    public void remove(EvpnRoute route) {
+        routes.compute(route.evpnPrefix(), (prefix, set) -> {
+            if (set != null) {
+                set.remove(route);
+                if (set.isEmpty()) {
+                    return null;
+                }
+                return set;
+            }
+            return null;
+        });
+    }
+
+    @Override
+    public Collection<EvpnRouteSet> getRoutes() {
+        return routes.entrySet().stream()
+                .map(e -> new EvpnRouteSet(id, e.getKey(), e.getValue().value()))
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public EvpnRouteSet getRoutes(EvpnPrefix prefix) {
+        Versioned<Set<EvpnRoute>> routeSet = routes.get(prefix);
+
+        if (routeSet != null) {
+            return new EvpnRouteSet(id, prefix, routeSet.value());
+        }
+        return null;
+    }
+
+    @Override
+    public Collection<EvpnRoute> getRoutesForNextHop(IpAddress nextHop) {
+        // TODO index
+        return routes.values().stream()
+                .flatMap(v -> v.value().stream())
+                .filter(r -> r.nextHop().equals(nextHop))
+                .collect(Collectors.toSet());
+    }
+
+    private class RouteTableListener
+            implements MapEventListener<EvpnPrefix, Set<EvpnRoute>> {
+
+        private EvpnInternalRouteEvent createRouteEvent(
+                EvpnInternalRouteEvent.Type type, MapEvent<EvpnPrefix, Set<EvpnRoute>>
+                event) {
+            Set<EvpnRoute> currentRoutes =
+                    (event.newValue() == null) ? Collections.emptySet() : event.newValue().value();
+            return new EvpnInternalRouteEvent(type, new EvpnRouteSet(id, event
+                    .key(), currentRoutes));
+        }
+
+        @Override
+        public void event(MapEvent<EvpnPrefix, Set<EvpnRoute>> event) {
+            EvpnInternalRouteEvent ire = null;
+            switch (event.type()) {
+                case INSERT:
+                    ire = createRouteEvent(EvpnInternalRouteEvent.Type.ROUTE_ADDED, event);
+                    break;
+                case UPDATE:
+                    if (event.newValue().value().size() > event.oldValue().value().size()) {
+                        ire = createRouteEvent(EvpnInternalRouteEvent.Type.ROUTE_ADDED, event);
+                    } else {
+                        ire = createRouteEvent(EvpnInternalRouteEvent.Type.ROUTE_REMOVED, event);
+                    }
+                    break;
+                case REMOVE:
+                    ire = createRouteEvent(EvpnInternalRouteEvent.Type.ROUTE_REMOVED, event);
+                    break;
+                default:
+                    break;
+            }
+            if (ire != null) {
+                delegate.notify(ire);
+            }
+        }
+    }
+
+}
+
diff --git a/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/package-info.java b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/package-info.java
new file mode 100644
index 0000000..52e9d6c
--- /dev/null
+++ b/apps/evpn-route-service/app/src/main/java/org/onosproject/evpnrouteservice/store/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implementation of the unicast routing service.
+ */
+package org.onosproject.evpnrouteservice.store;
diff --git a/apps/evpn-route-service/pom.xml b/apps/evpn-route-service/pom.xml
new file mode 100644
index 0000000..a008f5f
--- /dev/null
+++ b/apps/evpn-route-service/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-present Open Networking Foundation
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<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>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-apps</artifactId>
+        <version>1.11.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-app-evpn-route-service</artifactId>
+    <packaging>pom</packaging>
+
+    <description>EVPN Routing Application</description>
+
+    <modules>
+        <module>api</module>
+        <module>app</module>
+    </modules>
+
+</project>
diff --git a/apps/evpnopenflow/BUCK b/apps/evpnopenflow/BUCK
index a244b1f..d3d92ee 100644
--- a/apps/evpnopenflow/BUCK
+++ b/apps/evpnopenflow/BUCK
@@ -7,6 +7,7 @@
   '//apps/gluon:onos-apps-gluon',
   '//apps/vtn/vtnrsc:onos-apps-vtn-vtnrsc',
   '//apps/route-service/api:onos-apps-route-service-api',
+  '//apps/evpn-route-service/api:onos-apps-evpn-route-service-api',
 ]
 
 TEST_DEPS = [
@@ -25,5 +26,6 @@
   url = 'http://onosproject.org',
   description = 'Ethernet VPN (EVPN) introduces a new model for Ethernet services delivery.' +
   'It enables integrated Layer 2 service over Ethernet with multihoming.',
-  required_apps = [ 'org.onosproject.route-service' ],
+  required_apps = [ 'org.onosproject.route-service', 'org.onosproject.evpnrouteservice',
+                    'org.onosproject.gluon', 'org.onosproject.vtn' ],
 )
diff --git a/apps/evpnopenflow/pom.xml b/apps/evpnopenflow/pom.xml
index 43cca85..a1ec1b8 100644
--- a/apps/evpnopenflow/pom.xml
+++ b/apps/evpnopenflow/pom.xml
@@ -110,5 +110,10 @@
             <artifactId>onos-apps-route-service-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-evpn-route-service-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/EvpnService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/EvpnService.java
index 560b96e..5a41454 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/EvpnService.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/EvpnService.java
@@ -17,7 +17,7 @@
 package org.onosproject.evpnopenflow.manager;
 
 import org.onosproject.evpnopenflow.rsc.VpnPort;
-import org.onosproject.incubator.net.routing.EvpnRoute;
+import org.onosproject.evpnrouteservice.EvpnRoute;
 import org.onosproject.net.Host;
 
 /**
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java
index 7f7314b..33d6924 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/manager/impl/EvpnManager.java
@@ -50,22 +50,22 @@
 import org.onosproject.incubator.net.resource.label.LabelResourceAdminService;
 import org.onosproject.incubator.net.resource.label.LabelResourceId;
 import org.onosproject.incubator.net.resource.label.LabelResourceService;
-import org.onosproject.incubator.net.routing.EvpnInstanceName;
-import org.onosproject.incubator.net.routing.EvpnInstanceNextHop;
-import org.onosproject.incubator.net.routing.EvpnInstancePrefix;
-import org.onosproject.incubator.net.routing.EvpnInstanceRoute;
-import org.onosproject.incubator.net.routing.EvpnNextHop;
-import org.onosproject.incubator.net.routing.EvpnRoute;
-import org.onosproject.incubator.net.routing.EvpnRoute.Source;
-import org.onosproject.incubator.net.routing.EvpnRouteAdminService;
-import org.onosproject.incubator.net.routing.EvpnRouteEvent;
-import org.onosproject.incubator.net.routing.EvpnRouteListener;
-import org.onosproject.incubator.net.routing.EvpnRouteService;
-import org.onosproject.incubator.net.routing.EvpnRouteSet;
-import org.onosproject.incubator.net.routing.EvpnRouteStore;
-import org.onosproject.incubator.net.routing.Label;
-import org.onosproject.incubator.net.routing.RouteDistinguisher;
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.EvpnInstanceName;
+import org.onosproject.evpnrouteservice.EvpnInstanceNextHop;
+import org.onosproject.evpnrouteservice.EvpnInstancePrefix;
+import org.onosproject.evpnrouteservice.EvpnInstanceRoute;
+import org.onosproject.evpnrouteservice.EvpnNextHop;
+import org.onosproject.evpnrouteservice.EvpnRoute;
+import org.onosproject.evpnrouteservice.EvpnRoute.Source;
+import org.onosproject.evpnrouteservice.EvpnRouteAdminService;
+import org.onosproject.evpnrouteservice.EvpnRouteEvent;
+import org.onosproject.evpnrouteservice.EvpnRouteListener;
+import org.onosproject.evpnrouteservice.EvpnRouteService;
+import org.onosproject.evpnrouteservice.EvpnRouteSet;
+import org.onosproject.evpnrouteservice.EvpnRouteStore;
+import org.onosproject.evpnrouteservice.Label;
+import org.onosproject.evpnrouteservice.RouteDistinguisher;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.Device;
@@ -103,7 +103,6 @@
 import java.util.List;
 import java.util.Set;
 
-import static com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type.Reference;
 import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID;
 import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ARP_PRIORITY;
 import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ARP_RESPONSE;
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnAfConfig.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnAfConfig.java
index 2481830..afa32a0 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnAfConfig.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnAfConfig.java
@@ -16,7 +16,7 @@
 
 package org.onosproject.evpnopenflow.rsc;
 
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnInstance.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnInstance.java
index e7f9c5d..62b1a70 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnInstance.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/DefaultVpnInstance.java
@@ -16,9 +16,9 @@
 
 package org.onosproject.evpnopenflow.rsc;
 
-import org.onosproject.incubator.net.routing.EvpnInstanceName;
-import org.onosproject.incubator.net.routing.RouteDistinguisher;
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.EvpnInstanceName;
+import org.onosproject.evpnrouteservice.RouteDistinguisher;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 
 import java.util.Objects;
 import java.util.Set;
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnAfConfig.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnAfConfig.java
index e9bd068..83d5686 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnAfConfig.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnAfConfig.java
@@ -16,7 +16,7 @@
 
 package org.onosproject.evpnopenflow.rsc;
 
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 
 /**
  * Representation of a VPN af configuration.
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstance.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstance.java
index d49027b..3c2d062 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstance.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/VpnInstance.java
@@ -16,9 +16,9 @@
 
 package org.onosproject.evpnopenflow.rsc;
 
-import org.onosproject.incubator.net.routing.EvpnInstanceName;
-import org.onosproject.incubator.net.routing.RouteDistinguisher;
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.EvpnInstanceName;
+import org.onosproject.evpnrouteservice.RouteDistinguisher;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 
 import java.util.Set;
 
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPrivateRouteListCommand.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPrivateRouteListCommand.java
index 2122320..f4ddf15 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPrivateRouteListCommand.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPrivateRouteListCommand.java
@@ -20,7 +20,7 @@
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.evpnopenflow.manager.EvpnService;
 import org.onosproject.evpnopenflow.manager.impl.EvpnManager;
-import org.onosproject.incubator.net.routing.EvpnInstanceRoute;
+import org.onosproject.evpnrouteservice.EvpnInstanceRoute;
 
 import java.util.Collection;
 
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPublicRouteListCommand.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPublicRouteListCommand.java
index 3067257..2ce5fb8 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPublicRouteListCommand.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/cli/EvpnPublicRouteListCommand.java
@@ -18,9 +18,9 @@
 
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.incubator.net.routing.EvpnRoute;
-import org.onosproject.incubator.net.routing.EvpnRouteSet;
-import org.onosproject.incubator.net.routing.EvpnRouteStore;
+import org.onosproject.evpnrouteservice.EvpnRoute;
+import org.onosproject.evpnrouteservice.EvpnRouteSet;
+import org.onosproject.evpnrouteservice.EvpnRouteStore;
 
 import java.util.Collection;
 
@@ -55,4 +55,4 @@
             }
         });
     }
-}
\ No newline at end of file
+}
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java
index 31714ad..ecde40d 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/VpnAfConfigService.java
@@ -18,7 +18,7 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import org.onosproject.evpnopenflow.rsc.VpnAfConfig;
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 
 import java.util.Collection;
 
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java
index fafd5d8..7645c2e 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpnafconfig/impl/VpnAfConfigManager.java
@@ -31,7 +31,7 @@
 import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigEvent;
 import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigListener;
 import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService;
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.StorageService;
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/VpnInstanceService.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/VpnInstanceService.java
index f233f29..a61a811 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/VpnInstanceService.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/VpnInstanceService.java
@@ -19,7 +19,7 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import org.onosproject.evpnopenflow.rsc.VpnInstance;
 import org.onosproject.evpnopenflow.rsc.VpnInstanceId;
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 
 import java.util.Collection;
 import java.util.Set;
diff --git a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java
index e0ec5a9..20c6d15 100644
--- a/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java
+++ b/apps/evpnopenflow/src/main/java/org/onosproject/evpnopenflow/rsc/vpninstance/impl/VpnInstanceManager.java
@@ -33,10 +33,10 @@
 import org.onosproject.evpnopenflow.rsc.VpnInstanceId;
 import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService;
 import org.onosproject.evpnopenflow.rsc.vpninstance.VpnInstanceService;
-import org.onosproject.incubator.net.routing.EvpnInstanceName;
+import org.onosproject.evpnrouteservice.EvpnInstanceName;
 import org.onosproject.routeservice.RouteAdminService;
-import org.onosproject.incubator.net.routing.RouteDistinguisher;
-import org.onosproject.incubator.net.routing.VpnRouteTarget;
+import org.onosproject.evpnrouteservice.RouteDistinguisher;
+import org.onosproject.evpnrouteservice.VpnRouteTarget;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.StorageService;
diff --git a/apps/pom.xml b/apps/pom.xml
index 0fd13fc..617daa6 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -92,6 +92,7 @@
 	    <module>gluon</module>
         <module>evpnopenflow</module>
         <module>route-service</module>
+        <module>evpn-route-service</module>
     </modules>
 
     <properties>