Jonathan Hart

Implemented SDN-IP/BgpRouter neighbour handling using NeighbourResolutionService

Change-Id: Ia7e3f18bd69d56cb2f46f815eaa2352533a54ed0
......@@ -19,6 +19,5 @@ onos_app (
category = 'Traffic Steering',
url = 'http://onosproject.org',
description = 'BGP router application.',
required_apps = [ 'org.onosproject.proxyarp' ],
included_bundles = BUNDLES,
)
......
......@@ -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>
......
......@@ -95,6 +95,7 @@ public class BgpRouter {
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");
}
......
/*
* 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;
}
}
}
}
......@@ -26,6 +26,5 @@ onos_app (
category = 'Utility',
url = 'http://onosproject.org',
included_bundles = BUNDLES,
required_apps = [ 'org.onosproject.proxyarp' ],
description = 'SDN-IP peering application',
)
......
......@@ -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>
......
......@@ -68,6 +68,7 @@ public class SdnIp {
private final List<String> components = ImmutableList.of(
"org.onosproject.routing.bgp.BgpSessionManager",
"org.onosproject.routing.impl.BgpSpeakerNeighbourHandler",
org.onosproject.sdnip.SdnIpFib.class.getName()
);
......