Adding route subsystem code to support EVPN
Change-Id: I5d9715af8e2a9474892267c97cd4763f12be4816
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstance.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstance.java
new file mode 100644
index 0000000..4201909
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstanceName.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstanceName.java
new file mode 100644
index 0000000..ee63cf4
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstanceNextHop.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstanceNextHop.java
new file mode 100644
index 0000000..4acd2b3
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onlab.packet.IpAddress;
+
+import java.util.Objects;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstancePrefix.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstancePrefix.java
new file mode 100644
index 0000000..45c4c04
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+import java.util.Objects;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstanceRoute.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInstanceRoute.java
new file mode 100644
index 0000000..b7c2b5cc
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+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 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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInternalRouteEvent.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnInternalRouteEvent.java
new file mode 100644
index 0000000..046927b
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnNextHop.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnNextHop.java
new file mode 100644
index 0000000..6aacabb
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onlab.packet.IpAddress;
+
+import java.util.List;
+import java.util.Objects;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnPrefix.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnPrefix.java
new file mode 100644
index 0000000..acea7d9
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+import java.util.Objects;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRoute.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRoute.java
new file mode 100644
index 0000000..06ab18a
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRoute.java
@@ -0,0 +1,284 @@
+/*
+ * 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.incubator.net.routing;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+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 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 prefix
+ * @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
+ * @param prefix
+ */
+ 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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteAdminService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteAdminService.java
new file mode 100644
index 0000000..3a4ea8f
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteEvent.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteEvent.java
new file mode 100644
index 0000000..2d2db40
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.joda.time.LocalDateTime;
+import org.onosproject.event.AbstractEvent;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteListener.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteListener.java
new file mode 100644
index 0000000..02779c0
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Listener for route events.
+ */
+public interface EvpnRouteListener extends EventListener<EvpnRouteEvent> {
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteService.java
new file mode 100644
index 0000000..ba9179b
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onosproject.event.ListenerService;
+
+import java.util.Collection;
+
+/**
+ * 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<RouteTableId> getRouteTables();
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteSet.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteSet.java
new file mode 100644
index 0000000..9530f09
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Objects;
+import java.util.Set;
+
+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 RouteTableId 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(RouteTableId 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 RouteTableId 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 RouteSet)) {
+ 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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteStore.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteStore.java
new file mode 100644
index 0000000..9dd5e73
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.store.Store;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * 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<RouteTableId> getRouteTables();
+
+ /**
+ * Returns the routes in the given route table, grouped by prefix.
+ *
+ * @param table route table ID
+ * @return routes
+ */
+ Collection<EvpnRouteSet> getRoutes(RouteTableId 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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteStoreDelegate.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnRouteStoreDelegate.java
new file mode 100644
index 0000000..55818e1
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Route store delegate abstraction.
+ */
+public interface EvpnRouteStoreDelegate extends
+ StoreDelegate<EvpnInternalRouteEvent> {
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnTable.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/EvpnTable.java
new file mode 100755
index 0000000..eaa07af
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+import org.onlab.packet.IpAddress;
+
+import java.util.Collection;
+
+/**
+ * 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
+ */
+ RouteTableId 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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/Label.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/Label.java
new file mode 100644
index 0000000..0ce19af
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/RouteDistinguisher.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/RouteDistinguisher.java
new file mode 100644
index 0000000..c0e5b10
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+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/incubator/api/src/main/java/org/onosproject/incubator/net/routing/VpnRouteTarget.java b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/VpnRouteTarget.java
new file mode 100644
index 0000000..d7aee60
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing;
+
+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/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/EvpnListenerQueue.java b/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/EvpnListenerQueue.java
new file mode 100644
index 0000000..77a57ca
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/routing/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.incubator.net.routing.impl;
+
+import org.onosproject.incubator.net.routing.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/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/EvpnRouteManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/EvpnRouteManager.java
new file mode 100644
index 0000000..7ea4813
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/routing/impl/EvpnRouteManager.java
@@ -0,0 +1,272 @@
+/*
+ * 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.incubator.net.routing.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.incubator.net.routing.EvpnInternalRouteEvent;
+import org.onosproject.incubator.net.routing.EvpnRoute;
+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.EvpnRouteStoreDelegate;
+import org.onosproject.incubator.net.routing.RouteTableId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.concurrent.GuardedBy;
+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 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<RouteTableId> 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/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/DistributedEvpnRouteStore.java b/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/DistributedEvpnRouteStore.java
new file mode 100755
index 0000000..49356b6
--- /dev/null
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/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.incubator.store.routing.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.incubator.net.routing.EvpnInternalRouteEvent;
+import org.onosproject.incubator.net.routing.EvpnRoute;
+import org.onosproject.incubator.net.routing.EvpnRouteSet;
+import org.onosproject.incubator.net.routing.EvpnRouteStore;
+import org.onosproject.incubator.net.routing.EvpnRouteStoreDelegate;
+import org.onosproject.incubator.net.routing.EvpnTable;
+import org.onosproject.incubator.net.routing.RouteTableId;
+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 RouteTableId EVPN_IPV4 = new RouteTableId("evpn_ipv4");
+ private static final RouteTableId EVPN_IPV6 = new RouteTableId("evpn_ipv6");
+
+ private final SetEventListener<RouteTableId> masterRouteTableListener =
+ new MasterRouteTableListener();
+ private final EvpnRouteStoreDelegate ourDelegate = new
+ InternalEvpnRouteStoreDelegate();
+
+ // Stores the route tables that have been created
+ public DistributedSet<RouteTableId> masterRouteTable;
+ // Local memory map to store route table object
+ public Map<RouteTableId, 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(RouteTableId.class)
+ .build();
+
+ masterRouteTable = storageService.<RouteTableId>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<RouteTableId> getRouteTables() {
+ return ImmutableSet.copyOf(masterRouteTable);
+ }
+
+ @Override
+ public Collection<EvpnRouteSet> getRoutes(RouteTableId 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(RouteTableId tableId) {
+ routeTables.computeIfAbsent(tableId, id -> new EvpnRouteTable(id,
+ ourDelegate, storageService, executor));
+ }
+
+ private void destroyRouteTable(RouteTableId 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) {
+ RouteTableId 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<RouteTableId> {
+ @Override
+ public void event(SetEvent<RouteTableId> 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/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/EmptyEvpnRouteTable.java b/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/EmptyEvpnRouteTable.java
new file mode 100755
index 0000000..fc59649
--- /dev/null
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/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.incubator.store.routing.impl;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.incubator.net.routing.EvpnPrefix;
+import org.onosproject.incubator.net.routing.EvpnRoute;
+import org.onosproject.incubator.net.routing.EvpnRouteSet;
+import org.onosproject.incubator.net.routing.EvpnTable;
+import org.onosproject.incubator.net.routing.RouteTableId;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Route table that contains no routes.
+ */
+public final class EmptyEvpnRouteTable implements EvpnTable {
+
+ private final RouteTableId id = new RouteTableId("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 RouteTableId 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/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/EvpnRouteTable.java b/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/EvpnRouteTable.java
new file mode 100755
index 0000000..9fd8798
--- /dev/null
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/routing/impl/EvpnRouteTable.java
@@ -0,0 +1,233 @@
+/*
+ * 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.incubator.store.routing.impl;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.incubator.net.routing.EvpnInternalRouteEvent;
+import org.onosproject.incubator.net.routing.EvpnPrefix;
+import org.onosproject.incubator.net.routing.EvpnRoute;
+import org.onosproject.incubator.net.routing.EvpnRouteSet;
+import org.onosproject.incubator.net.routing.EvpnRouteStoreDelegate;
+import org.onosproject.incubator.net.routing.EvpnTable;
+import org.onosproject.incubator.net.routing.Label;
+import org.onosproject.incubator.net.routing.Route;
+import org.onosproject.incubator.net.routing.RouteDistinguisher;
+import org.onosproject.incubator.net.routing.RouteTableId;
+import org.onosproject.incubator.net.routing.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 RouteTableId 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(RouteTableId 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(Route.class)
+ .register(Route.Source.class)
+ .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(RouteTableId.class)
+ .build();
+ return storageService.<EvpnPrefix, Set<EvpnRoute>>consistentMapBuilder()
+ .withName("onos-evpn-routes-" + id.name())
+ .withRelaxedReadConsistency()
+ .withSerializer(Serializer.using(routeTableSerializer))
+ .build();
+ }
+
+ @Override
+ public RouteTableId 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);
+ }
+ }
+ }
+
+}
+