Merge "Cleanup and javadocs for SDN-IP code"
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
index 400dba0..4056cbe 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
@@ -1,5 +1,7 @@
 package org.onlab.onos.sdnip;
 
+import java.util.List;
+
 import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.DefaultTrafficSelector;
@@ -8,6 +10,7 @@
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.PointToPointIntent;
+import org.onlab.onos.sdnip.bgp.BgpConstants;
 import org.onlab.onos.sdnip.config.BgpPeer;
 import org.onlab.onos.sdnip.config.BgpSpeaker;
 import org.onlab.onos.sdnip.config.Interface;
@@ -20,8 +23,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.List;
-
 /**
  * Manages the connectivity requirements between peers.
  */
@@ -30,37 +31,44 @@
     private static final Logger log = LoggerFactory.getLogger(
             PeerConnectivityManager.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 SdnIpConfigService configService;
     private final InterfaceService interfaceService;
     private final IntentService intentService;
 
     private final ApplicationId appId;
 
+    /**
+     * Creates a new PeerConnectivityManager.
+     *
+     * @param appId             the application ID
+     * @param configService     the SDN-IP config service
+     * @param interfaceService  the interface service
+     * @param intentService     the intent service
+     */
     public PeerConnectivityManager(ApplicationId appId,
-                                   SdnIpConfigService configInfoService,
+                                   SdnIpConfigService configService,
                                    InterfaceService interfaceService,
                                    IntentService intentService) {
         this.appId = appId;
-        this.configInfoService = configInfoService;
+        this.configService = configService;
         this.interfaceService = interfaceService;
         this.intentService = intentService;
     }
 
+    /**
+     * Starts the peer connectivity manager.
+     */
     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()) {
+        } else if (configService.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) {
+        } else if (configService.getBgpSpeakers() == null) {
 
             log.error("The BGP speaker in configuration file is empty. "
                               + "Thus, the SDN-IP application can not be started.");
@@ -79,7 +87,7 @@
      * for paths from all peers to each BGP speaker.
      */
     private void setupBgpPaths() {
-        for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers()
+        for (BgpSpeaker bgpSpeaker : configService.getBgpSpeakers()
                 .values()) {
             log.debug("Start to set up BGP paths for BGP speaker: {}",
                       bgpSpeaker);
@@ -88,7 +96,7 @@
             List<InterfaceAddress> interfaceAddresses =
                     bgpSpeaker.interfaceAddresses();
 
-            for (BgpPeer bgpPeer : configInfoService.getBgpPeers().values()) {
+            for (BgpPeer bgpPeer : configService.getBgpPeers().values()) {
 
                 log.debug("Start to set up BGP paths between BGP speaker: {} "
                                   + "to BGP peer: {}", bgpSpeaker, bgpPeer);
@@ -121,16 +129,14 @@
 
                 // 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.
                 TrafficSelector selector = DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
-                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchTcpDst(BGP_PORT)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchTcpDst((short) BgpConstants.BGP_PORT)
                         .build();
 
                 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
@@ -149,9 +155,11 @@
                 selector = DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
-                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchTcpSrc(BGP_PORT)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchTcpSrc((short) BgpConstants.BGP_PORT)
                         .build();
 
                 PointToPointIntent intentMatchSrcTcpPort =
@@ -167,9 +175,11 @@
                 selector = DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
-                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchTcpDst(BGP_PORT)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchTcpDst((short) BgpConstants.BGP_PORT)
                         .build();
 
                 PointToPointIntent reversedIntentMatchDstTcpPort =
@@ -185,9 +195,11 @@
                 selector = DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
-                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchTcpSrc(BGP_PORT)
+                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchTcpSrc((short) BgpConstants.BGP_PORT)
                         .build();
 
                 PointToPointIntent reversedIntentMatchSrcTcpPort =
@@ -211,7 +223,7 @@
      * for paths from all peers to each BGP speaker.
      */
     private void setupIcmpPaths() {
-        for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers()
+        for (BgpSpeaker bgpSpeaker : configService.getBgpSpeakers()
                 .values()) {
             log.debug("Start to set up ICMP paths for BGP speaker: {}",
                       bgpSpeaker);
@@ -219,7 +231,7 @@
             List<InterfaceAddress> interfaceAddresses = bgpSpeaker
                     .interfaceAddresses();
 
-            for (BgpPeer bgpPeer : configInfoService.getBgpPeers().values()) {
+            for (BgpPeer bgpPeer : configService.getBgpPeers().values()) {
 
                 Interface peerInterface = interfaceService.getInterface(
                         bgpPeer.connectPoint());
@@ -253,8 +265,10 @@
                 TrafficSelector selector = DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_ICMP)
-                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
+                        .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
                         .build();
 
                 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
@@ -271,8 +285,10 @@
                 selector = DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_ICMP)
-                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
-                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
+                        .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
+                        .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
+                                IpAddress.MAX_INET_MASK))
                         .build();
 
                 PointToPointIntent reversedIntent =
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java
index ed5b8df..1d8ef16 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java
@@ -55,8 +55,6 @@
 /**
  * This class processes BGP route update, translates each update into a intent
  * and submits the intent.
- * <p/>
- * TODO: Make it thread-safe.
  */
 public class Router implements RouteListener {
 
@@ -69,14 +67,13 @@
     // Stores all incoming route updates in a queue.
     private BlockingQueue<RouteUpdate> routeUpdates;
 
-    // The Ip4Address is the next hop address of each route update.
+    // The IpAddress is the next hop address of each route update.
     private SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp;
     private ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent> pushedRouteIntents;
 
     private IntentService intentService;
-    //private IProxyArpService proxyArp;
     private HostService hostService;
-    private SdnIpConfigService configInfoService;
+    private SdnIpConfigService configService;
     private InterfaceService interfaceService;
 
     private ExecutorService bgpUpdatesExecutor;
@@ -98,18 +95,19 @@
     /**
      * Class constructor.
      *
+     * @param appId             the application ID
      * @param intentService     the intent service
      * @param hostService       the host service
-     * @param configInfoService the configuration service
+     * @param configService     the configuration service
      * @param interfaceService  the interface service
      */
     public Router(ApplicationId appId, IntentService intentService,
-                  HostService hostService, SdnIpConfigService configInfoService,
+                  HostService hostService, SdnIpConfigService configService,
                   InterfaceService interfaceService) {
         this.appId = appId;
         this.intentService = intentService;
         this.hostService = hostService;
-        this.configInfoService = configInfoService;
+        this.configService = configService;
         this.interfaceService = interfaceService;
 
         bgpRoutes = new ConcurrentInvertedRadixTree<>(
@@ -172,7 +170,7 @@
 
     @Override
     public void update(RouteUpdate routeUpdate) {
-        log.debug("Received new route Update: {}", routeUpdate);
+        log.debug("Received new route update: {}", routeUpdate);
 
         try {
             routeUpdates.put(routeUpdate);
@@ -498,9 +496,11 @@
     private void executeRouteAdd(RouteEntry routeEntry) {
         log.debug("Executing route add: {}", routeEntry);
 
+        // Monitor the IP address so we'll get notified of updates to the MAC
+        // address.
+        hostService.startMonitoringIp(routeEntry.nextHop());
+
         // See if we know the MAC address of the next hop
-        //MacAddress nextHopMacAddress =
-        //proxyArp.getMacAddress(routeEntry.getNextHop());
         MacAddress nextHopMacAddress = null;
         Set<Host> hosts = hostService.getHostsByIp(
                 routeEntry.nextHop().toPrefix());
@@ -511,9 +511,6 @@
 
         if (nextHopMacAddress == null) {
             routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry);
-            //proxyArp.sendArpRequest(routeEntry.getNextHop(), this, true);
-            // TODO maybe just do this for every prefix anyway
-            hostService.startMonitoringIp(routeEntry.nextHop());
             return;
         }
 
@@ -536,11 +533,11 @@
 
         // Find the attachment point (egress interface) of the next hop
         Interface egressInterface;
-        if (configInfoService.getBgpPeers().containsKey(nextHopIpAddress)) {
+        if (configService.getBgpPeers().containsKey(nextHopIpAddress)) {
             // Route to a peer
             log.debug("Route to peer {}", nextHopIpAddress);
             BgpPeer peer =
-                    configInfoService.getBgpPeers().get(nextHopIpAddress);
+                    configService.getBgpPeers().get(nextHopIpAddress);
             egressInterface =
                     interfaceService.getInterface(peer.connectPoint());
         } else {
@@ -593,17 +590,12 @@
         }
 
         // Match the destination IP prefix at the first hop
-        //PacketMatchBuilder builder = new PacketMatchBuilder();
-        //builder.setEtherType(Ethernet.TYPE_IPV4).setDstIpNet(prefix);
-        //PacketMatch packetMatch = builder.build();
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPDst(prefix)
                 .build();
 
         // Rewrite the destination MAC address
-        //ModifyDstMacAction modifyDstMacAction =
-        //new ModifyDstMacAction(nextHopMacAddress);
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .setEthDst(nextHopMacAddress)
                 .build();
@@ -635,10 +627,6 @@
             log.debug("Processing route delete: {}", routeEntry);
             IpPrefix prefix = routeEntry.prefix();
 
-            // TODO check the change of logic here - remove doesn't check that
-            // the route entry was what we expected (and we can't do this
-            // concurrently)
-
             if (bgpRoutes.remove(RouteEntry.createBinaryString(prefix))) {
                 //
                 // Only delete flows if an entry was actually removed from the
@@ -680,17 +668,19 @@
     }
 
     /**
-     * This method handles the prefixes which are waiting for ARP replies for
-     * MAC addresses of next hops.
+     * Signals the Router that the MAC to IP mapping has potentially been
+     * updated. This has the effect of updating the MAC address for any
+     * installed prefixes if it has changed, as well as installing any pending
+     * prefixes that were waiting for MAC resolution.
      *
-     * @param ipAddress  next hop router IP address, for which we sent ARP
-     *                   request out
-     * @param macAddress MAC address which is relative to the ipAddress
+     * @param ipAddress the IP address that an event was received for
+     * @param macAddress the most recently known MAC address for the IP address
      */
-    //@Override
-    // TODO change name
-    public void arpResponse(IpAddress ipAddress, MacAddress macAddress) {
-        log.debug("Received ARP response: {} => {}", ipAddress, macAddress);
+    private void updateMac(IpAddress ipAddress, MacAddress macAddress) {
+        log.debug("Received updated MAC info: {} => {}", ipAddress, macAddress);
+
+        // TODO here we should check whether the next hop for any of our
+        // installed prefixes has changed, not just prefixes pending installation.
 
         // We synchronize on this to prevent changes to the radix tree
         // while we're pushing intents. If the tree changes, the
@@ -708,8 +698,6 @@
                         bgpRoutes.getValueForExactKey(binaryString);
                 if (foundRouteEntry != null &&
                         foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
-                    log.debug("Pushing prefix {} next hop {}",
-                              routeEntry.prefix(), routeEntry.nextHop());
                     // We only push prefix flows if the prefix is still in the
                     // radix tree and the next hop is the same as our
                     // update.
@@ -717,9 +705,8 @@
                     // for the ARP, or the next hop could have changed.
                     addRouteIntentToNextHop(prefix, ipAddress, macAddress);
                 } else {
-                    log.debug("Received ARP response, but {}/{} is no longer in"
-                                      + " the radix tree", routeEntry.prefix(),
-                              routeEntry.nextHop());
+                    log.debug("{} has been revoked before the MAC was resolved",
+                            routeEntry);
                 }
             }
         }
@@ -769,7 +756,7 @@
                     event.type() == HostEvent.Type.HOST_UPDATED) {
                 Host host = event.subject();
                 for (IpPrefix ip : host.ipAddresses()) {
-                    arpResponse(ip.toIpAddress(), host.mac());
+                    updateMac(ip.toIpAddress(), host.mac());
                 }
             }
         }
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 d66ec9c..5ce37c8 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
@@ -26,7 +26,7 @@
 @Service
 public class SdnIp implements SdnIpService {
 
-    private static final String SDN_ID_APP = "org.onlab.onos.sdnip";
+    private static final String SDN_IP_APP = "org.onlab.onos.sdnip";
 
     private final Logger log = getLogger(getClass());
 
@@ -53,8 +53,10 @@
 
         InterfaceService interfaceService = new HostToInterfaceAdaptor(hostService);
 
-        ApplicationId appId = coreService.registerApplication(SDN_ID_APP);
-        peerConnectivity = new PeerConnectivityManager(appId, config, interfaceService, intentService);
+        ApplicationId appId = coreService.registerApplication(SDN_IP_APP);
+
+        peerConnectivity = new PeerConnectivityManager(appId, config,
+                interfaceService, intentService);
         peerConnectivity.start();
 
         router = new Router(appId, intentService, hostService, config, interfaceService);
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java
index 9ab5916..9e7e425 100644
--- a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/RouterTest.java
@@ -1,7 +1,9 @@
 package org.onlab.onos.sdnip;
 
+import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.reset;
 import static org.easymock.EasyMock.verify;
@@ -27,6 +29,7 @@
 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.host.HostListener;
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
@@ -55,10 +58,17 @@
     private IntentService intentService;
     private HostService hostService;
 
-    private Map<IpAddress, BgpPeer> bgpPeers;
-    private Map<IpAddress, BgpPeer> configuredPeers;
-    private Set<Interface> interfaces;
-    private Set<Interface> configuredInterfaces;
+    private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
+            DeviceId.deviceId("of:0000000000000001"),
+            PortNumber.portNumber(1));
+
+    private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
+            DeviceId.deviceId("of:0000000000000002"),
+            PortNumber.portNumber(1));
+
+    private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
+            DeviceId.deviceId("of:0000000000000003"),
+            PortNumber.portNumber(1));
 
     private static final ApplicationId APPID = new ApplicationId() {
         @Override
@@ -76,55 +86,12 @@
 
     @Before
     public void setUp() throws Exception {
-        bgpPeers = setUpBgpPeers();
-        interfaces = setUpInterfaces();
-        initRouter();
-    }
+        setUpBgpPeers();
 
-    /**
-     * Initializes Router class.
-     */
-    private void initRouter() {
+        setUpInterfaceService();
+        setUpHostService();
 
         intentService = createMock(IntentService.class);
-        hostService = createMock(HostService.class);
-
-        interfaceService = createMock(InterfaceService.class);
-        expect(interfaceService.getInterfaces()).andReturn(
-                interfaces).anyTimes();
-
-        Set<IpPrefix> ipAddressesOnSw1Eth1 = new HashSet<IpPrefix>();
-        ipAddressesOnSw1Eth1.add(IpPrefix.valueOf("192.168.10.0/24"));
-        Interface expectedInterface =
-                new Interface(new ConnectPoint(
-                        DeviceId.deviceId("of:0000000000000001"),
-                        PortNumber.portNumber("1")),
-                        ipAddressesOnSw1Eth1,
-                        MacAddress.valueOf("00:00:00:00:00:01"));
-        ConnectPoint egressPoint = new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000001"),
-                PortNumber.portNumber(1));
-        expect(interfaceService.getInterface(egressPoint)).andReturn(
-                expectedInterface).anyTimes();
-
-        Set<IpPrefix> ipAddressesOnSw2Eth1 = new HashSet<IpPrefix>();
-        ipAddressesOnSw2Eth1.add(IpPrefix.valueOf("192.168.20.0/24"));
-        Interface expectedInterfaceNew =
-                new Interface(new ConnectPoint(
-                        DeviceId.deviceId("of:0000000000000002"),
-                        PortNumber.portNumber("1")),
-                        ipAddressesOnSw2Eth1,
-                        MacAddress.valueOf("00:00:00:00:00:02"));
-        ConnectPoint egressPointNew = new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000002"),
-                PortNumber.portNumber(1));
-        expect(interfaceService.getInterface(egressPointNew)).andReturn(
-                expectedInterfaceNew).anyTimes();
-        replay(interfaceService);
-
-        sdnIpConfigService = createMock(SdnIpConfigService.class);
-        expect(sdnIpConfigService.getBgpPeers()).andReturn(bgpPeers).anyTimes();
-        replay(sdnIpConfigService);
 
         router = new Router(APPID, intentService,
                 hostService, sdnIpConfigService, interfaceService);
@@ -132,67 +99,99 @@
 
     /**
      * Sets up BGP peers in external networks.
-     *
-     * @return configured BGP peers as a Map from peer IP address to BgpPeer
      */
-    private Map<IpAddress, BgpPeer> setUpBgpPeers() {
+    private void setUpBgpPeers() {
 
-        configuredPeers = new HashMap<>();
+        Map<IpAddress, BgpPeer> peers = new HashMap<>();
 
         String peerSw1Eth1 = "192.168.10.1";
-        configuredPeers.put(IpAddress.valueOf(peerSw1Eth1),
+        peers.put(IpAddress.valueOf(peerSw1Eth1),
                 new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1));
 
         // Two BGP peers are connected to switch 2 port 1.
         String peer1Sw2Eth1 = "192.168.20.1";
-        configuredPeers.put(IpAddress.valueOf(peer1Sw2Eth1),
+        peers.put(IpAddress.valueOf(peer1Sw2Eth1),
                 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
 
         String peer2Sw2Eth1 = "192.168.20.2";
-        configuredPeers.put(IpAddress.valueOf(peer2Sw2Eth1),
+        peers.put(IpAddress.valueOf(peer2Sw2Eth1),
                 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
 
-        return configuredPeers;
+        sdnIpConfigService = createMock(SdnIpConfigService.class);
+        expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
+        replay(sdnIpConfigService);
+
     }
 
     /**
      * Sets up logical interfaces, which emulate the configured interfaces
      * in SDN-IP application.
-     *
-     * @return configured interfaces as a Set
      */
-    private Set<Interface> setUpInterfaces() {
+    private void setUpInterfaceService() {
+        interfaceService = createMock(InterfaceService.class);
 
-        configuredInterfaces = Sets.newHashSet();
+        Set<Interface> interfaces = Sets.newHashSet();
 
-        Set<IpPrefix> ipAddressesOnSw1Eth1 = new HashSet<IpPrefix>();
-        ipAddressesOnSw1Eth1.add(IpPrefix.valueOf("192.168.10.0/24"));
-        configuredInterfaces.add(
-                new Interface(new ConnectPoint(
-                        DeviceId.deviceId("of:0000000000000001"),
-                        PortNumber.portNumber(1)),
-                        ipAddressesOnSw1Eth1,
-                        MacAddress.valueOf("00:00:00:00:00:01")));
+        Interface sw1Eth1 = new Interface(SW1_ETH1,
+                Sets.newHashSet(IpPrefix.valueOf("192.168.10.101/24")),
+                MacAddress.valueOf("00:00:00:00:00:01"));
 
-        Set<IpPrefix> ipAddressesOnSw2Eth1 = new HashSet<IpPrefix>();
-        ipAddressesOnSw2Eth1.add(IpPrefix.valueOf("192.168.20.0/24"));
-        configuredInterfaces.add(
-                new Interface(new ConnectPoint(
-                        DeviceId.deviceId("of:0000000000000002"),
-                        PortNumber.portNumber(1)),
-                        ipAddressesOnSw2Eth1,
-                        MacAddress.valueOf("00:00:00:00:00:02")));
+        expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
+        interfaces.add(sw1Eth1);
 
-        Set<IpPrefix> ipAddressesOnSw3Eth1 = new HashSet<IpPrefix>();
-        ipAddressesOnSw3Eth1.add(IpPrefix.valueOf("192.168.30.0/24"));
-        configuredInterfaces.add(
-                new Interface(new ConnectPoint(
-                        DeviceId.deviceId("of:0000000000000003"),
-                        PortNumber.portNumber(1)),
-                        ipAddressesOnSw3Eth1,
-                        MacAddress.valueOf("00:00:00:00:00:03")));
+        Interface sw2Eth1 = new Interface(SW2_ETH1,
+                Sets.newHashSet(IpPrefix.valueOf("192.168.20.101/24")),
+                MacAddress.valueOf("00:00:00:00:00:02"));
 
-        return configuredInterfaces;
+        expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
+        interfaces.add(sw2Eth1);
+
+        Interface sw3Eth1 = new Interface(SW3_ETH1,
+                Sets.newHashSet(IpPrefix.valueOf("192.168.30.101/24")),
+                MacAddress.valueOf("00:00:00:00:00:03"));
+
+        expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
+        interfaces.add(sw3Eth1);
+
+        expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
+
+        replay(interfaceService);
+    }
+
+    /**
+     * Sets up the host service with details of some hosts.
+     */
+    private void setUpHostService() {
+        hostService = createMock(HostService.class);
+
+        hostService.addListener(anyObject(HostListener.class));
+        expectLastCall().anyTimes();
+
+        IpPrefix host1Address = IpPrefix.valueOf("192.168.10.1/32");
+        Host host1 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+                MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
+                new HostLocation(SW1_ETH1, 1),
+                        Sets.newHashSet(host1Address));
+
+        expect(hostService.getHostsByIp(host1Address))
+                .andReturn(Sets.newHashSet(host1)).anyTimes();
+        hostService.startMonitoringIp(host1Address.toIpAddress());
+        expectLastCall().anyTimes();
+
+
+        IpPrefix host2Address = IpPrefix.valueOf("192.168.20.1/32");
+        Host host2 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+                MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
+                new HostLocation(SW2_ETH1, 1),
+                        Sets.newHashSet(host2Address));
+
+        expect(hostService.getHostsByIp(host2Address))
+                .andReturn(Sets.newHashSet(host2)).anyTimes();
+        hostService.startMonitoringIp(host2Address.toIpAddress());
+        expectLastCall().anyTimes();
+
+
+        replay(hostService);
     }
 
     /**
@@ -200,7 +199,6 @@
      */
     @Test
     public void testProcessRouteAdd() throws TestUtilsException {
-
         // Construct a route entry
         RouteEntry routeEntry = new RouteEntry(
                 IpPrefix.valueOf("1.1.1.0/24"),
@@ -217,36 +215,13 @@
         treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
 
         Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
-        ingressPoints.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000002"),
-                PortNumber.portNumber("1")));
-        ingressPoints.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000003"),
-                PortNumber.portNumber("1")));
-
-        ConnectPoint egressPoint = new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000001"),
-                PortNumber.portNumber("1"));
+        ingressPoints.add(SW2_ETH1);
+        ingressPoints.add(SW3_ETH1);
 
         MultiPointToSinglePointIntent intent =
                 new MultiPointToSinglePointIntent(APPID,
                         selectorBuilder.build(), treatmentBuilder.build(),
-                        ingressPoints, egressPoint);
-
-        // Reset host service
-        reset(hostService);
-        Set<Host> hosts = new HashSet<Host>(1);
-        Set<IpPrefix> ipPrefixes = new HashSet<IpPrefix>();
-        ipPrefixes.add(IpPrefix.valueOf("192.168.10.1/32"));
-        hosts.add(new DefaultHost(ProviderId.NONE, HostId.NONE,
-                MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
-                new HostLocation(
-                        DeviceId.deviceId("of:0000000000000001"),
-                        PortNumber.portNumber(1), 1),
-                        ipPrefixes));
-        expect(hostService.getHostsByIp(
-                IpPrefix.valueOf("192.168.10.1/32"))).andReturn(hosts);
-        replay(hostService);
+                        ingressPoints, SW1_ETH1);
 
         // Set up test expectation
         reset(intentService);
@@ -274,7 +249,6 @@
      */
     @Test
     public void testRouteUpdate() throws TestUtilsException {
-
         // Firstly add a route
         testProcessRouteAdd();
 
@@ -293,22 +267,14 @@
                 DefaultTrafficTreatment.builder();
         treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
 
-        ConnectPoint egressPoint = new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000001"),
-                PortNumber.portNumber("1"));
-
         Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
-        ingressPoints.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000002"),
-                PortNumber.portNumber("1")));
-        ingressPoints.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000003"),
-                PortNumber.portNumber("1")));
+        ingressPoints.add(SW2_ETH1);
+        ingressPoints.add(SW3_ETH1);
 
         MultiPointToSinglePointIntent intent =
                 new MultiPointToSinglePointIntent(APPID,
                         selectorBuilder.build(), treatmentBuilder.build(),
-                        ingressPoints, egressPoint);
+                        ingressPoints, SW1_ETH1);
 
         // Start to construct a new route entry and new intent
         RouteEntry routeEntryUpdate = new RouteEntry(
@@ -325,38 +291,16 @@
                 DefaultTrafficTreatment.builder();
         treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
 
-        ConnectPoint egressPointNew = new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000002"),
-                PortNumber.portNumber("1"));
 
         Set<ConnectPoint> ingressPointsNew = new HashSet<ConnectPoint>();
-        ingressPointsNew.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000001"),
-                PortNumber.portNumber("1")));
-        ingressPointsNew.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000003"),
-                PortNumber.portNumber("1")));
+        ingressPointsNew.add(SW1_ETH1);
+        ingressPointsNew.add(SW3_ETH1);
 
         MultiPointToSinglePointIntent intentNew =
                 new MultiPointToSinglePointIntent(APPID,
                         selectorBuilderNew.build(),
                         treatmentBuilderNew.build(),
-                        ingressPointsNew, egressPointNew);
-
-        // Reset host service
-        reset(hostService);
-        Set<Host> hosts = new HashSet<Host>(1);
-        Set<IpPrefix> ipPrefixes = new HashSet<IpPrefix>();
-        ipPrefixes.add(IpPrefix.valueOf("192.168.20.1/32"));
-        hosts.add(new DefaultHost(ProviderId.NONE, HostId.NONE,
-                MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
-                new HostLocation(
-                        DeviceId.deviceId("of:0000000000000002"),
-                        PortNumber.portNumber(1), 1),
-                        ipPrefixes));
-        expect(hostService.getHostsByIp(
-                IpPrefix.valueOf("192.168.20.1/32"))).andReturn(hosts);
-        replay(hostService);
+                        ingressPointsNew, SW2_ETH1);
 
         // Set up test expectation
         reset(intentService);
@@ -383,7 +327,6 @@
      */
     @Test
     public void testProcessRouteDelete() throws TestUtilsException {
-
         // Firstly add a route
         testProcessRouteAdd();
 
@@ -402,22 +345,14 @@
                 DefaultTrafficTreatment.builder();
         treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
 
-        ConnectPoint egressPoint = new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000001"),
-                PortNumber.portNumber("1"));
-
         Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
-        ingressPoints.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000002"),
-                PortNumber.portNumber("1")));
-        ingressPoints.add(new ConnectPoint(
-                DeviceId.deviceId("of:0000000000000003"),
-                PortNumber.portNumber("1")));
+        ingressPoints.add(SW2_ETH1);
+        ingressPoints.add(SW3_ETH1);
 
         MultiPointToSinglePointIntent intent =
                 new MultiPointToSinglePointIntent(APPID,
                         selectorBuilder.build(), treatmentBuilder.build(),
-                        ingressPoints, egressPoint);
+                        ingressPoints, SW1_ETH1);
 
         // Set up expectation
         reset(intentService);
@@ -442,7 +377,6 @@
      */
     @Test
     public void testLocalRouteAdd() throws TestUtilsException {
-
         // Construct a route entry, the next hop is the local BGP speaker
         RouteEntry routeEntry = new RouteEntry(
                 IpPrefix.valueOf("1.1.1.0/24"), IpAddress.valueOf("0.0.0.0"));