Ported PeerConnectivity onto ONOS next, and implemented a service that can
construct Interface objects based on PortAddresses from HostService.
diff --git a/apps/sdnip/pom.xml b/apps/sdnip/pom.xml
index 99960a4..c8db20d 100644
--- a/apps/sdnip/pom.xml
+++ b/apps/sdnip/pom.xml
@@ -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>
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostServiceBasedInterfaceService.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostServiceBasedInterfaceService.java
new file mode 100644
index 0000000..d6ad3c4
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostServiceBasedInterfaceService.java
@@ -0,0 +1,59 @@
+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");
+    }
+
+}
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/InterfaceService.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/InterfaceService.java
new file mode 100644
index 0000000..f9e881f
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/InterfaceService.java
@@ -0,0 +1,37 @@
+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);
+}
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivity.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivity.java
new file mode 100644
index 0000000..75ffd98
--- /dev/null
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivity.java
@@ -0,0 +1,343 @@
+package org.onlab.onos.sdnip;
+
+import java.util.List;
+
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.DefaultTrafficTreatment;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.intent.IntentId;
+import org.onlab.onos.net.intent.IntentService;
+import org.onlab.onos.net.intent.PointToPointIntent;
+import org.onlab.onos.sdnip.config.BgpPeer;
+import org.onlab.onos.sdnip.config.BgpSpeaker;
+import org.onlab.onos.sdnip.config.Interface;
+import org.onlab.onos.sdnip.config.InterfaceAddress;
+import org.onlab.onos.sdnip.config.SdnIpConfigService;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages the connectivity requirements between peers.
+ */
+public class PeerConnectivity {
+
+    private static final Logger log = LoggerFactory.getLogger(
+            PeerConnectivity.class);
+
+    // TODO these shouldn't be defined here
+    private static final short BGP_PORT = 179;
+    private static final int IPV4_BIT_LENGTH = 32;
+
+    private final SdnIpConfigService configInfoService;
+    private final InterfaceService interfaceService;
+    private final IntentService intentService;
+
+    // TODO this sucks.
+    private int intentId = 0;
+
+    public PeerConnectivity(SdnIpConfigService configInfoService,
+            InterfaceService interfaceService, IntentService intentService) {
+        this.configInfoService = configInfoService;
+        this.interfaceService = interfaceService;
+        this.intentService = intentService;
+    }
+
+    public void start() {
+        // TODO are any of these errors?
+        if (interfaceService.getInterfaces().isEmpty()) {
+
+            log.warn("The interface in configuration file is empty. "
+                    + "Thus, the SDN-IP application can not be started.");
+        } else if (configInfoService.getBgpPeers().isEmpty()) {
+
+            log.warn("The BGP peer in configuration file is empty."
+                    + "Thus, the SDN-IP application can not be started.");
+        } else if (configInfoService.getBgpSpeakers() == null) {
+
+            log.error("The BGP speaker in configuration file is empty. "
+                    + "Thus, the SDN-IP application can not be started.");
+            return;
+        }
+
+        setupBgpPaths();
+        setupIcmpPaths();
+    }
+
+    /**
+     * Sets up paths for all {@link BgpSpeaker}s and all external peers.
+     * <p/>
+     * Run a loop for all BGP speakers and a loop for all BGP peers outside.
+     * Push intents for paths from each BGP speaker to all peers. Push intents
+     * for paths from all peers to each BGP speaker.
+     */
+    private void setupBgpPaths() {
+        for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers()
+                .values()) {
+            log.debug("Start to set up BGP paths for BGP speaker: {}",
+                    bgpSpeaker);
+            ConnectPoint bgpdConnectPoint = bgpSpeaker.connectPoint();
+
+            List<InterfaceAddress> interfaceAddresses =
+                    bgpSpeaker.interfaceAddresses();
+
+            for (BgpPeer bgpPeer : configInfoService.getBgpPeers().values()) {
+
+                log.debug("Start to set up BGP paths between BGP speaker: {} "
+                        + "to BGP peer: {}", bgpSpeaker, bgpPeer);
+
+                Interface peerInterface = interfaceService.getInterface(
+                        bgpPeer.connectPoint());
+                if (peerInterface == null) {
+                    log.error("Can not find the corresponding Interface from "
+                            + "configuration for BGP peer {}",
+                            bgpPeer.ipAddress());
+                    continue;
+                }
+
+                IpAddress bgpdAddress = null;
+                for (InterfaceAddress interfaceAddress : interfaceAddresses) {
+                    if (interfaceAddress.connectPoint().equals(
+                            peerInterface.connectPoint())) {
+                        bgpdAddress = interfaceAddress.ipAddress();
+                        break;
+                    }
+                }
+                if (bgpdAddress == null) {
+                    log.debug("There is no interface IP address for bgpPeer: {}"
+                            + " on interface {}", bgpPeer, bgpPeer.connectPoint());
+                    return;
+                }
+
+                IpAddress bgpdPeerAddress = bgpPeer.ipAddress();
+                ConnectPoint bgpdPeerConnectPoint = peerInterface.connectPoint();
+
+                // install intent for BGP path from BGPd to BGP peer matching
+                // destination TCP port 179
+
+                // TODO: The usage of PacketMatchBuilder will be improved, then we
+                // only need to new the PacketMatchBuilder once.
+                // By then, the code here will be improved accordingly.
+                /*PacketMatch packetMatch = new PacketMatchBuilder().setEtherType(
+                        Ethernet.TYPE_IPV4)
+                        .setIpProto(PROTOCOL_TCP)
+                        .setSrcIpNet(new Ip4Prefix(bgpdAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setDstIpNet(new Ip4Prefix(bgpdPeerAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setDstTcpPort(BGP_PORT)
+                        .build();
+                        */
+
+                TrafficSelector selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchIPProtocol(IPv4.PROTOCOL_TCP)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchTcpDst(BGP_PORT)
+                        .build();
+
+                TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                        .build();
+
+                PointToPointIntent intentMatchDstTcpPort = new PointToPointIntent(
+                        nextIntentId(), selector, treatment,
+                        bgpdConnectPoint, bgpdPeerConnectPoint);
+                intentService.submit(intentMatchDstTcpPort);
+                log.debug("Submitted BGP path intent matching dst TCP port 179 "
+                        + "from BGPd {} to peer {}: {}",
+                        bgpdAddress, bgpdPeerAddress, intentMatchDstTcpPort);
+
+                // install intent for BGP path from BGPd to BGP peer matching
+                // source TCP port 179
+                /*packetMatch = new PacketMatchBuilder().setEtherType(Ethernet.TYPE_IPV4)
+                        .setIpProto(PROTOCOL_TCP)
+                        .setSrcIpNet(new Ip4Prefix(bgpdAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setDstIpNet(new Ip4Prefix(bgpdPeerAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setSrcTcpPort(BGP_PORT)
+                        .build();*/
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchIPProtocol(IPv4.PROTOCOL_TCP)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchTcpSrc(BGP_PORT)
+                        .build();
+
+                PointToPointIntent intentMatchSrcTcpPort = new PointToPointIntent(
+                        nextIntentId(), selector, treatment,
+                        bgpdConnectPoint, bgpdPeerConnectPoint);
+                intentService.submit(intentMatchSrcTcpPort);
+                log.debug("Submitted BGP path intent matching src TCP port 179"
+                        + "from BGPd {} to peer {}: {}",
+                        bgpdAddress, bgpdPeerAddress, intentMatchSrcTcpPort);
+
+                // install intent for reversed BGP path from BGP peer to BGPd
+                // matching destination TCP port 179
+                /*packetMatch = new PacketMatchBuilder().setEtherType(Ethernet.TYPE_IPV4)
+                        .setIpProto(PROTOCOL_TCP)
+                        .setSrcIpNet(new Ip4Prefix(bgpdPeerAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setDstIpNet(new Ip4Prefix(bgpdAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setDstTcpPort(BGP_PORT)
+                        .build();*/
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchIPProtocol(IPv4.PROTOCOL_TCP)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchTcpDst(BGP_PORT)
+                        .build();
+
+                PointToPointIntent reversedIntentMatchDstTcpPort = new PointToPointIntent(
+                        nextIntentId(), selector, treatment,
+                        bgpdPeerConnectPoint, bgpdConnectPoint);
+                intentService.submit(reversedIntentMatchDstTcpPort);
+                log.debug("Submitted BGP path intent matching dst TCP port 179"
+                        + "from BGP peer {} to BGPd {} : {}",
+                        bgpdPeerAddress, bgpdAddress, reversedIntentMatchDstTcpPort);
+
+                // install intent for reversed BGP path from BGP peer to BGPd
+                // matching source TCP port 179
+                /*packetMatch = new PacketMatchBuilder().setEtherType(Ethernet.TYPE_IPV4)
+                        .setIpProto(PROTOCOL_TCP)
+                        .setSrcIpNet(new Ip4Prefix(bgpdPeerAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setDstIpNet(new Ip4Prefix(bgpdAddress,
+                                                   (short) Ip4Address.BIT_LENGTH))
+                        .setSrcTcpPort(BGP_PORT)
+                        .build();*/
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchIPProtocol(IPv4.PROTOCOL_TCP)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchTcpSrc(BGP_PORT)
+                        .build();
+
+                PointToPointIntent reversedIntentMatchSrcTcpPort = new PointToPointIntent(
+                        nextIntentId(), selector, treatment,
+                        bgpdPeerConnectPoint, bgpdConnectPoint);
+                intentService.submit(reversedIntentMatchSrcTcpPort);
+                log.debug("Submitted BGP path intent matching src TCP port 179"
+                        + "from BGP peer {} to BGPd {} : {}",
+                        bgpdPeerAddress, bgpdAddress, reversedIntentMatchSrcTcpPort);
+
+            }
+        }
+    }
+
+    /**
+     * Sets up ICMP paths between each {@link BgpSpeaker} and all BGP peers
+     * located in other external networks.
+     * <p/>
+     * Run a loop for all BGP speakers and a loop for all BGP Peers. Push
+     * intents for paths from each BGP speaker to all peers. Push intents
+     * for paths from all peers to each BGP speaker.
+     */
+    private void setupIcmpPaths() {
+        for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers()
+                .values()) {
+            log.debug("Start to set up ICMP paths for BGP speaker: {}",
+                    bgpSpeaker);
+            ConnectPoint bgpdConnectPoint = bgpSpeaker.connectPoint();
+            List<InterfaceAddress> interfaceAddresses = bgpSpeaker
+                    .interfaceAddresses();
+
+            for (BgpPeer bgpPeer : configInfoService.getBgpPeers().values()) {
+
+                Interface peerInterface = interfaceService.getInterface(
+                        bgpPeer.connectPoint());
+
+                if (peerInterface == null) {
+                    log.error("Can not find the corresponding Interface from "
+                            + "configuration for BGP peer {}",
+                            bgpPeer.ipAddress());
+                    continue;
+                }
+                IpAddress bgpdAddress = null;
+                for (InterfaceAddress interfaceAddress : interfaceAddresses) {
+                    if (interfaceAddress.connectPoint().equals(
+                            peerInterface.connectPoint())) {
+                        bgpdAddress = interfaceAddress.ipAddress();
+                        break;
+                    }
+
+                }
+                if (bgpdAddress == null) {
+                    log.debug("There is no IP address for bgpPeer: {} on "
+                            + "interface port: {}", bgpPeer,
+                            bgpPeer.connectPoint());
+                    return;
+                }
+
+                IpAddress bgpdPeerAddress = bgpPeer.ipAddress();
+                ConnectPoint bgpdPeerConnectPoint = peerInterface.connectPoint();
+
+                // install intent for ICMP path from BGPd to BGP peer
+                /*PacketMatch packetMatch =
+                        new PacketMatchBuilder().setEtherType(
+                                Ethernet.TYPE_IPV4)
+                        .setIpProto(PROTOCOL_ICMP)
+                        .setSrcIpNet(new Ip4Prefix(bgpdAddress,
+                                (short) Ip4Address.BIT_LENGTH))
+                                .setDstIpNet(new Ip4Prefix(bgpdPeerAddress,
+                                        (short) Ip4Address.BIT_LENGTH))
+                                        .build();*/
+                TrafficSelector selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchIPProtocol(IPv4.PROTOCOL_ICMP)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .build();
+
+                TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                        .build();
+
+                PointToPointIntent intent = new PointToPointIntent(
+                        nextIntentId(), selector, treatment,
+                        bgpdConnectPoint, bgpdPeerConnectPoint);
+                intentService.submit(intent);
+                log.debug("Submitted ICMP path intent from BGPd {} to peer {} :"
+                        + " {}", bgpdAddress, bgpdPeerAddress, intent);
+
+                // install intent for reversed ICMP path from BGP peer to BGPd
+                /*packetMatch = new PacketMatchBuilder().setEtherType(
+                        Ethernet.TYPE_IPV4)
+                        .setIpProto(PROTOCOL_ICMP)
+                        .setSrcIpNet(new Ip4Prefix(bgpdPeerAddress,
+                                (short) Ip4Address.BIT_LENGTH))
+                                .setDstIpNet(new Ip4Prefix(bgpdAddress,
+                                        (short) Ip4Address.BIT_LENGTH))
+                                        .build();*/
+
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchIPProtocol(IPv4.PROTOCOL_ICMP)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
+                        .build();
+
+                PointToPointIntent reversedIntent = new PointToPointIntent(
+                        nextIntentId(), selector, treatment,
+                        bgpdPeerConnectPoint, bgpdConnectPoint);
+                intentService.submit(reversedIntent);
+                log.debug("Submitted ICMP path intent from BGP peer {} to BGPd"
+                        + " {} : {}",
+                        bgpdPeerAddress, bgpdAddress, reversedIntent);
+            }
+        }
+    }
+
+    private IntentId nextIntentId() {
+        return new IntentId(intentId++);
+    }
+}
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java
index a15faef..25b13f1 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java
@@ -5,6 +5,10 @@
 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 @@
 
     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 @@
 
         config = new SdnIpConfigReader();
         config.init();
+
+        InterfaceService interfaceService = new HostServiceBasedInterfaceService(hostService);
+
+        peerConnectivity = new PeerConnectivity(config, interfaceService, intentService);
+        peerConnectivity.start();
+
     }
 
     @Deactivate
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpPeer.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpPeer.java
index 9d014d0..3e89c58 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpPeer.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpPeer.java
@@ -8,19 +8,20 @@
 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 @@
      *
      * @return the connection point
      */
-    public ConnectPoint getConnectPoint() {
+    public ConnectPoint connectPoint() {
         return connectPoint;
     }
 
@@ -46,7 +47,7 @@
      *
      * @return the IP address
      */
-    public IpAddress getIpAddress() {
+    public IpAddress ipAddress() {
         return ipAddress;
     }
 
@@ -69,4 +70,12 @@
         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();
+    }
 }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpSpeaker.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpSpeaker.java
index c7c2edd..248fc1d 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpSpeaker.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/BgpSpeaker.java
@@ -10,6 +10,8 @@
 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 @@
  * 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 @@
      *
      * @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 @@
      * @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 @@
 
         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();
+    }
 }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java
index 33287ad..88de952 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/Interface.java
@@ -1,86 +1,78 @@
 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 @@
 
         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();
     }
 }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/InterfaceAddress.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/InterfaceAddress.java
index 4b423a7..1ae204f 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/InterfaceAddress.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/InterfaceAddress.java
@@ -8,6 +8,8 @@
 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 @@
     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 @@
      *
      * @return the connection point
      */
-    public ConnectPoint getConnectPoint() {
+    public ConnectPoint connectPoint() {
         return connectPoint;
     }
 
@@ -49,7 +51,7 @@
      *
      * @return the IP address
      */
-    public IpAddress getIpAddress() {
+    public IpAddress ipAddress() {
         return ipAddress;
     }
 
@@ -72,4 +74,12 @@
         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();
+    }
 }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java
index f98cd15..50034ed 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/config/SdnIpConfigReader.java
@@ -50,11 +50,11 @@
             }*/
             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);
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
index 9568f1f..c1c56c3 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
@@ -161,10 +161,10 @@
         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 @@
             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:
diff --git a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
index 44a018e..fef0cfd 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IpAddress.java
@@ -181,6 +181,15 @@
         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.
      *