Jonathan Hart
Committed by Gerrit Code Review

Moved ProxyArp, SDN-IP and BgpRouter to use new config format.

The new config format is based on the new network configuration subsystem.

Includes a few config fixes to NetworkConfigLoader and InterfaceManager.

Change-Id: Id7f766736decb7afb6b63c2731d3baba9fc7c764
Showing 30 changed files with 457 additions and 364 deletions
......@@ -49,6 +49,11 @@
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-incubator-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
......@@ -64,6 +69,6 @@
<artifactId>onos-app-proxyarp</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
......
......@@ -20,7 +20,6 @@ import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -29,9 +28,11 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onosproject.config.NetworkConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
......@@ -56,15 +57,14 @@ import org.onosproject.routing.FibEntry;
import org.onosproject.routing.FibListener;
import org.onosproject.routing.FibUpdate;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.config.BgpSpeaker;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.onosproject.routing.config.BgpConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/* For test only - will be removed before Cardinal release
......@@ -95,7 +95,10 @@ public class BgpRouter {
protected RoutingService routingService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RoutingConfigurationService configService;
protected InterfaceService interfaceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService networkConfigService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
......@@ -106,14 +109,6 @@ public class BgpRouter {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
//
// NOTE: Unused reference - needed to guarantee that the
// NetworkConfigReader component is activated and the network configuration
// is read.
//
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService networkConfigService;
private ApplicationId appId;
// Reference count for how many times a next hop is used by a route
......@@ -145,14 +140,25 @@ public class BgpRouter {
@Activate
protected void activate() {
appId = coreService.registerApplication(BGP_ROUTER_APP);
getDeviceConfiguration(configService.getBgpSpeakers());
ApplicationId routerAppId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
BgpConfig bgpConfig =
networkConfigService.getConfig(routerAppId, RoutingService.CONFIG_CLASS);
if (bgpConfig == null) {
log.error("No BgpConfig found");
return;
}
getDeviceConfiguration(bgpConfig);
connectivityManager = new TunnellingConnectivityManager(appId,
configService,
bgpConfig,
interfaceService,
packetService,
flowObjectiveService);
icmpHandler = new IcmpHandler(configService, packetService);
icmpHandler = new IcmpHandler(interfaceService, packetService);
deviceListener = new InnerDeviceListener();
routingService.addFibListener(new InternalFibListener());
routingService.start();
......@@ -162,7 +168,7 @@ public class BgpRouter {
// Initialize devices now if they are already connected
if (deviceService.isAvailable(deviceId)) {
processIntfFilters(true, configService.getInterfaces());
processIntfFilters(true, interfaceService.getInterfaces());
}
if (deviceService.isAvailable(ctrlDeviceId)) {
......@@ -182,21 +188,36 @@ public class BgpRouter {
log.info("BgpRouter stopped");
}
private void getDeviceConfiguration(Map<String, BgpSpeaker> bgps) {
if (bgps == null || bgps.values().isEmpty()) {
log.error("BGP speakers configuration is missing");
private void getDeviceConfiguration(BgpConfig bgpConfig) {
Optional<BgpConfig.BgpSpeakerConfig> bgpSpeaker =
bgpConfig.bgpSpeakers().stream().findAny();
if (!bgpSpeaker.isPresent()) {
log.error("BGP speaker configuration not found");
return;
}
for (BgpSpeaker s : bgps.values()) {
ctrlDeviceId = s.connectPoint().deviceId();
if (s.interfaceAddresses() == null || s.interfaceAddresses().isEmpty()) {
log.error("BGP Router must have interfaces configured");
return;
}
deviceId = s.interfaceAddresses().get(0).connectPoint().deviceId();
break;
ctrlDeviceId = bgpSpeaker.get().connectPoint().deviceId();
Optional<IpAddress> peerAddress =
bgpSpeaker.get().peers().stream().findAny();
if (!peerAddress.isPresent()) {
log.error("BGP speaker must have peers configured");
return;
}
Interface intf = interfaceService.getMatchingInterface(peerAddress.get());
if (intf == null) {
log.error("No interface found for peer");
return;
}
// Assume all peers are configured on the same device - this is required
// by the BGP router
deviceId = intf.connectPoint().deviceId();
log.info("Router dpid: {}", deviceId);
log.info("Control Plane OVS dpid: {}", ctrlDeviceId);
}
......@@ -283,7 +304,7 @@ public class BgpRouter {
if (nextHopsCount.count(entry.nextHopIp()) == 0) {
// There was no next hop in the multiset
Interface egressIntf = configService.getMatchingInterface(entry.nextHopIp());
Interface egressIntf = interfaceService.getMatchingInterface(entry.nextHopIp());
if (egressIntf == null) {
log.warn("no egress interface found for {}", entry);
return;
......@@ -405,7 +426,7 @@ public class BgpRouter {
if (deviceService.isAvailable(event.subject().id())) {
log.info("Device connected {}", event.subject().id());
if (event.subject().id().equals(deviceId)) {
processIntfFilters(true, configService.getInterfaces());
processIntfFilters(true, interfaceService.getInterfaces());
/* For test only - will be removed before Cardinal release
delay(1000);
......
......@@ -19,6 +19,8 @@ import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onlab.packet.IPv4;
import org.onlab.packet.IpAddress;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
......@@ -29,8 +31,6 @@ import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -41,14 +41,14 @@ public class IcmpHandler {
private static final Logger log = LoggerFactory.getLogger(IcmpHandler.class);
private final PacketService packetService;
private final RoutingConfigurationService configService;
private final InterfaceService interfaceService;
private final IcmpProcessor processor = new IcmpProcessor();
public IcmpHandler(RoutingConfigurationService configService,
public IcmpHandler(InterfaceService interfaceService,
PacketService packetService) {
this.configService = configService;
this.interfaceService = interfaceService;
this.packetService = packetService;
}
......@@ -67,7 +67,7 @@ public class IcmpHandler {
IPv4 ipv4 = (IPv4) ethernet.getPayload();
ConnectPoint connectPoint = pkt.receivedFrom();
IpAddress destIpAddress = IpAddress.valueOf(ipv4.getDestinationAddress());
Interface targetInterface = configService.getMatchingInterface(destIpAddress);
Interface targetInterface = interfaceService.getMatchingInterface(destIpAddress);
if (targetInterface == null) {
log.trace("No matching interface for {}", destIpAddress);
......
......@@ -15,14 +15,14 @@
*/
package org.onosproject.bgprouter;
import static org.slf4j.LoggerFactory.getLogger;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.IpAddress;
import org.onlab.packet.TCP;
import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
......@@ -36,12 +36,14 @@ import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.routing.config.BgpPeer;
import org.onosproject.routing.config.BgpSpeaker;
import org.onosproject.routing.config.InterfaceAddress;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.onosproject.routing.config.BgpConfig;
import org.slf4j.Logger;
import java.util.Optional;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Manages connectivity between peers by tunnelling BGP traffic through
......@@ -53,34 +55,32 @@ public class TunnellingConnectivityManager {
private final Logger log = getLogger(getClass());
private final ApplicationId appId;
private final BgpSpeaker bgpSpeaker;
private final BgpConfig.BgpSpeakerConfig bgpSpeaker;
private final PacketService packetService;
private final RoutingConfigurationService configService;
private final InterfaceService interfaceService;
private final FlowObjectiveService flowObjectiveService;
private final BgpProcessor processor = new BgpProcessor();
public TunnellingConnectivityManager(ApplicationId appId,
RoutingConfigurationService configService,
BgpConfig bgpConfig,
InterfaceService interfaceService,
PacketService packetService,
FlowObjectiveService flowObjectiveService) {
this.appId = appId;
this.configService = configService;
this.interfaceService = interfaceService;
this.packetService = packetService;
this.flowObjectiveService = flowObjectiveService;
BgpSpeaker bgpSpeaker = null;
for (BgpSpeaker speaker : configService.getBgpSpeakers().values()) {
bgpSpeaker = speaker;
break;
}
Optional<BgpConfig.BgpSpeakerConfig> bgpSpeaker =
bgpConfig.bgpSpeakers().stream().findAny();
if (bgpSpeaker == null) {
if (!bgpSpeaker.isPresent()) {
throw new IllegalArgumentException("Must have at least one BGP speaker configured");
}
this.bgpSpeaker = bgpSpeaker;
this.bgpSpeaker = bgpSpeaker.get();
}
......@@ -149,14 +149,19 @@ public class TunnellingConnectivityManager {
IpAddress dstAddress = IpAddress.valueOf(ipv4.getDestinationAddress());
if (context.inPacket().receivedFrom().equals(bgpSpeaker.connectPoint())) {
BgpPeer peer = configService.getBgpPeers().get(dstAddress);
if (peer != null) {
outputPort = peer.connectPoint();
if (bgpSpeaker.peers().contains(dstAddress)) {
Interface intf = interfaceService.getMatchingInterface(dstAddress);
if (intf != null) {
outputPort = intf.connectPoint();
}
}
}
for (InterfaceAddress addr : bgpSpeaker.interfaceAddresses()) {
if (addr.ipAddress().equals(dstAddress) && !context.inPacket()
.receivedFrom().equals(bgpSpeaker.connectPoint())) {
} else {
Set<Interface> interfaces =
interfaceService.getInterfacesByPort(context.inPacket().receivedFrom());
if (interfaces.stream()
.flatMap(intf -> intf.ipAddresses().stream())
.anyMatch(ia -> ia.ipAddress().equals(dstAddress))) {
outputPort = bgpSpeaker.connectPoint();
}
}
......
......@@ -37,6 +37,11 @@
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-incubator-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
......
......@@ -18,6 +18,7 @@ package org.onosproject.routing;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.net.ConnectPoint;
import org.onosproject.routing.config.BgpConfig;
import java.util.Collection;
......@@ -28,6 +29,8 @@ public interface RoutingService {
String ROUTER_APP_ID = "org.onosproject.router";
Class<BgpConfig> CONFIG_CLASS = BgpConfig.class;
/**
* Specifies the type of an IP address or an IP prefix location.
*/
......
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.onosproject.routing.config.impl;
package org.onosproject.routing.config;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Sets;
......@@ -32,27 +32,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class BgpConfig extends Config<ApplicationId> {
public static final String PEERS = "bgpPeers";
public static final String SPEAKERS = "bgpSpeakers";
public static final String CONNECT_POINT = "connectPoint";
public static final String IP_ADDRESS = "ipAddress";
public static final String LISTEN_ADDRESSES = "listenAddresses";
public static final String PEERS = "peers";
/**
* Gets the set of configured BGP peers.
*
* @return BGP peers
*/
public Set<BgpPeerConfig> bgpPeers() {
Set<BgpPeerConfig> peers = Sets.newHashSet();
JsonNode peersNode = node.get(PEERS);
peersNode.forEach(jsonNode -> peers.add(
new BgpPeerConfig(ConnectPoint.deviceConnectPoint(jsonNode.path(CONNECT_POINT).asText()),
IpAddress.valueOf(jsonNode.path(IP_ADDRESS).asText()))));
return peers;
}
// TODO add methods for updating config
/**
* Gets the set of configured BGP speakers.
......@@ -65,7 +49,7 @@ public class BgpConfig extends Config<ApplicationId> {
JsonNode speakersNode = node.get(SPEAKERS);
speakersNode.forEach(jsonNode -> {
Set<IpAddress> listenAddresses = Sets.newHashSet();
jsonNode.path(LISTEN_ADDRESSES).forEach(addressNode ->
jsonNode.path(PEERS).forEach(addressNode ->
listenAddresses.add(IpAddress.valueOf(addressNode.asText()))
);
speakers.add(new BgpSpeakerConfig(
......@@ -77,46 +61,24 @@ public class BgpConfig extends Config<ApplicationId> {
}
/**
* Configuration for a BGP peer.
*/
public class BgpPeerConfig {
private ConnectPoint connectPoint;
private IpAddress ipAddress;
public BgpPeerConfig(ConnectPoint connectPoint, IpAddress ipAddress) {
this.connectPoint = connectPoint;
this.ipAddress = ipAddress;
}
public ConnectPoint connectPoint() {
return connectPoint;
}
public IpAddress ipAddress() {
return ipAddress;
}
}
/**
* Configuration for a BGP speaker.
*/
public class BgpSpeakerConfig {
public static class BgpSpeakerConfig {
private ConnectPoint connectPoint;
private Set<IpAddress> listenAddresses;
private Set<IpAddress> peers;
public BgpSpeakerConfig(ConnectPoint connectPoint, Set<IpAddress> listenAddresses) {
public BgpSpeakerConfig(ConnectPoint connectPoint, Set<IpAddress> peers) {
this.connectPoint = checkNotNull(connectPoint);
this.listenAddresses = checkNotNull(listenAddresses);
this.peers = checkNotNull(peers);
}
public ConnectPoint connectPoint() {
return connectPoint;
}
public Set<IpAddress> listenAddresses() {
return listenAddresses;
public Set<IpAddress> peers() {
return peers;
}
}
}
......
......@@ -77,7 +77,9 @@ public interface RoutingConfigurationService {
* Retrieves the entire set of interfaces in the network.
*
* @return the set of interfaces
* @deprecated in Drake release - use InterfaceService instead
*/
@Deprecated
Set<Interface> getInterfaces();
/**
......@@ -86,7 +88,7 @@ public interface RoutingConfigurationService {
*
* @return the set of connect points connected to BGP peers
*/
public Set<ConnectPoint> getBgpPeerConnectPoints();
Set<ConnectPoint> getBgpPeerConnectPoints();
/**
* Retrieves the interface associated with the given connect point.
......@@ -94,7 +96,9 @@ public interface RoutingConfigurationService {
* @param connectPoint the connect point to retrieve interface information
* for
* @return the interface
* @deprecated in Drake release - use InterfaceService instead
*/
@Deprecated
Interface getInterface(ConnectPoint connectPoint);
/**
......@@ -102,7 +106,9 @@ public interface RoutingConfigurationService {
*
* @param ip IP address of the interface
* @return the interface
* @deprecated in Drake release - use InterfaceService instead
*/
@Deprecated
Interface getInterface(IpAddress ip);
/**
......@@ -111,7 +117,9 @@ public interface RoutingConfigurationService {
*
* @param ipAddress IP address to match
* @return the matching interface
* @deprecated in Drake release - use InterfaceService instead
*/
@Deprecated
Interface getMatchingInterface(IpAddress ipAddress);
}
......
/*
* Copyright 2015 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.cli;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.config.impl.BgpConfig;
/**
* Lists the BGP peers configured in the system.
*/
@Command(scope = "onos", name = "bgp-peers",
description = "Lists all BGP peers")
public class BgpPeersListCommand extends AbstractShellCommand {
private static final String FORMAT = "%s : %s";
@Override
protected void execute() {
NetworkConfigService configService = get(NetworkConfigService.class);
CoreService coreService = get(CoreService.class);
ApplicationId appId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
print(appId.toString());
BgpConfig config = configService.getConfig(appId, BgpConfig.class);
if (config == null || config.bgpPeers().isEmpty()) {
print("No peers configured");
} else {
config.bgpPeers().forEach(
p -> print(FORMAT, p.ipAddress(), p.connectPoint()));
}
}
}
......@@ -22,7 +22,7 @@ import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.config.impl.BgpConfig;
import org.onosproject.routing.config.BgpConfig;
/**
* Lists the BGP speakers configured in the system.
......@@ -47,7 +47,7 @@ public class BgpSpeakersListCommand extends AbstractShellCommand {
print("No speakers configured");
} else {
config.bgpSpeakers().forEach(
s -> print(FORMAT, s.connectPoint(), s.listenAddresses()));
s -> print(FORMAT, s.connectPoint(), s.peers()));
}
}
}
......
......@@ -30,16 +30,22 @@ import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.host.HostService;
import org.onosproject.routing.config.BgpConfig;
import org.onosproject.routing.config.BgpPeer;
import org.onosproject.routing.config.BgpSpeaker;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.LocalIpPrefixEntry;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.onosproject.routing.impl.Router;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -51,6 +57,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static org.onosproject.routing.RouteEntry.createBinaryString;
......@@ -74,6 +81,15 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry registry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService configService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected InterfaceService interfaceService;
private Map<String, BgpSpeaker> bgpSpeakers = new ConcurrentHashMap<>();
private Map<IpAddress, BgpPeer> bgpPeers = new ConcurrentHashMap<>();
private Set<IpAddress> gatewayIpAddresses = new HashSet<>();
......@@ -178,7 +194,20 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
@Override
public Set<ConnectPoint> getBgpPeerConnectPoints() {
return Collections.unmodifiableSet(bgpPeerConnectPoints);
// TODO perhaps cache this result in future
ApplicationId routerAppId = coreService.getAppId(Router.ROUTER_APP_ID);
if (routerAppId == null) {
return Collections.emptySet();
}
BgpConfig bgpConfig = configService.getConfig(routerAppId, BgpConfig.class);
return bgpConfig.bgpSpeakers().stream()
.flatMap(speaker -> speaker.peers().stream())
.map(peer -> interfaceService.getMatchingInterface(peer))
.filter(intf -> intf != null)
.map(intf -> intf.connectPoint())
.collect(Collectors.toSet());
}
@Override
......
......@@ -35,6 +35,8 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.core.CoreService;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.host.HostEvent;
......@@ -49,7 +51,6 @@ import org.onosproject.routing.RouteEntry;
import org.onosproject.routing.RouteListener;
import org.onosproject.routing.RouteUpdate;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -60,6 +61,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
......@@ -110,6 +112,9 @@ public class Router implements RoutingService {
protected BgpService bgpService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected InterfaceService interfaceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RoutingConfigurationService routingConfigurationService;
private ExecutorService bgpUpdatesExecutor;
......@@ -603,8 +608,7 @@ public class Router implements RoutingService {
RouteEntry routeEntry = getLongestMatchableRouteEntry(dstIpAddress);
if (routeEntry != null) {
nextHopIpAddress = routeEntry.nextHop();
Interface it = routingConfigurationService
.getMatchingInterface(nextHopIpAddress);
Interface it = interfaceService.getMatchingInterface(nextHopIpAddress);
if (it != null) {
return it.connectPoint();
} else {
......@@ -700,18 +704,18 @@ public class Router implements RoutingService {
private TrafficType trafficTypeClassifier(ConnectPoint srcConnectPoint,
IpAddress dstIp) {
LocationType dstIpLocationType = getLocationType(dstIp);
Interface srcInterface =
routingConfigurationService.getInterface(srcConnectPoint);
Optional<Interface> srcInterface =
interfaceService.getInterfacesByPort(srcConnectPoint).stream().findFirst();
switch (dstIpLocationType) {
case INTERNET:
if (srcInterface == null) {
if (!srcInterface.isPresent()) {
return TrafficType.HOST_TO_INTERNET;
} else {
return TrafficType.INTERNET_TO_INTERNET;
}
case LOCAL:
if (srcInterface == null) {
if (!srcInterface.isPresent()) {
return TrafficType.HOST_TO_HOST;
} else {
// TODO Currently we only consider local public prefixes.
......
......@@ -32,9 +32,6 @@
<action class="org.onosproject.routing.cli.RemoveRouteCommand"/>
</command>
<command>
<action class="org.onosproject.routing.cli.BgpPeersListCommand"/>
</command>
<command>
<action class="org.onosproject.routing.cli.BgpSpeakersListCommand"/>
</command>
</command-bundle>
......
......@@ -22,8 +22,5 @@
<bundle>mvn:${project.groupId}/onos-app-sdnip/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-app-routing-api/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-app-routing/${project.version}</bundle>
<!-- NOTE: Temporarily the sdnip app will bring the config bundle
until we can specify dependencies between applictions -->
<bundle>mvn:${project.groupId}/onos-app-config/${project.version}</bundle>
</feature>
</features>
......
......@@ -23,6 +23,8 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.flow.DefaultTrafficSelector;
......@@ -43,8 +45,6 @@ import org.onosproject.net.intent.constraint.PartialFailureConstraint;
import org.onosproject.routing.FibListener;
import org.onosproject.routing.FibUpdate;
import org.onosproject.routing.IntentRequestListener;
import org.onosproject.routing.config.BgpPeer;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -81,6 +81,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
private final ApplicationId appId;
private final IntentService intentService;
private final HostService hostService;
private final InterfaceService interfaceService;
private final Map<IntentKey, PointToPointIntent> peerIntents;
private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents;
......@@ -104,10 +105,12 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
*/
IntentSynchronizer(ApplicationId appId, IntentService intentService,
HostService hostService,
RoutingConfigurationService configService) {
RoutingConfigurationService configService,
InterfaceService interfaceService) {
this.appId = appId;
this.intentService = intentService;
this.hostService = hostService;
this.interfaceService = interfaceService;
peerIntents = new ConcurrentHashMap<>();
routeIntents = new ConcurrentHashMap<>();
......@@ -122,12 +125,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
* Starts the synchronizer.
*/
public void start() {
bgpIntentsSynchronizerExecutor.execute(new Runnable() {
@Override
public void run() {
doIntentSynchronizationThread();
}
});
bgpIntentsSynchronizerExecutor.execute(this::doIntentSynchronizationThread);
}
/**
......@@ -313,24 +311,11 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
MacAddress nextHopMacAddress) {
// Find the attachment point (egress interface) of the next hop
Interface egressInterface;
if (configService.getBgpPeers().containsKey(nextHopIpAddress)) {
// Route to a peer
log.debug("Route to peer {}", nextHopIpAddress);
BgpPeer peer =
configService.getBgpPeers().get(nextHopIpAddress);
egressInterface =
configService.getInterface(peer.connectPoint());
} else {
// Route to non-peer
log.debug("Route to non-peer {}", nextHopIpAddress);
egressInterface =
configService.getMatchingInterface(nextHopIpAddress);
if (egressInterface == null) {
log.warn("No outgoing interface found for {}",
nextHopIpAddress);
return null;
}
Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress);
if (egressInterface == null) {
log.warn("No outgoing interface found for {}",
nextHopIpAddress);
return null;
}
//
......@@ -341,7 +326,8 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
log.debug("Generating intent for prefix {}, next hop mac {}",
prefix, nextHopMacAddress);
for (Interface intf : configService.getInterfaces()) {
for (Interface intf : interfaceService.getInterfaces()) {
// TODO this should be only peering interfaces
if (!intf.connectPoint().equals(egressInterface.connectPoint())) {
ConnectPoint srcPort = intf.connectPoint();
ingressPorts.add(srcPort);
......
......@@ -26,9 +26,10 @@ import org.onosproject.cluster.ControllerNode;
import org.onosproject.cluster.LeadershipEvent;
import org.onosproject.cluster.LeadershipEventListener;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.config.NetworkConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.IntentService;
import org.onosproject.routing.RoutingService;
......@@ -70,14 +71,12 @@ public class SdnIp implements SdnIpService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RoutingConfigurationService config;
//
// NOTE: Unused reference - needed to guarantee that the
// NetworkConfigReader component is activated and the network configuration
// is read.
//
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService networkConfigService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected InterfaceService interfaceService;
private IntentSynchronizer intentSynchronizer;
private PeerConnectivityManager peerConnectivity;
......@@ -96,12 +95,15 @@ public class SdnIp implements SdnIpService {
intentSynchronizer = new IntentSynchronizer(appId, intentService,
hostService,
config);
config,
interfaceService);
intentSynchronizer.start();
peerConnectivity = new PeerConnectivityManager(appId,
intentSynchronizer,
config);
networkConfigService,
coreService.getAppId(RoutingService.ROUTER_APP_ID),
interfaceService);
peerConnectivity.start();
routingService.addFibListener(intentSynchronizer);
......
......@@ -28,6 +28,9 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
......@@ -45,7 +48,6 @@ import org.onosproject.routing.FibEntry;
import org.onosproject.routing.FibUpdate;
import org.onosproject.routing.RouteEntry;
import org.onosproject.routing.config.BgpPeer;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
......@@ -56,7 +58,11 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static org.easymock.EasyMock.*;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
......@@ -71,7 +77,9 @@ import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId;
public class IntentSyncTest extends AbstractIntentTest {
private RoutingConfigurationService routingConfig;
private InterfaceService interfaceService;
private IntentService intentService;
private NetworkConfigService configService;
private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
DeviceId.deviceId("of:0000000000000001"),
......@@ -90,6 +98,7 @@ public class IntentSyncTest extends AbstractIntentTest {
PortNumber.portNumber(1));
private IntentSynchronizer intentSynchronizer;
private final Set<Interface> interfaces = Sets.newHashSet();
private static final ApplicationId APPID = new ApplicationId() {
@Override
......@@ -108,17 +117,21 @@ public class IntentSyncTest extends AbstractIntentTest {
super.setUp();
routingConfig = createMock(RoutingConfigurationService.class);
interfaceService = createMock(InterfaceService.class);
configService = createMock(NetworkConfigService.class);
// These will set expectations on routingConfig
setUpInterfaceService();
setUpBgpPeers();
replay(routingConfig);
replay(interfaceService);
intentService = createMock(IntentService.class);
intentSynchronizer = new IntentSynchronizer(APPID, intentService,
null, routingConfig);
null, routingConfig,
interfaceService);
}
/**
......@@ -152,9 +165,6 @@ public class IntentSyncTest extends AbstractIntentTest {
* Sets up InterfaceService.
*/
private void setUpInterfaceService() {
Set<Interface> interfaces = Sets.newHashSet();
Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
interfaceIpAddresses1.add(new InterfaceIpAddress(
IpAddress.valueOf("192.168.10.101"),
......@@ -190,16 +200,26 @@ public class IntentSyncTest extends AbstractIntentTest {
MacAddress.valueOf("00:00:00:00:00:04"),
VlanId.vlanId((short) 1));
expect(routingConfig.getInterface(SW4_ETH1)).andReturn(
sw4Eth1).anyTimes();
expect(interfaceService.getInterfacesByPort(SW4_ETH1)).andReturn(
Collections.singleton(sw4Eth1)).anyTimes();
expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.40.1")))
.andReturn(sw4Eth1).anyTimes();
interfaces.add(sw4Eth1);
expect(routingConfig.getInterface(SW1_ETH1)).andReturn(
sw1Eth1).anyTimes();
expect(routingConfig.getInterface(SW2_ETH1)).andReturn(
sw2Eth1).anyTimes();
expect(routingConfig.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
expect(routingConfig.getInterfaces()).andReturn(interfaces).anyTimes();
expect(interfaceService.getInterfacesByPort(SW1_ETH1)).andReturn(
Collections.singleton(sw1Eth1)).anyTimes();
expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.10.1")))
.andReturn(sw1Eth1).anyTimes();
expect(interfaceService.getInterfacesByPort(SW2_ETH1)).andReturn(
Collections.singleton(sw2Eth1)).anyTimes();
expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.20.1")))
.andReturn(sw2Eth1).anyTimes();
expect(interfaceService.getInterfacesByPort(SW3_ETH1)).andReturn(
Collections.singleton(sw3Eth1)).anyTimes();
expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.30.1")))
.andReturn(sw3Eth1).anyTimes();
expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
}
/**
......@@ -599,8 +619,8 @@ public class IntentSyncTest extends AbstractIntentTest {
treatmentBuilder.setEthDst(MacAddress.valueOf(nextHopMacAddress));
Set<ConnectPoint> ingressPoints = new HashSet<>();
for (Interface intf : routingConfig.getInterfaces()) {
if (!intf.equals(routingConfig.getInterface(egressPoint))) {
for (Interface intf : interfaces) {
if (!intf.connectPoint().equals(egressPoint)) {
ConnectPoint srcPort = intf.connectPoint();
ingressPoints.add(srcPort);
}
......@@ -621,7 +641,6 @@ public class IntentSyncTest extends AbstractIntentTest {
* A static MultiPointToSinglePointIntent builder, the returned intent is
* equal to the input intent except that the id is different.
*
*
* @param intent the intent to be used for building a new intent
* @param routeEntry the relative routeEntry of the intent
* @return the newly constructed MultiPointToSinglePointIntent
......
......@@ -23,6 +23,7 @@ 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.net.config.Config;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigService;
......@@ -49,11 +50,11 @@ public class NetworkConfigLoader {
// FIXME: Add mutual exclusion to make sure this happens only once per startup.
private Map<InnerConfigPosition, ObjectNode> jsons = Maps.newHashMap();
private final Map<InnerConfigPosition, ObjectNode> jsons = Maps.newConcurrentMap();
private final NetworkConfigListener configListener = new InnerConfigListener();
ObjectNode root;
private ObjectNode root;
@Activate
public void activate() {
......@@ -101,24 +102,24 @@ public class NetworkConfigLoader {
* Inner class that allows for tracking of JSON class configurations.
*/
private final class InnerConfigPosition {
private String subjectKey, subject, classKey;
private final String subjectKey, subject, configKey;
private String getSubjectKey() {
private String subjectKey() {
return subjectKey;
}
private String getSubject() {
private String subject() {
return subject;
}
private String getClassKey() {
return classKey;
private String configKey() {
return configKey;
}
private InnerConfigPosition(String subjectKey, String subject, String classKey) {
private InnerConfigPosition(String subjectKey, String subject, String configKey) {
this.subjectKey = subjectKey;
this.subject = subject;
this.classKey = classKey;
this.configKey = configKey;
}
@Override
......@@ -128,15 +129,16 @@ public class NetworkConfigLoader {
}
if (obj instanceof InnerConfigPosition) {
final InnerConfigPosition that = (InnerConfigPosition) obj;
return Objects.equals(this.subjectKey, that.subjectKey) && Objects.equals(this.subject, that.subject)
&& Objects.equals(this.classKey, that.classKey);
return Objects.equals(this.subjectKey, that.subjectKey)
&& Objects.equals(this.subject, that.subject)
&& Objects.equals(this.configKey, that.configKey);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(subjectKey, subject, classKey);
return Objects.hash(subjectKey, subject, configKey);
}
}
......@@ -174,38 +176,41 @@ public class NetworkConfigLoader {
}
/**
* Apply the configurations associated with all of the config classes that are imported and have not yet been
* applied.
* Apply the configurations associated with all of the config classes that
* are imported and have not yet been applied.
*/
protected void applyConfigurations() {
private void applyConfigurations() {
Iterator<Map.Entry<InnerConfigPosition, ObjectNode>> iter = jsons.entrySet().iterator();
Map.Entry<InnerConfigPosition, ObjectNode> entry;
InnerConfigPosition key;
ObjectNode node;
String subjectKey;
String subject;
String classKey;
String subjectString;
String configKey;
while (iter.hasNext()) {
entry = iter.next();
node = entry.getValue();
key = entry.getKey();
subjectKey = key.getSubjectKey();
subject = key.getSubject();
classKey = key.getClassKey();
subjectKey = key.subjectKey();
subjectString = key.subject();
configKey = key.configKey();
Class<? extends Config> configClass =
networkConfigService.getConfigClass(subjectKey, configKey);
//Check that the config class has been imported
if (networkConfigService.getConfigClass(subjectKey, subject) != null) {
if (configClass != null) {
Object subject = networkConfigService.getSubjectFactory(subjectKey).
createSubject(subjectString);
//Apply the configuration
networkConfigService.applyConfig(networkConfigService.getSubjectFactory(subjectKey).
createSubject(subject),
networkConfigService.getConfigClass(subjectKey, classKey), node);
networkConfigService.applyConfig(subject, configClass, node);
//Now that it has been applied the corresponding JSON entry is no longer needed
jsons.remove(key);
iter.remove();
}
}
}
......
......@@ -24,6 +24,7 @@ import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.provider.AbstractListenerProviderRegistry;
import org.onosproject.core.Permission;
import org.onosproject.net.config.NetworkConfigEvent;
......@@ -86,6 +87,9 @@ public class HostManager
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService networkConfigService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected InterfaceService interfaceService;
private HostMonitor monitor;
@Activate
......@@ -93,7 +97,7 @@ public class HostManager
store.setDelegate(delegate);
eventDispatcher.addSink(HostEvent.class, listenerRegistry);
networkConfigService.addListener(networkConfigListener);
monitor = new HostMonitor(deviceService, packetService, this);
monitor = new HostMonitor(packetService, this, interfaceService);
monitor.start();
log.info("Started");
}
......
......@@ -20,26 +20,23 @@ import org.jboss.netty.util.TimerTask;
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP6;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IPv6;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.packet.ndp.NeighborDiscoveryOptions;
import org.onlab.packet.ndp.NeighborSolicitation;
import org.onlab.util.Timer;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.Port;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.host.PortAddresses;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketService;
......@@ -63,9 +60,9 @@ import java.util.concurrent.TimeUnit;
* </p>
*/
public class HostMonitor implements TimerTask {
private DeviceService deviceService;
private PacketService packetService;
private HostManager hostManager;
private InterfaceService interfaceService;
private final Set<IpAddress> monitoredAddresses;
......@@ -80,20 +77,19 @@ public class HostMonitor implements TimerTask {
/**
* Creates a new host monitor.
*
* @param deviceService device service used to find edge ports
* @param packetService packet service used to send packets on the data plane
* @param hostManager host manager used to look up host information and
* probe existing hosts
* @param interfaceService interface service for interface information
*/
public HostMonitor(DeviceService deviceService, PacketService packetService,
HostManager hostManager) {
public HostMonitor(PacketService packetService, HostManager hostManager,
InterfaceService interfaceService) {
this.deviceService = deviceService;
this.packetService = packetService;
this.hostManager = hostManager;
this.interfaceService = interfaceService;
monitoredAddresses = Collections.newSetFromMap(
new ConcurrentHashMap<IpAddress, Boolean>());
monitoredAddresses = Collections.newSetFromMap(new ConcurrentHashMap<>());
hostProviders = new ConcurrentHashMap<>();
}
......@@ -176,29 +172,21 @@ public class HostMonitor implements TimerTask {
* @param targetIp IP address to send the request for
*/
private void sendArpNdpRequest(IpAddress targetIp) {
// Find ports with an IP address in the target's subnet and sent ARP/ND
// probes out those ports.
for (Device device : deviceService.getDevices()) {
for (Port port : deviceService.getPorts(device.id())) {
ConnectPoint cp = new ConnectPoint(device.id(), port.number());
Set<PortAddresses> portAddressSet =
hostManager.getAddressBindingsForPort(cp);
for (PortAddresses portAddresses : portAddressSet) {
for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
if (ia.subnetAddress().contains(targetIp)) {
sendArpNdpProbe(device.id(), port, targetIp,
ia.ipAddress(),
portAddresses.mac(),
portAddresses.vlan());
}
}
}
Interface intf = interfaceService.getMatchingInterface(targetIp);
if (intf == null) {
return;
}
for (InterfaceIpAddress ia : intf.ipAddresses()) {
if (ia.subnetAddress().contains(targetIp)) {
sendArpNdpProbe(intf.connectPoint(), targetIp, ia.ipAddress(),
intf.mac(), intf.vlan());
}
}
}
private void sendArpNdpProbe(DeviceId deviceId, Port port,
private void sendArpNdpProbe(ConnectPoint connectPoint,
IpAddress targetIp,
IpAddress sourceIp, MacAddress sourceMac,
VlanId vlan) {
......@@ -215,14 +203,14 @@ public class HostMonitor implements TimerTask {
}
List<Instruction> instructions = new ArrayList<>();
instructions.add(Instructions.createOutput(port.number()));
instructions.add(Instructions.createOutput(connectPoint.port()));
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(port.number())
.setOutput(connectPoint.port())
.build();
OutboundPacket outboundPacket =
new DefaultOutboundPacket(deviceId, treatment,
new DefaultOutboundPacket(connectPoint.deviceId(), treatment,
ByteBuffer.wrap(probePacket.serialize()));
packetService.emit(outboundPacket);
......
......@@ -98,7 +98,7 @@ public class MultiPointToSinglePointIntentCompiler
partialTree = true;
for (Link link : path.links()) {
if (links.containsKey(link.src().deviceId())) {
if (links.containsKey(link.dst().deviceId())) {
// We've already reached the existing tree with the first
// part of this path. Add the merging point with different
// incoming port, but don't add the remainder of the path
......
......@@ -26,6 +26,8 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
......@@ -94,7 +96,7 @@ public class HostMonitorTest {
expectLastCall().once();
replay(hostProvider);
hostMonitor = new HostMonitor(null, null, hostManager);
hostMonitor = new HostMonitor(null, hostManager, null);
hostMonitor.registerHostProvider(hostProvider);
hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
......@@ -129,16 +131,20 @@ public class HostMonitorTest {
new PortAddresses(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE);
expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
.andReturn(Collections.<Host>emptySet()).anyTimes();
expect(hostManager.getAddressBindingsForPort(cp))
.andReturn(Collections.singleton(pa)).anyTimes();
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE))
.anyTimes();
replay(interfaceService);
TestPacketService packetService = new TestPacketService();
// Run the test
hostMonitor = new HostMonitor(deviceService, packetService, hostManager);
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService);
hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
hostMonitor.run(null);
......@@ -197,16 +203,20 @@ public class HostMonitorTest {
VlanId.vlanId(vlan));
expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
.andReturn(Collections.<Host>emptySet()).anyTimes();
expect(hostManager.getAddressBindingsForPort(cp))
.andReturn(Collections.singleton(pa)).anyTimes();
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
.andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.vlanId(vlan)))
.anyTimes();
replay(interfaceService);
TestPacketService packetService = new TestPacketService();
// Run the test
hostMonitor = new HostMonitor(deviceService, packetService, hostManager);
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService);
hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
hostMonitor.run(null);
......
......@@ -23,8 +23,11 @@ import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultHost;
import org.onosproject.net.Device;
......@@ -44,7 +47,6 @@ import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.host.HostService;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.host.PortAddresses;
import org.onosproject.net.link.LinkListener;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.packet.DefaultOutboundPacket;
......@@ -57,12 +59,17 @@ import org.onosproject.net.proxyarp.ProxyArpStoreDelegate;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Tests for the {@link ProxyArpManager} class.
......@@ -104,6 +111,7 @@ public class ProxyArpManagerTest {
private DeviceService deviceService;
private LinkService linkService;
private HostService hostService;
private InterfaceService interfaceService;
@Before
public void setUp() throws Exception {
......@@ -119,6 +127,9 @@ public class ProxyArpManagerTest {
hostService = createMock(HostService.class);
proxyArp.hostService = hostService;
interfaceService = createMock(InterfaceService.class);
proxyArp.interfaceService = interfaceService;
createTopology();
proxyArp.deviceService = deviceService;
proxyArp.linkService = linkService;
......@@ -207,7 +218,7 @@ public class ProxyArpManagerTest {
}
private void addAddressBindings() {
Set<PortAddresses> addresses = Sets.newHashSet();
Set<Interface> interfaces = Sets.newHashSet();
for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
......@@ -219,29 +230,28 @@ public class ProxyArpManagerTest {
Ip4Address addr2 = Ip4Address.valueOf("10.0." + (2 * i) + ".1");
InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
PortAddresses pa1 =
new PortAddresses(cp, Sets.newHashSet(ia1),
MacAddress.valueOf(2 * i - 1),
VlanId.vlanId((short) 1));
PortAddresses pa2 =
new PortAddresses(cp, Sets.newHashSet(ia2),
MacAddress.valueOf(2 * i),
VlanId.NONE);
addresses.add(pa1);
addresses.add(pa2);
expect(hostService.getAddressBindingsForPort(cp))
.andReturn(Sets.newHashSet(pa1, pa2)).anyTimes();
Interface intf1 = new Interface(cp, Sets.newHashSet(ia1),
MacAddress.valueOf(2 * i - 1),
VlanId.vlanId((short) 1));
Interface intf2 = new Interface(cp, Sets.newHashSet(ia2),
MacAddress.valueOf(2 * i),
VlanId.NONE);
interfaces.add(intf1);
interfaces.add(intf2);
expect(interfaceService.getInterfacesByPort(cp))
.andReturn(Sets.newHashSet(intf1, intf2)).anyTimes();
}
expect(hostService.getAddressBindings()).andReturn(addresses).anyTimes();
expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
for (int i = 1; i <= NUM_FLOOD_PORTS; i++) {
ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS),
P1);
expect(hostService.getAddressBindingsForPort(cp))
.andReturn(Collections.<PortAddresses>emptySet()).anyTimes();
expect(interfaceService.getInterfacesByPort(cp))
.andReturn(Collections.emptySet()).anyTimes();
}
}
......@@ -254,6 +264,7 @@ public class ProxyArpManagerTest {
public void testNotKnown() {
expect(hostService.getHostsByIp(IP1)).andReturn(Collections.<Host>emptySet());
replay(hostService);
replay(interfaceService);
assertFalse(proxyArp.isKnown(IP1));
}
......@@ -271,6 +282,7 @@ public class ProxyArpManagerTest {
expect(hostService.getHostsByIp(IP1))
.andReturn(Sets.newHashSet(host1, host2));
replay(hostService);
replay(interfaceService);
assertTrue(proxyArp.isKnown(IP1));
}
......@@ -296,6 +308,7 @@ public class ProxyArpManagerTest {
expect(hostService.getHost(HID2)).andReturn(requestor);
replay(hostService);
replay(interfaceService);
Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
......@@ -319,11 +332,14 @@ public class ProxyArpManagerTest {
Collections.singleton(IP2));
expect(hostService.getHostsByIp(IP1))
.andReturn(Collections.<Host>emptySet());
.andReturn(Collections.emptySet());
expect(interfaceService.getInterfacesByIp(IP2))
.andReturn(Collections.emptySet());
expect(hostService.getHost(HID2)).andReturn(requestor);
replay(hostService);
replay(interfaceService);
Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
......@@ -354,9 +370,12 @@ public class ProxyArpManagerTest {
expect(hostService.getHostsByIp(IP1))
.andReturn(Collections.singleton(replyer));
expect(interfaceService.getInterfacesByIp(IP2))
.andReturn(Collections.emptySet());
expect(hostService.getHost(HID2)).andReturn(requestor);
replay(hostService);
replay(interfaceService);
Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
......@@ -382,6 +401,7 @@ public class ProxyArpManagerTest {
expect(hostService.getHost(HID2)).andReturn(requestor);
replay(hostService);
replay(interfaceService);
Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourFirstIp);
isEdgePointReturn = true;
......@@ -405,6 +425,7 @@ public class ProxyArpManagerTest {
@Test
public void testReplyExternalPortBadRequest() {
replay(hostService); // no further host service expectations
replay(interfaceService);
Ip4Address theirIp = Ip4Address.valueOf("10.0.1.254");
......@@ -428,8 +449,13 @@ public class ProxyArpManagerTest {
Ip4Address theirIp = Ip4Address.valueOf("10.0.1.100");
expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet());
expect(interfaceService.getInterfacesByIp(ourIp))
.andReturn(Collections.singleton(new Interface(getLocation(1),
Collections.singleton(new InterfaceIpAddress(ourIp, IpPrefix.valueOf("10.0.1.1/24"))),
ourMac, VLAN1)));
expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null);
replay(hostService);
replay(interfaceService);
// This is a request from something inside our network (like a BGP
// daemon) to an external host.
......@@ -462,6 +488,7 @@ public class ProxyArpManagerTest {
expect(hostService.getHost(HID1)).andReturn(host1);
expect(hostService.getHost(HID2)).andReturn(host2);
replay(hostService);
replay(interfaceService);
Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
......@@ -482,6 +509,7 @@ public class ProxyArpManagerTest {
public void testForwardFlood() {
expect(hostService.getHost(HID1)).andReturn(null);
replay(hostService);
replay(interfaceService);
Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
......@@ -508,12 +536,7 @@ public class ProxyArpManagerTest {
assertEquals(NUM_FLOOD_PORTS - 1, packetService.packets.size());
Collections.sort(packetService.packets,
new Comparator<OutboundPacket>() {
@Override
public int compare(OutboundPacket o1, OutboundPacket o2) {
return o1.sendThrough().uri().compareTo(o2.sendThrough().uri());
}
});
(o1, o2) -> o1.sendThrough().uri().compareTo(o2.sendThrough().uri()));
for (int i = 0; i < NUM_FLOOD_PORTS - 1; i++) {
......
/*
* Copyright 2015 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.incubator.net.config.basics;
/**
* Signals that an error was encountered while reading/writing configuration.
*/
public class ConfigException extends Exception {
/**
* Constructs a new ConfigException with the given message.
*
* @param message message
*/
public ConfigException(String message) {
super(message);
}
/**
* Constructs a new ConfigException with the given message and cause.
*
* @param message message
* @param cause cause
*/
public ConfigException(String message, Throwable cause) {
super(message, cause);
}
}
......@@ -36,19 +36,41 @@ public class InterfaceConfig extends Config<ConnectPoint> {
public static final String MAC = "mac";
public static final String VLAN = "vlan";
public static final String IP_MISSING_ERROR = "Must have at least one IP address";
public static final String MAC_MISSING_ERROR = "Must have a MAC address for each interface";
public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
/**
* Retrieves all interfaces configured on this port.
*
* @return set of interfaces
* @throws ConfigException if there is any error in the JSON config
*/
public Set<Interface> getInterfaces() {
public Set<Interface> getInterfaces() throws ConfigException {
Set<Interface> interfaces = Sets.newHashSet();
for (JsonNode intfNode : node.path(INTERFACES)) {
interfaces.add(new Interface(subject,
getIps(intfNode),
MacAddress.valueOf(intfNode.path(MAC).asText()),
VlanId.vlanId(Short.parseShort(intfNode.path(VLAN).asText()))));
try {
for (JsonNode intfNode : node.path(INTERFACES)) {
Set<InterfaceIpAddress> ips = getIps(intfNode);
if (ips.isEmpty()) {
throw new ConfigException(IP_MISSING_ERROR);
}
if (intfNode.path(MAC).isMissingNode()) {
throw new ConfigException(MAC_MISSING_ERROR);
}
MacAddress mac = MacAddress.valueOf(intfNode.path(MAC).asText());
VlanId vlan = VlanId.NONE;
if (!intfNode.path(VLAN).isMissingNode()) {
vlan = VlanId.vlanId(Short.valueOf(intfNode.path(VLAN).asText()));
}
interfaces.add(new Interface(subject, ips, mac, vlan));
}
} catch (IllegalArgumentException e) {
throw new ConfigException(CONFIG_VALUE_ERROR, e);
}
return interfaces;
......
......@@ -25,6 +25,8 @@ import org.onosproject.net.host.InterfaceIpAddress;
import java.util.Objects;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* An Interface maps network configuration information (such as addresses and
* vlans) to a port in the network.
......@@ -46,10 +48,10 @@ public class Interface {
public Interface(ConnectPoint connectPoint,
Set<InterfaceIpAddress> ipAddresses,
MacAddress macAddress, VlanId vlan) {
this.connectPoint = connectPoint;
this.ipAddresses = Sets.newHashSet(ipAddresses);
this.macAddress = macAddress;
this.vlan = vlan;
this.connectPoint = checkNotNull(connectPoint);
this.ipAddresses = Sets.newHashSet(checkNotNull(ipAddresses));
this.macAddress = checkNotNull(macAddress);
this.vlan = checkNotNull(vlan);
}
/**
......
......@@ -26,19 +26,18 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.IpAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.incubator.net.config.basics.InterfaceConfig;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.Port;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
......@@ -55,11 +54,11 @@ public class InterfaceManager implements InterfaceService {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService configService;
private static final Class<ConnectPoint> SUBJECT_CLASS = ConnectPoint.class;
private static final Class<InterfaceConfig> CONFIG_CLASS = InterfaceConfig.class;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
protected NetworkConfigService configService;
private final InternalConfigListener listener = new InternalConfigListener();
......@@ -69,14 +68,12 @@ public class InterfaceManager implements InterfaceService {
public void activate() {
configService.addListener(listener);
for (Device d : deviceService.getDevices()) {
for (Port p : deviceService.getPorts(d.id())) {
InterfaceConfig config =
configService.getConfig(new ConnectPoint(d.id(), p.number()), InterfaceConfig.class);
// TODO address concurrency issues here
for (ConnectPoint subject : configService.getSubjects(SUBJECT_CLASS, CONFIG_CLASS)) {
InterfaceConfig config = configService.getConfig(subject, CONFIG_CLASS);
if (config != null) {
updateInterfaces(config);
}
if (config != null) {
updateInterfaces(config);
}
}
......@@ -100,7 +97,11 @@ public class InterfaceManager implements InterfaceService {
@Override
public Set<Interface> getInterfacesByPort(ConnectPoint port) {
return ImmutableSet.copyOf(interfaces.get(port));
Set<Interface> intfs = interfaces.get(port);
if (intfs == null) {
return Collections.emptySet();
}
return ImmutableSet.copyOf(intfs);
}
@Override
......@@ -108,7 +109,9 @@ public class InterfaceManager implements InterfaceService {
return interfaces.values()
.stream()
.flatMap(set -> set.stream())
.filter(intf -> intf.ipAddresses().contains(ip))
.filter(intf -> intf.ipAddresses()
.stream()
.anyMatch(ia -> ia.ipAddress().equals(ip)))
.collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
}
......@@ -139,7 +142,11 @@ public class InterfaceManager implements InterfaceService {
}
private void updateInterfaces(InterfaceConfig intfConfig) {
interfaces.put(intfConfig.subject(), intfConfig.getInterfaces());
try {
interfaces.put(intfConfig.subject(), intfConfig.getInterfaces());
} catch (ConfigException e) {
log.error("Error in interface config", e);
}
}
private void removeInterfaces(ConnectPoint port) {
......