Jonathan Hart

Ported PeerConnectivity onto ONOS next, and implemented a service that can

construct Interface objects based on PortAddresses from HostService.
......@@ -2,35 +2,40 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-apps</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-apps</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-sdnip</artifactId>
<packaging>bundle</packaging>
<artifactId>onos-app-sdnip</artifactId>
<packaging>bundle</packaging>
<description>SDN-IP peering application</description>
<description>SDN-IP peering application</description>
<dependencies>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
</project>
......
package org.onlab.onos.sdnip;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import org.apache.commons.lang.NotImplementedException;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.host.HostService;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.onos.sdnip.config.Interface;
import org.onlab.packet.IpAddress;
import com.google.common.collect.Sets;
/**
* Provides IntefaceService using PortAddresses data from the HostService.
*/
public class HostServiceBasedInterfaceService implements InterfaceService {
private final HostService hostService;
public HostServiceBasedInterfaceService(HostService hostService) {
this.hostService = checkNotNull(hostService);
}
@Override
public Set<Interface> getInterfaces() {
Set<PortAddresses> addresses = hostService.getAddressBindings();
Set<Interface> interfaces = Sets.newHashSetWithExpectedSize(addresses.size());
for (PortAddresses a : addresses) {
interfaces.add(new Interface(a));
}
return interfaces;
}
@Override
public Interface getInterface(ConnectPoint connectPoint) {
checkNotNull(connectPoint);
PortAddresses portAddresses =
hostService.getAddressBindingsForPort(connectPoint);
if (!portAddresses.ips().isEmpty()) {
return new Interface(portAddresses);
}
return null;
}
@Override
public Interface getMatchingInterface(IpAddress ipAddress) {
// TODO implement
throw new NotImplementedException("getMatchingInteface is not yet implemented");
}
}
package org.onlab.onos.sdnip;
import java.util.Set;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.sdnip.config.Interface;
import org.onlab.packet.IpAddress;
/**
* Provides information about the interfaces in the network.
*/
public interface InterfaceService {
/**
* Retrieves the entire set of interfaces in the network.
*
* @return the set of interfaces
*/
Set<Interface> getInterfaces();
/**
* Retrieves the interface associated with the given connect point.
*
* @param connectPoint the connect point to retrieve interface information
* for
* @return the interface
*/
Interface getInterface(ConnectPoint connectPoint);
/**
* Retrieves the interface that matches the given IP address. Matching
* means that the IP address is in one of the interface's assigned subnets.
*
* @param ipAddress IP address to match
* @return the matching interface
*/
Interface getMatchingInterface(IpAddress ipAddress);
}
......@@ -5,6 +5,10 @@ import static org.slf4j.LoggerFactory.getLogger;
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.onlab.onos.net.host.HostService;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.sdnip.config.SdnIpConfigReader;
import org.slf4j.Logger;
......@@ -16,7 +20,14 @@ public class SdnIp {
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentService intentService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
private SdnIpConfigReader config;
private PeerConnectivity peerConnectivity;
@Activate
protected void activate() {
......@@ -24,6 +35,12 @@ public class SdnIp {
config = new SdnIpConfigReader();
config.init();
InterfaceService interfaceService = new HostServiceBasedInterfaceService(hostService);
peerConnectivity = new PeerConnectivity(config, interfaceService, intentService);
peerConnectivity.start();
}
@Deactivate
......
......@@ -8,19 +8,20 @@ import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.packet.IpAddress;
import com.google.common.base.MoreObjects;
/**
* Configuration details for a BGP peer. It contains the peer's IP address and
* an interface name which maps to the interface they are attached at.
* Configuration details for a BGP peer.
*/
public class BgpPeer {
private final ConnectPoint connectPoint;
private final IpAddress ipAddress;
/**
* Class constructor, taking the interface name and IP address of the peer.
* Creates a new BgpPeer.
*
* @param interfaceName the String name of the interface which can be used
* to look up the interface this peer is attached at
* @param dpid the DPID of the switch the peer is attached at, as a String
* @param port the port the peer is attached at
* @param ipAddress the IP address of the peer as a String
*/
public BgpPeer(@JsonProperty("attachmentDpid") String dpid,
......@@ -37,7 +38,7 @@ public class BgpPeer {
*
* @return the connection point
*/
public ConnectPoint getConnectPoint() {
public ConnectPoint connectPoint() {
return connectPoint;
}
......@@ -46,7 +47,7 @@ public class BgpPeer {
*
* @return the IP address
*/
public IpAddress getIpAddress() {
public IpAddress ipAddress() {
return ipAddress;
}
......@@ -69,4 +70,12 @@ public class BgpPeer {
return Objects.equals(this.connectPoint, that.connectPoint)
&& Objects.equals(this.ipAddress, that.ipAddress);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("connectPoint", connectPoint)
.add("ipAddress", ipAddress)
.toString();
}
}
......
......@@ -10,6 +10,8 @@ import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.packet.MacAddress;
import com.google.common.base.MoreObjects;
/**
* Represents a BGP daemon in SDN network.
* <p/>
......@@ -23,28 +25,28 @@ import org.onlab.packet.MacAddress;
* used to reference this speaker in the configuration.
*/
public class BgpSpeaker {
private final String speakerName;
private final ConnectPoint attachmentSwitchPort;
private final String name;
private final ConnectPoint connectPoint;
private final MacAddress macAddress;
private List<InterfaceAddress> interfaceAddresses;
/**
* Class constructor used by the JSON library to create an object.
*
* @param speakerName the name of the BGP router inside SDN network
* @param attachmentDpid the DPID where the BGP router is attached to
* @param attachmentPort the port where the BGP router is attached to
* @param macAddress the MAC address of the BGP router
* @param name the name of the BGP speaker inside SDN network
* @param attachmentDpid the DPID where the BGP speaker is attached to
* @param attachmentPort the port where the BGP speaker is attached to
* @param macAddress the MAC address of the BGP speaker
*/
@JsonCreator
public BgpSpeaker(@JsonProperty("name") String speakerName,
public BgpSpeaker(@JsonProperty("name") String name,
@JsonProperty("attachmentDpid") String attachmentDpid,
@JsonProperty("attachmentPort") int attachmentPort,
@JsonProperty("macAddress") String macAddress) {
this.speakerName = speakerName;
this.name = name;
this.macAddress = MacAddress.valueOf(macAddress);
this.attachmentSwitchPort = new ConnectPoint(
this.connectPoint = new ConnectPoint(
DeviceId.deviceId(SdnIpConfigReader.dpidToUri(attachmentDpid)),
PortNumber.portNumber(attachmentPort));
}
......@@ -67,25 +69,25 @@ public class BgpSpeaker {
*
* @return the BGP speaker name
*/
public String getSpeakerName() {
return speakerName;
public String name() {
return name;
}
/**
* Gets the switch port where the BGP speaker is attached.
* Gets the connect point where the BGP speaker is attached.
*
* @return the switch port where the BGP speaker is attached
* @return the connect point
*/
public ConnectPoint getAttachmentSwitchPort() {
return attachmentSwitchPort;
public ConnectPoint connectPoint() {
return connectPoint;
}
/**
* Gets the MAC address of the BGP speaker.
*
* @return the MAC address of the BGP speaker
* @return the MAC address
*/
public MacAddress getMacAddress() {
public MacAddress macAddress() {
return macAddress;
}
......@@ -96,7 +98,7 @@ public class BgpSpeaker {
* @return a list of IP addresses of the BGP speaker configured on all
* virtual interfaces
*/
public List<InterfaceAddress> getInterfaceAddresses() {
public List<InterfaceAddress> interfaceAddresses() {
return interfaceAddresses;
}
......@@ -108,17 +110,27 @@ public class BgpSpeaker {
BgpSpeaker otherBgpSpeaker = (BgpSpeaker) other;
return speakerName.equals(otherBgpSpeaker.speakerName) &&
attachmentSwitchPort.equals(
otherBgpSpeaker.attachmentSwitchPort) &&
return name.equals(otherBgpSpeaker.name) &&
connectPoint.equals(
otherBgpSpeaker.connectPoint) &&
macAddress.equals(otherBgpSpeaker.macAddress) &&
interfaceAddresses.equals(otherBgpSpeaker.interfaceAddresses);
}
@Override
public int hashCode() {
return Objects.hash(speakerName, attachmentSwitchPort, macAddress,
return Objects.hash(name, connectPoint, macAddress,
interfaceAddresses);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("speakerName", name)
.add("connectPoint", connectPoint)
.add("macAddress", macAddress)
.add("interfaceAddresses", interfaceAddresses)
.toString();
}
}
......
package org.onlab.onos.sdnip.config;
import java.util.Objects;
import java.util.Set;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Sets;
/**
* Represents an interface, which is an external-facing switch port that
* connects to another network.
* <p/>
* SDN-IP treats external-facing ports similarly to router ports. Logically, it
* assigns an IP subnetwork prefix and several IP addresses to each port which
* are used for communication with the BGP peers located in other networks, for
* example, the BGP peering sessions. The peers in other networks will be
* configured to peer with the IP addresses (logically) assigned to the
* interface. The logical {@code Interface} construct maps on to a physical
* port in the data plane, which of course has no notion of IP addresses.
* <p/>
* Each interface has a name, which is a unique identifying String that is used
* to reference this interface in the configuration (for example, to map
* {@link BgpPeer}s to {@code Interfaces}.
* An Interface is a set of addresses that are logically mapped to a switch
* port in the network.
*/
public class Interface {
private final String name;
private final ConnectPoint switchPort;
private final IpPrefix ip4Prefix;
private final ConnectPoint connectPoint;
private final Set<IpPrefix> ipAddresses;
private final MacAddress macAddress;
/**
* Class constructor used by the JSON library to create an object.
* Creates an Interface based on a connection point, a set of IP addresses
* and a MAC address.
*
* @param name the name of the interface
* @param dpid the dpid of the switch
* @param port the port on the switch
* @param prefixAddress the network prefix address logically assigned to the
* interface
* @param prefixLength the length of the network prefix of the IP address
* @param connectPoint the connect point this interface is mapped to
* @param prefixAddress the IP addresses for the interface
* @param macAddress the MAC address of the interface
*/
@JsonCreator
public Interface(@JsonProperty("name") String name,
@JsonProperty("dpid") String dpid,
@JsonProperty("port") int port,
@JsonProperty("ipAddress") String prefixAddress,
@JsonProperty("prefixLength") short prefixLength) {
this.name = name;
this.switchPort = new ConnectPoint(
DeviceId.deviceId(SdnIpConfigReader.dpidToUri(dpid)),
PortNumber.portNumber(port));
this.ip4Prefix = IpPrefix.valueOf(prefixAddress + "/" + prefixLength);
public Interface(ConnectPoint connectPoint, Set<IpPrefix> prefixAddress,
MacAddress macAddress) {
this.connectPoint = connectPoint;
this.ipAddresses = Sets.newHashSet(prefixAddress);
this.macAddress = macAddress;
}
/**
* Gets the name of the interface.
* Creates an Interface based on a PortAddresses object.
*
* @return the name of the interface
* @param portAddresses the PortAddresses object to turn into an Interface
*/
public String getName() {
return name;
public Interface(PortAddresses portAddresses) {
connectPoint = portAddresses.connectPoint();
ipAddresses = Sets.newHashSet(portAddresses.ips());
macAddress = portAddresses.mac();
}
/**
* Gets the {@link SwitchPort} that this interface maps to.
* Retrieves the connection point that this interface maps to.
*
* @return the switch port
* @return the connection point
*/
public ConnectPoint getSwitchPort() {
return switchPort;
public ConnectPoint connectPoint() {
return connectPoint;
}
/**
* Gets the IP prefix of the subnetwork which is logically assigned
* to the switch port.
* Retrieves the set of IP addresses that are assigned to the interface.
*
* @return the IP prefix
* @return the set of IP addresses
*/
public IpPrefix getIp4Prefix() {
return ip4Prefix;
public Set<IpPrefix> ips() {
return ipAddresses;
}
/**
* Retrieves the MAC address that is assigned to the interface.
*
* @return the MAC address
*/
public MacAddress mac() {
return macAddress;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Interface)) {
......@@ -89,13 +81,22 @@ public class Interface {
Interface otherInterface = (Interface) other;
return name.equals(otherInterface.name) &&
switchPort.equals(otherInterface.switchPort) &&
ip4Prefix.equals(otherInterface.ip4Prefix);
return connectPoint.equals(otherInterface.connectPoint) &&
ipAddresses.equals(otherInterface.ipAddresses) &&
macAddress.equals(otherInterface.macAddress);
}
@Override
public int hashCode() {
return Objects.hash(name, switchPort, ip4Prefix);
return Objects.hash(connectPoint, ipAddresses, macAddress);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("connectPoint", connectPoint)
.add("ipAddresses", ipAddresses)
.add("macAddress", macAddress)
.toString();
}
}
......
......@@ -8,6 +8,8 @@ import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.packet.IpAddress;
import com.google.common.base.MoreObjects;
/**
* Represents an address of a {@link BgpSpeaker} configured on an
* {@link Interface}.
......@@ -19,10 +21,10 @@ public class InterfaceAddress {
private final IpAddress ipAddress;
/**
* Class constructor used by the JSON library to create an object.
* Creates an InterfaceAddress object.
*
* @param interfaceName the interface name for which an IP address of a BGP
* router is configured
* @param dpid the DPID of the interface as a String
* @param port the port of the interface
* @param ipAddress the IP address of a {@link BgpSpeaker} configured on
* the interface
*/
......@@ -40,7 +42,7 @@ public class InterfaceAddress {
*
* @return the connection point
*/
public ConnectPoint getConnectPoint() {
public ConnectPoint connectPoint() {
return connectPoint;
}
......@@ -49,7 +51,7 @@ public class InterfaceAddress {
*
* @return the IP address
*/
public IpAddress getIpAddress() {
public IpAddress ipAddress() {
return ipAddress;
}
......@@ -72,4 +74,12 @@ public class InterfaceAddress {
return Objects.equals(this.connectPoint, that.connectPoint)
&& Objects.equals(this.ipAddress, that.ipAddress);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("connectPoint", connectPoint)
.add("ipAddress", ipAddress)
.toString();
}
}
......
......@@ -50,11 +50,11 @@ public class SdnIpConfigReader implements SdnIpConfigService {
}*/
bgpSpeakers = new ConcurrentHashMap<>();
for (BgpSpeaker speaker : config.getBgpSpeakers()) {
bgpSpeakers.put(speaker.getSpeakerName(), speaker);
bgpSpeakers.put(speaker.name(), speaker);
}
bgpPeers = new ConcurrentHashMap<>();
for (BgpPeer peer : config.getPeers()) {
bgpPeers.put(peer.getIpAddress(), peer);
bgpPeers.put(peer.ipAddress(), peer);
}
} catch (IOException e) {
log.error("Error reading JSON file", e);
......
......@@ -161,10 +161,10 @@ public class FlowModBuilder {
switch (l3m.subtype()) {
case IP_DST:
ip = (ModIPInstruction) i;
return factory.actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
return factory.actions().setNwDst(IPv4Address.of(ip.ip().toRealInt()));
case IP_SRC:
ip = (ModIPInstruction) i;
return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toRealInt()));
default:
log.warn("Unimplemented action type {}.", l3m.subtype());
break;
......@@ -220,21 +220,21 @@ public class FlowModBuilder {
case IPV4_DST:
ip = (IPCriterion) c;
if (ip.ip().isMasked()) {
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()),
IPv4Address.of(ip.ip().netmask().toInt()));
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toRealInt()),
IPv4Address.of(ip.ip().netmask().toRealInt()));
mBuilder.setMasked(MatchField.IPV4_DST, maskedIp);
} else {
mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toInt()));
mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toRealInt()));
}
break;
case IPV4_SRC:
ip = (IPCriterion) c;
if (ip.ip().isMasked()) {
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()),
IPv4Address.of(ip.ip().netmask().toInt()));
Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toRealInt()),
IPv4Address.of(ip.ip().netmask().toRealInt()));
mBuilder.setMasked(MatchField.IPV4_SRC, maskedIp);
} else {
mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toInt()));
mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toRealInt()));
}
break;
case IP_PROTO:
......
......@@ -181,6 +181,15 @@ public final class IpAddress {
return address;
}
public int toRealInt() {
int val = 0;
for (int i = 0; i < octets.length; i++) {
val <<= 8;
val |= octets[i] & 0xff;
}
return val;
}
/**
* Helper for computing the mask value from CIDR.
*
......