Implemented SDN-IP/BgpRouter neighbour handling using NeighbourResolutionService
Change-Id: Ia7e3f18bd69d56cb2f46f815eaa2352533a54ed0
diff --git a/apps/bgprouter/BUCK b/apps/bgprouter/BUCK
index 62ec78e..0e1870f 100644
--- a/apps/bgprouter/BUCK
+++ b/apps/bgprouter/BUCK
@@ -19,6 +19,5 @@
category = 'Traffic Steering',
url = 'http://onosproject.org',
description = 'BGP router application.',
- required_apps = [ 'org.onosproject.proxyarp' ],
included_bundles = BUNDLES,
)
diff --git a/apps/bgprouter/app.xml b/apps/bgprouter/app.xml
index 2b5c117..91e010a 100644
--- a/apps/bgprouter/app.xml
+++ b/apps/bgprouter/app.xml
@@ -22,5 +22,4 @@
<artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-app-routing-api/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-app-routing/${project.version}</artifact>
- <artifact>mvn:${project.groupId}/onos-app-proxyarp/${project.version}</artifact>
</app>
diff --git a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
index 0ae6fa8..e6941c3 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
@@ -95,6 +95,7 @@
static {
components.add("org.onosproject.routing.bgp.BgpSessionManager");
components.add("org.onosproject.routing.impl.Router");
+ components.add("org.onosproject.routing.impl.BgpSpeakerNeighbourHandler");
components.add("org.onosproject.routing.impl.SingleSwitchFibInstaller");
}
diff --git a/apps/routing/src/main/java/org/onosproject/routing/impl/BgpSpeakerNeighbourHandler.java b/apps/routing/src/main/java/org/onosproject/routing/impl/BgpSpeakerNeighbourHandler.java
new file mode 100644
index 0000000..aeaf13d
--- /dev/null
+++ b/apps/routing/src/main/java/org/onosproject/routing/impl/BgpSpeakerNeighbourHandler.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.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.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceEvent;
+import org.onosproject.incubator.net.intf.InterfaceListener;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
+import org.onosproject.incubator.net.neighbour.NeighbourMessageHandler;
+import org.onosproject.incubator.net.neighbour.NeighbourResolutionService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Host;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.host.HostService;
+import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.config.BgpConfig;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.onosproject.net.HostId.hostId;
+
+/**
+ * Manages neighbour message handlers for the use case of internal BGP speakers
+ * connected to the network at some point that are exchanging neighbour
+ * resolution messages with external routers that are connected behind interfaces.
+ * <p>
+ * For each internal speaker port we use a handler that proxies packets from
+ * that port to the appropriate external-facing interface port.
+ * For each external interface, we use a handler that responds to requests based
+ * on the interface configuration and proxies replies back the the internal BGP
+ * speaker.
+ * </p>
+ */
+@Component(immediate = true, enabled = false)
+public class BgpSpeakerNeighbourHandler {
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected InterfaceService interfaceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NeighbourResolutionService neighbourService;
+
+ private ApplicationId appId;
+
+ private Set<ConnectPoint> speakerConnectPoints = new HashSet<>();
+
+
+ private InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
+ private InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
+
+ private ExternalInterfaceNeighbourHandler externalHandler = new ExternalInterfaceNeighbourHandler();
+ private InternalSpeakerNeighbourHandler internalHandler = new InternalSpeakerNeighbourHandler();
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
+ configService.addListener(configListener);
+ interfaceService.addListener(interfaceListener);
+
+ interfaceService.getInterfaces().forEach(
+ intf -> neighbourService.registerNeighbourHandler(intf, externalHandler, appId));
+ configureSpeakerHandlers();
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ configService.removeListener(configListener);
+ interfaceService.removeListener(interfaceListener);
+
+ neighbourService.unregisterNeighbourHandlers(appId);
+ }
+
+ private void configureSpeakerHandlers() {
+ BgpConfig config = configService.getConfig(appId, RoutingService.CONFIG_CLASS);
+
+ if (config == null) {
+ return;
+ }
+
+ speakerConnectPoints.forEach(
+ cp -> neighbourService.unregisterNeighbourHandler(cp, internalHandler, appId));
+ speakerConnectPoints.clear();
+
+ config.bgpSpeakers().forEach(speaker -> {
+ neighbourService.registerNeighbourHandler(speaker.connectPoint(), internalHandler, appId);
+ speakerConnectPoints.add(speaker.connectPoint());
+ });
+ }
+
+ private void updateInterface(Interface intf) {
+ // Only use interfaces that have an IP address
+ if (!intf.ipAddresses().isEmpty()) {
+ neighbourService.registerNeighbourHandler(intf, externalHandler, appId);
+ }
+ }
+
+ private void removeInterface(Interface intf) {
+ neighbourService.unregisterNeighbourHandler(intf, externalHandler, appId);
+ }
+
+ /**
+ * Neighbour message handler for external facing ports that have interface
+ * configuration.
+ */
+ public class ExternalInterfaceNeighbourHandler implements
+ NeighbourMessageHandler {
+
+ @Override
+ public void handleMessage(NeighbourMessageContext context, HostService hostService) {
+ switch (context.type()) {
+ case REQUEST:
+ // Reply to requests that target our configured interface IP
+ // address on this port. Drop all other requests.
+
+ interfaceService.getInterfacesByPort(context.inPort())
+ .stream()
+ .filter(intf -> intf.ipAddresses()
+ .stream()
+ .anyMatch(ia -> ia.ipAddress().equals(context.target())))
+ .forEach(intf -> context.reply(intf.mac()));
+
+ break;
+ case REPLY:
+ // Proxy replies over to our internal BGP speaker if the host
+ // is known to us
+ Host h = hostService.getHost(hostId(context.dstMac(), context.vlan()));
+
+ if (h == null) {
+ context.drop();
+ } else {
+ context.proxy(h.location());
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ /**
+ * Neighbour message handler for ports connected to the internal BGP speakers.
+ */
+ private class InternalSpeakerNeighbourHandler implements
+ NeighbourMessageHandler {
+ @Override
+ public void handleMessage(NeighbourMessageContext context, HostService hostService) {
+ // For messages coming from a BGP speaker, look at the sender address
+ // to find the interface to proxy to
+ interfaceService.getInterfacesByIp(context.sender())
+ .stream()
+ .filter(intf -> intf.vlan().equals(context.vlan()))
+ .map(intf -> intf.connectPoint())
+ .forEach(context::proxy);
+ }
+ }
+
+ private class InternalNetworkConfigListener implements
+ NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ switch (event.type()) {
+ case CONFIG_REGISTERED:
+ break;
+ case CONFIG_UNREGISTERED:
+ break;
+ case CONFIG_ADDED:
+ case CONFIG_UPDATED:
+ case CONFIG_REMOVED:
+ if (event.configClass() == RoutingService.CONFIG_CLASS) {
+ configureSpeakerHandlers();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private class InternalInterfaceListener implements InterfaceListener {
+
+ @Override
+ public void event(InterfaceEvent event) {
+ switch (event.type()) {
+ case INTERFACE_ADDED:
+ updateInterface(event.subject());
+ break;
+ case INTERFACE_UPDATED:
+ break;
+ case INTERFACE_REMOVED:
+ removeInterface(event.subject());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/apps/sdnip/BUCK b/apps/sdnip/BUCK
index b15d478..d934d74 100644
--- a/apps/sdnip/BUCK
+++ b/apps/sdnip/BUCK
@@ -26,6 +26,5 @@
category = 'Utility',
url = 'http://onosproject.org',
included_bundles = BUNDLES,
- required_apps = [ 'org.onosproject.proxyarp' ],
description = 'SDN-IP peering application',
)
diff --git a/apps/sdnip/app.xml b/apps/sdnip/app.xml
index 1a803e2..4bea73c 100644
--- a/apps/sdnip/app.xml
+++ b/apps/sdnip/app.xml
@@ -17,7 +17,7 @@
<app name="org.onosproject.sdnip" origin="ON.Lab" version="${project.version}"
category="Traffic Steering" url="http://onosproject.org" title="SDN-IP App"
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
- features="${project.artifactId}" apps="org.onosproject.proxyarp">
+ features="${project.artifactId}">
<description>${project.description}</description>
<artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-app-routing-api/${project.version}</artifact>
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
index 201a909..643bb2b 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
@@ -68,6 +68,7 @@
private final List<String> components = ImmutableList.of(
"org.onosproject.routing.bgp.BgpSessionManager",
+ "org.onosproject.routing.impl.BgpSpeakerNeighbourHandler",
org.onosproject.sdnip.SdnIpFib.class.getName()
);