Moved BGP code and Router code into their own bundle.

The main goal of this is to allow routing code to be used by multiple
applications.

Changes include:
 * Created an onos-app-routing bundle and moved BGP code and routing code
   into it.
 * Created an onos-app-routing-api bundle as a common API bundle between
   onos-app-routing and onos-app-sdnip, to prevent circular dependencies.
 * Moved API classes into onos-app-routing-api bundle.
 * Made Router and BgpSessionManager into OSGi components. This is not quite
   clean, because there is still a chain of start() method calls from SdnIp
   through to BgpSessionManager to preserve startup order. This should be
   revisted so components can be started using activate()
 * Created BgpService and RoutingService APIs to glue different components
   together.
 * Many unit test changes. A lot of the previous unit tests spanned the
   Router and IntentSynchronizer classes, but this is not possible any more
   since these classes are in different bundles. I had to rewrite some of
   these tests so that each unit test class only tests one real class. A
   nice side-effect is that the tests are now simpler because each test
   tests less functionality.
 * Removed SdnIp test seeing as it doesn't run automatically, was already
   broken and has been largely superseded by other unit tests and the nightly
   functional tests.

Change-Id: I70ecf5391aa353e99e7cdcf7ed38a530c87571bb
diff --git a/apps/sdnip/pom.xml b/apps/sdnip/pom.xml
index 920b5e5..925bc58 100644
--- a/apps/sdnip/pom.xml
+++ b/apps/sdnip/pom.xml
@@ -61,11 +61,6 @@
 
     <dependency>
       <groupId>org.onosproject</groupId>
-      <artifactId>onlab-thirdparty</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>org.onosproject</groupId>
       <artifactId>onlab-misc</artifactId>
     </dependency>
 
@@ -85,13 +80,13 @@
 
     <dependency>
       <groupId>org.onosproject</groupId>
-      <artifactId>onos-cli</artifactId>
+      <artifactId>onos-app-routing-api</artifactId>
       <version>${project.version}</version>
     </dependency>
 
     <dependency>
       <groupId>org.onosproject</groupId>
-      <artifactId>onos-core-dist</artifactId>
+      <artifactId>onos-cli</artifactId>
       <version>${project.version}</version>
     </dependency>
 
@@ -107,11 +102,6 @@
     </dependency>
 
     <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-    </dependency>
-
-    <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymock</artifactId>
       <scope>test</scope>
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibEntry.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibEntry.java
deleted file mode 100644
index 988b49a..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibEntry.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-
-/**
- * An entry in the Forwarding Information Base (FIB).
- */
-public class FibEntry {
-
-    private final IpPrefix prefix;
-    private final IpAddress nextHopIp;
-    private final MacAddress nextHopMac;
-
-    /**
-     * Creates a new FIB entry.
-     *
-     * @param prefix IP prefix of the FIB entry
-     * @param nextHopIp IP address of the next hop
-     * @param nextHopMac MAC address of the next hop
-     */
-    public FibEntry(IpPrefix prefix, IpAddress nextHopIp, MacAddress nextHopMac) {
-        this.prefix = prefix;
-        this.nextHopIp = nextHopIp;
-        this.nextHopMac = nextHopMac;
-    }
-
-    /**
-     * Returns the IP prefix of the FIB entry.
-     *
-     * @return the IP prefix
-     */
-    public IpPrefix prefix() {
-        return prefix;
-    }
-
-    /**
-     * Returns the IP address of the next hop.
-     *
-     * @return the IP address
-     */
-    public IpAddress nextHopIp() {
-        return nextHopIp;
-    }
-
-    /**
-     * Returns the MAC address of the next hop.
-     *
-     * @return the MAC address
-     */
-    public MacAddress nextHopMac() {
-        return nextHopMac;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibListener.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibListener.java
deleted file mode 100644
index 13674e3..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibListener.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import java.util.Collection;
-
-/**
- * A component that is able to process Forwarding Information Base (FIB) updates.
- */
-public interface FibListener {
-
-    /**
-     * Signals the FIB component of changes to the FIB.
-     *
-     * @param updates FIB updates of the UDPATE type
-     * @param withdraws FIB updates of the WITHDRAW type
-     */
-    // TODO this interface should use only one collection when we have the new
-    // intent key API
-    void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws);
-
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibUpdate.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/FibUpdate.java
deleted file mode 100644
index a3d8c3c..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/FibUpdate.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-/**
- * Represents a change to the Forwarding Information Base (FIB).
- */
-public class FibUpdate {
-
-    /**
-     * Specifies the type of the FIB update.
-     */
-    public enum Type {
-        /**
-         * The update contains a new or updated FIB entry for a prefix.
-         */
-        UPDATE,
-
-        /**
-         * The update signals that a prefix should be removed from the FIB.
-         */
-        DELETE
-    }
-
-    private final Type type;
-    private final FibEntry entry;
-
-    /**
-     * Creates a new FIB update.
-     *
-     * @param type type of the update
-     * @param entry FIB entry describing the update
-     */
-    public FibUpdate(Type type, FibEntry entry) {
-        this.type = type;
-        this.entry = entry;
-    }
-
-    /**
-     * Returns the type of the update.
-     *
-     * @return update type
-     */
-    public Type type() {
-        return type;
-    }
-
-    /**
-     * Returns the FIB entry which contains update information.
-     *
-     * @return the FIB entry
-     */
-    public FibEntry entry() {
-        return entry;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
index 9f3c872..698a2d6 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/IntentSynchronizer.java
@@ -36,6 +36,8 @@
 import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.routingapi.FibListener;
+import org.onosproject.routingapi.FibUpdate;
 import org.onosproject.sdnip.config.BgpPeer;
 import org.onosproject.sdnip.config.Interface;
 import org.onosproject.sdnip.config.SdnIpConfigurationService;
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
index 59ff346..93b442d 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
@@ -15,15 +15,11 @@
  */
 package org.onosproject.sdnip;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.IPv6;
-import org.onlab.packet.IpAddress;
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
@@ -32,7 +28,6 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.intent.PointToPointIntent;
-import org.onosproject.sdnip.bgp.BgpConstants;
 import org.onosproject.sdnip.config.BgpPeer;
 import org.onosproject.sdnip.config.BgpSpeaker;
 import org.onosproject.sdnip.config.Interface;
@@ -41,6 +36,10 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
 /**
  * Manages the connectivity requirements between peers.
  */
@@ -49,6 +48,8 @@
     private static final Logger log = LoggerFactory.getLogger(
             PeerConnectivityManager.class);
 
+    private static final short BGP_PORT = 179;
+
     private final IntentSynchronizer intentSynchronizer;
     private final SdnIpConfigurationService configService;
     private final InterfaceService interfaceService;
@@ -191,7 +192,7 @@
                                  bgpdAddress,
                                  bgpdPeerAddress,
                                  null,
-                                 (short) BgpConstants.BGP_PORT);
+                                 BGP_PORT);
 
         intents.add(new PointToPointIntent(appId, selector, treatment,
                                bgpdConnectPoint, bgpdPeerConnectPoint));
@@ -200,7 +201,7 @@
         selector = buildSelector(tcpProtocol,
                                  bgpdAddress,
                                  bgpdPeerAddress,
-                                 (short) BgpConstants.BGP_PORT,
+                                 BGP_PORT,
                                  null);
 
         intents.add(new PointToPointIntent(appId, selector, treatment,
@@ -211,7 +212,7 @@
                                  bgpdPeerAddress,
                                  bgpdAddress,
                                  null,
-                                 (short) BgpConstants.BGP_PORT);
+                                 BGP_PORT);
 
         intents.add(new PointToPointIntent(appId, selector, treatment,
                                bgpdPeerConnectPoint, bgpdConnectPoint));
@@ -220,7 +221,7 @@
         selector = buildSelector(tcpProtocol,
                                  bgpdPeerAddress,
                                  bgpdAddress,
-                                 (short) BgpConstants.BGP_PORT,
+                                 BGP_PORT,
                                  null);
 
         intents.add(new PointToPointIntent(appId, selector, treatment,
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteEntry.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteEntry.java
deleted file mode 100644
index 3cffb7e..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteEntry.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Objects;
-
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-
-import com.google.common.base.MoreObjects;
-
-/**
- * Represents a route entry for an IP prefix.
- */
-public class RouteEntry {
-    private final IpPrefix prefix;              // The IP prefix
-    private final IpAddress nextHop;            // Next-hop IP address
-
-    /**
-     * Class constructor.
-     *
-     * @param prefix the IP prefix of the route
-     * @param nextHop the next hop IP address for the route
-     */
-    public RouteEntry(IpPrefix prefix, IpAddress nextHop) {
-        this.prefix = checkNotNull(prefix);
-        this.nextHop = checkNotNull(nextHop);
-    }
-
-    /**
-     * Returns the IP version of the route.
-     *
-     * @return the IP version of the route
-     */
-    public IpAddress.Version version() {
-        return nextHop.version();
-    }
-
-    /**
-     * Returns the IP prefix of the route.
-     *
-     * @return the IP prefix of the route
-     */
-    public IpPrefix prefix() {
-        return prefix;
-    }
-
-    /**
-     * Returns the next hop IP address for the route.
-     *
-     * @return the next hop IP address for the route
-     */
-    public IpAddress nextHop() {
-        return nextHop;
-    }
-
-    /**
-     * Creates the binary string representation of an IP prefix.
-     * The prefix can be either IPv4 or IPv6.
-     * The string length is equal to the prefix length.
-     *
-     * @param ipPrefix the IP prefix to use
-     * @return the binary string representation
-     */
-    static String createBinaryString(IpPrefix ipPrefix) {
-        if (ipPrefix.prefixLength() == 0) {
-            return "";
-        }
-
-        byte[] octets = ipPrefix.address().toOctets();
-        StringBuilder result = new StringBuilder(ipPrefix.prefixLength());
-        for (int i = 0; i < ipPrefix.prefixLength(); i++) {
-            int byteOffset = i / Byte.SIZE;
-            int bitOffset = i % Byte.SIZE;
-            int mask = 1 << (Byte.SIZE - 1 - bitOffset);
-            byte value = octets[byteOffset];
-            boolean isSet = ((value & mask) != 0);
-            result.append(isSet ? "1" : "0");
-        }
-        return result.toString();
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (this == other) {
-            return true;
-        }
-
-        //
-        // NOTE: Subclasses are considered as change of identity, hence
-        // equals() will return false if the class type doesn't match.
-        //
-        if (other == null || getClass() != other.getClass()) {
-            return false;
-        }
-
-        RouteEntry otherRoute = (RouteEntry) other;
-        return Objects.equals(this.prefix, otherRoute.prefix) &&
-            Objects.equals(this.nextHop, otherRoute.nextHop);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(prefix, nextHop);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(getClass())
-            .add("prefix", prefix)
-            .add("nextHop", nextHop)
-            .toString();
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteListener.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteListener.java
deleted file mode 100644
index 2d9ddc9..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import java.util.Collection;
-
-/**
- * An interface to receive route updates from route providers.
- */
-public interface RouteListener {
-    /**
-     * Receives a route update from a route provider.
-     *
-     * @param routeUpdates the collection with updated route information
-     */
-    public void update(Collection<RouteUpdate> routeUpdates);
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteUpdate.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteUpdate.java
deleted file mode 100644
index f63f214..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/RouteUpdate.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Objects;
-
-import com.google.common.base.MoreObjects;
-
-/**
- * Represents a change in routing information.
- */
-public class RouteUpdate {
-    private final Type type;                    // The route update type
-    private final RouteEntry routeEntry;        // The updated route entry
-
-    /**
-     * Specifies the type of a route update.
-     * <p>
-     * Route updates can either provide updated information for a route, or
-     * withdraw a previously updated route.
-     * </p>
-     */
-    public enum Type {
-        /**
-         * The update contains updated route information for a route.
-         */
-        UPDATE,
-        /**
-         * The update withdraws the route, meaning any previous information is
-         * no longer valid.
-         */
-        DELETE
-    }
-
-    /**
-     * Class constructor.
-     *
-     * @param type the type of the route update
-     * @param routeEntry the route entry with the update
-     */
-    public RouteUpdate(Type type, RouteEntry routeEntry) {
-        this.type = type;
-        this.routeEntry = checkNotNull(routeEntry);
-    }
-
-    /**
-     * Returns the type of the route update.
-     *
-     * @return the type of the update
-     */
-    public Type type() {
-        return type;
-    }
-
-    /**
-     * Returns the route entry the route update is for.
-     *
-     * @return the route entry the route update is for
-     */
-    public RouteEntry routeEntry() {
-        return routeEntry;
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (other == this) {
-            return true;
-        }
-
-        if (!(other instanceof RouteUpdate)) {
-            return false;
-        }
-
-        RouteUpdate otherUpdate = (RouteUpdate) other;
-
-        return Objects.equals(this.type, otherUpdate.type) &&
-            Objects.equals(this.routeEntry, otherUpdate.routeEntry);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(type, routeEntry);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(getClass())
-            .add("type", type)
-            .add("routeEntry", routeEntry)
-            .toString();
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
deleted file mode 100644
index d19f298..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/Router.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.googlecode.concurrenttrees.common.KeyValuePair;
-import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
-import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
-import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onosproject.net.Host;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * This class processes route updates and maintains a Routing Information Base
- * (RIB). After route updates have been processed and next hops have been
- * resolved, FIB updates are sent to any listening FIB components.
- */
-public class Router implements RouteListener {
-
-    private static final Logger log = LoggerFactory.getLogger(Router.class);
-
-    // Route entries are stored in a radix tree.
-    // The key in this tree is the binary string of prefix of the route.
-    private InvertedRadixTree<RouteEntry> ribTable4;
-    private InvertedRadixTree<RouteEntry> ribTable6;
-
-    // Stores all incoming route updates in a queue.
-    private final BlockingQueue<Collection<RouteUpdate>> routeUpdatesQueue;
-
-    // Next-hop IP address to route entry mapping for next hops pending MAC resolution
-    private final SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp;
-
-    // The IPv4 address to MAC address mapping
-    private final Map<IpAddress, MacAddress> ip2Mac;
-
-    private final FibListener fibComponent;
-    private final HostService hostService;
-    private final ExecutorService bgpUpdatesExecutor;
-    private final HostListener hostListener;
-
-    /**
-     * Class constructor.
-     *
-     * @param fibComponent the intent synchronizer
-     * @param hostService       the host service
-     */
-    public Router(FibListener fibComponent, HostService hostService) {
-        // TODO move to a listener model for adding fib listeners
-        this.fibComponent = fibComponent;
-        this.hostService = hostService;
-
-        this.hostListener = new InternalHostListener();
-
-        ribTable4 = new ConcurrentInvertedRadixTree<>(
-                new DefaultByteArrayNodeFactory());
-        ribTable6 = new ConcurrentInvertedRadixTree<>(
-                new DefaultByteArrayNodeFactory());
-        routeUpdatesQueue = new LinkedBlockingQueue<>();
-        routesWaitingOnArp = Multimaps.synchronizedSetMultimap(
-                HashMultimap.<IpAddress, RouteEntry>create());
-        ip2Mac = new ConcurrentHashMap<>();
-
-        bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
-                new ThreadFactoryBuilder()
-                .setNameFormat("sdnip-bgp-updates-%d").build());
-    }
-
-    /**
-     * Starts the router.
-     */
-    public void start() {
-        this.hostService.addListener(hostListener);
-
-        bgpUpdatesExecutor.execute(new Runnable() {
-            @Override
-            public void run() {
-                doUpdatesThread();
-            }
-        });
-    }
-
-    /**
-     * Stops the router.
-     */
-    public void stop() {
-        this.hostService.removeListener(hostListener);
-
-        // Stop the thread(s)
-        bgpUpdatesExecutor.shutdownNow();
-
-        synchronized (this) {
-            // Cleanup all local state
-            ribTable4 = new ConcurrentInvertedRadixTree<>(
-                new DefaultByteArrayNodeFactory());
-            ribTable6 = new ConcurrentInvertedRadixTree<>(
-                new DefaultByteArrayNodeFactory());
-            routeUpdatesQueue.clear();
-            routesWaitingOnArp.clear();
-            ip2Mac.clear();
-        }
-    }
-
-    @Override
-    public void update(Collection<RouteUpdate> routeUpdates) {
-        try {
-            routeUpdatesQueue.put(routeUpdates);
-        } catch (InterruptedException e) {
-            log.debug("Interrupted while putting on routeUpdatesQueue", e);
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    /**
-     * Thread for handling route updates.
-     */
-    private void doUpdatesThread() {
-        boolean interrupted = false;
-        try {
-            while (!interrupted) {
-                try {
-                    Collection<RouteUpdate> routeUpdates =
-                        routeUpdatesQueue.take();
-                    processRouteUpdates(routeUpdates);
-                } catch (InterruptedException e) {
-                    log.debug("Interrupted while taking from updates queue", e);
-                    interrupted = true;
-                } catch (Exception e) {
-                    log.debug("exception", e);
-                }
-            }
-        } finally {
-            if (interrupted) {
-                Thread.currentThread().interrupt();
-            }
-        }
-    }
-
-    /**
-     * Gets all IPv4 routes from the RIB.
-     *
-     * @return all IPv4 routes from the RIB
-     */
-    public Collection<RouteEntry> getRoutes4() {
-        Iterator<KeyValuePair<RouteEntry>> it =
-            ribTable4.getKeyValuePairsForKeysStartingWith("").iterator();
-
-        List<RouteEntry> routes = new LinkedList<>();
-
-        while (it.hasNext()) {
-            KeyValuePair<RouteEntry> entry = it.next();
-            routes.add(entry.getValue());
-        }
-
-        return routes;
-    }
-
-    /**
-     * Gets all IPv6 routes from the RIB.
-     *
-     * @return all IPv6 routes from the RIB
-     */
-    public Collection<RouteEntry> getRoutes6() {
-        Iterator<KeyValuePair<RouteEntry>> it =
-            ribTable6.getKeyValuePairsForKeysStartingWith("").iterator();
-
-        List<RouteEntry> routes = new LinkedList<>();
-
-        while (it.hasNext()) {
-            KeyValuePair<RouteEntry> entry = it.next();
-            routes.add(entry.getValue());
-        }
-
-        return routes;
-    }
-
-    /**
-     * Finds a route in the RIB for a prefix. The prefix can be either IPv4 or
-     * IPv6.
-     *
-     * @param prefix the prefix to use
-     * @return the route if found, otherwise null
-     */
-    RouteEntry findRibRoute(IpPrefix prefix) {
-        String binaryString = RouteEntry.createBinaryString(prefix);
-        if (prefix.version() == Ip4Address.VERSION) {
-            // IPv4
-            return ribTable4.getValueForExactKey(binaryString);
-        }
-        // IPv6
-        return ribTable6.getValueForExactKey(binaryString);
-    }
-
-    /**
-     * Adds a route to the RIB. The route can be either IPv4 or IPv6.
-     *
-     * @param routeEntry the route entry to use
-     */
-    void addRibRoute(RouteEntry routeEntry) {
-        if (routeEntry.prefix().version() == Ip4Address.VERSION) {
-            // IPv4
-            ribTable4.put(RouteEntry.createBinaryString(routeEntry.prefix()),
-                          routeEntry);
-        } else {
-            // IPv6
-            ribTable6.put(RouteEntry.createBinaryString(routeEntry.prefix()),
-                          routeEntry);
-        }
-    }
-
-    /**
-     * Removes a route for a prefix from the RIB. The prefix can be either IPv4
-     * or IPv6.
-     *
-     * @param prefix the prefix to use
-     * @return true if the route was found and removed, otherwise false
-     */
-    boolean removeRibRoute(IpPrefix prefix) {
-        if (prefix.version() == Ip4Address.VERSION) {
-            // IPv4
-            return ribTable4.remove(RouteEntry.createBinaryString(prefix));
-        }
-        // IPv6
-        return ribTable6.remove(RouteEntry.createBinaryString(prefix));
-    }
-
-    /**
-     * Processes route updates.
-     *
-     * @param routeUpdates the route updates to process
-     */
-    void processRouteUpdates(Collection<RouteUpdate> routeUpdates) {
-        synchronized (this) {
-            Collection<IpPrefix> withdrawPrefixes = new LinkedList<>();
-            Collection<FibUpdate> fibUpdates = new LinkedList<>();
-            Collection<FibUpdate> fibWithdraws = new LinkedList<>();
-
-            for (RouteUpdate update : routeUpdates) {
-                switch (update.type()) {
-                case UPDATE:
-                    FibEntry fib = processRouteAdd(update.routeEntry(),
-                                                    withdrawPrefixes);
-                    if (fib != null) {
-                        fibUpdates.add(new FibUpdate(FibUpdate.Type.UPDATE, fib));
-                    }
-
-                    break;
-                case DELETE:
-                    processRouteDelete(update.routeEntry(), withdrawPrefixes);
-
-                    break;
-                default:
-                    log.error("Unknown update Type: {}", update.type());
-                    break;
-                }
-            }
-
-            withdrawPrefixes.forEach(p -> fibWithdraws.add(new FibUpdate(
-                    FibUpdate.Type.DELETE, new FibEntry(p, null, null))));
-
-            fibComponent.update(fibUpdates, fibWithdraws);
-        }
-    }
-
-    /**
-     * Processes adding a route entry.
-     * <p>
-     * The route entry is added to the radix tree. If there was an existing
-     * next hop for this prefix, but the next hop was different, then the
-     * old route entry is deleted.
-     * </p>
-     * <p>
-     * NOTE: Currently, we don't handle routes if the next hop is within the
-     * SDN domain.
-     * </p>
-     *
-     * @param routeEntry the route entry to add
-     * @param withdrawPrefixes the collection of accumulated prefixes whose
-     * intents will be withdrawn
-     * @return the corresponding FIB entry change, or null
-     */
-    private FibEntry processRouteAdd(
-                RouteEntry routeEntry,
-                Collection<IpPrefix> withdrawPrefixes) {
-        log.debug("Processing route add: {}", routeEntry);
-
-        // Find the old next-hop if we are updating an old route entry
-        IpAddress oldNextHop = null;
-        RouteEntry oldRouteEntry = findRibRoute(routeEntry.prefix());
-        if (oldRouteEntry != null) {
-            oldNextHop = oldRouteEntry.nextHop();
-        }
-
-        // Add the new route to the RIB
-        addRibRoute(routeEntry);
-
-        if (oldNextHop != null) {
-            if (oldNextHop.equals(routeEntry.nextHop())) {
-                return null;            // No change
-            }
-            //
-            // Update an existing nexthop for the prefix.
-            // We need to remove the old flows for this prefix from the
-            // switches before the new flows are added.
-            //
-            withdrawPrefixes.add(routeEntry.prefix());
-        }
-
-        if (routeEntry.nextHop().isZero()) {
-            // Route originated by SDN domain
-            // We don't handle these at the moment
-            log.debug("Own route {} to {}",
-                      routeEntry.prefix(), routeEntry.nextHop());
-            return null;
-        }
-
-        //
-        // Find the MAC address of next hop router for this route entry.
-        // If the MAC address can not be found in ARP cache, then this prefix
-        // will be put in routesWaitingOnArp queue. Otherwise, generate
-        // a new route intent.
-        //
-
-        // Monitor the IP address for updates of the MAC address
-        hostService.startMonitoringIp(routeEntry.nextHop());
-
-        // Check if we know the MAC address of the next hop
-        MacAddress nextHopMacAddress = ip2Mac.get(routeEntry.nextHop());
-        if (nextHopMacAddress == null) {
-            Set<Host> hosts = hostService.getHostsByIp(routeEntry.nextHop());
-            if (!hosts.isEmpty()) {
-                nextHopMacAddress = hosts.iterator().next().mac();
-            }
-            if (nextHopMacAddress != null) {
-                ip2Mac.put(routeEntry.nextHop(), nextHopMacAddress);
-            }
-        }
-        if (nextHopMacAddress == null) {
-            routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry);
-            return null;
-        }
-        return new FibEntry(routeEntry.prefix(), routeEntry.nextHop(),
-                             nextHopMacAddress);
-    }
-
-    /**
-     * Processes the deletion of a route entry.
-     * <p>
-     * The prefix for the routing entry is removed from radix tree.
-     * If the operation is successful, the prefix is added to the collection
-     * of prefixes whose intents that will be withdrawn.
-     * </p>
-     *
-     * @param routeEntry the route entry to delete
-     * @param withdrawPrefixes the collection of accumulated prefixes whose
-     * intents will be withdrawn
-     */
-    private void processRouteDelete(RouteEntry routeEntry,
-                                    Collection<IpPrefix> withdrawPrefixes) {
-        log.debug("Processing route delete: {}", routeEntry);
-        boolean isRemoved = removeRibRoute(routeEntry.prefix());
-
-        if (isRemoved) {
-            //
-            // Only withdraw intents if an entry was actually removed from the
-            // tree. If no entry was removed, the <prefix, nexthop> wasn't
-            // there so it's probably already been removed and we don't
-            // need to do anything.
-            //
-            withdrawPrefixes.add(routeEntry.prefix());
-        }
-
-        routesWaitingOnArp.remove(routeEntry.nextHop(), routeEntry);
-    }
-
-    /**
-     * 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 the IP address that an event was received for
-     * @param macAddress the most recently known MAC address for the IP address
-     */
-    private void updateMac(IpAddress ipAddress, MacAddress macAddress) {
-        log.debug("Received updated MAC info: {} => {}", ipAddress,
-                  macAddress);
-
-        //
-        // We synchronize on "this" to prevent changes to the Radix tree
-        // while we're pushing intents. If the tree changes, the
-        // tree and the intents could get out of sync.
-        //
-        synchronized (this) {
-            Collection<FibUpdate> submitFibEntries = new LinkedList<>();
-
-            Set<RouteEntry> routesToPush =
-                routesWaitingOnArp.removeAll(ipAddress);
-
-            for (RouteEntry routeEntry : routesToPush) {
-                // These will always be adds
-                RouteEntry foundRouteEntry = findRibRoute(routeEntry.prefix());
-                if (foundRouteEntry != null &&
-                    foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
-                    // We only push FIB updates if the prefix is still in the
-                    // radix tree and the next hop is the same as our entry.
-                    // The prefix could have been removed while we were waiting
-                    // for the ARP, or the next hop could have changed.
-                    submitFibEntries.add(new FibUpdate(FibUpdate.Type.UPDATE,
-                                                       new FibEntry(routeEntry.prefix(),
-                                                       ipAddress, macAddress)));
-                } else {
-                    log.debug("{} has been revoked before the MAC was resolved",
-                              routeEntry);
-                }
-            }
-
-            if (!submitFibEntries.isEmpty()) {
-                fibComponent.update(submitFibEntries, Collections.emptyList());
-            }
-
-            ip2Mac.put(ipAddress, macAddress);
-        }
-    }
-
-    /**
-     * Listener for host events.
-     */
-    class InternalHostListener implements HostListener {
-        @Override
-        public void event(HostEvent event) {
-            log.debug("Received HostEvent {}", event);
-
-            Host host = event.subject();
-            switch (event.type()) {
-            case HOST_ADDED:
-                // FALLTHROUGH
-            case HOST_UPDATED:
-                for (IpAddress ipAddress : host.ipAddresses()) {
-                    updateMac(ipAddress, host.mac());
-                }
-                break;
-            case HOST_REMOVED:
-                for (IpAddress ipAddress : host.ipAddresses()) {
-                    ip2Mac.remove(ipAddress);
-                }
-                break;
-            default:
-                break;
-            }
-        }
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
index 0b921ff..b375852 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIp.java
@@ -32,14 +32,11 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.intent.IntentService;
-import org.onosproject.sdnip.bgp.BgpRouteEntry;
-import org.onosproject.sdnip.bgp.BgpSession;
-import org.onosproject.sdnip.bgp.BgpSessionManager;
+import org.onosproject.routingapi.RoutingService;
 import org.onosproject.sdnip.config.SdnIpConfigurationReader;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
-import java.util.Collection;
 import java.util.Dictionary;
 
 import static org.slf4j.LoggerFactory.getLogger;
@@ -69,8 +66,11 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LeadershipService leadershipService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected RoutingService routingService;
+
     //
-    // NOTE: Unused reference - needed to guarentee that the
+    // NOTE: Unused reference - needed to guarantee that the
     // NetworkConfigReader component is activated and the network configuration
     // is read.
     //
@@ -83,8 +83,7 @@
     private IntentSynchronizer intentSynchronizer;
     private SdnIpConfigurationReader config;
     private PeerConnectivityManager peerConnectivity;
-    private Router router;
-    private BgpSessionManager bgpSessionManager;
+
     private LeadershipEventListener leadershipEventListener =
         new InnerLeadershipEventListener();
     private ApplicationId appId;
@@ -114,23 +113,18 @@
                                                        interfaceService);
         peerConnectivity.start();
 
-        router = new Router(intentSynchronizer, hostService);
-        router.start();
+        routingService.start(intentSynchronizer);
 
         leadershipService.addListener(leadershipEventListener);
         leadershipService.runForLeadership(appId.name());
 
         log.info("Starting BGP with port {}", bgpPort);
-
-        bgpSessionManager = new BgpSessionManager(router);
-        bgpSessionManager.start(bgpPort);
+        // TODO feed port information through to the BgpService
     }
 
     @Deactivate
     protected void deactivate() {
-
-        bgpSessionManager.stop();
-        router.stop();
+        routingService.stop();
         peerConnectivity.stop();
         intentSynchronizer.stop();
 
@@ -168,31 +162,6 @@
     }
 
     @Override
-    public Collection<BgpSession> getBgpSessions() {
-        return bgpSessionManager.getBgpSessions();
-    }
-
-    @Override
-    public Collection<BgpRouteEntry> getBgpRoutes4() {
-        return bgpSessionManager.getBgpRoutes4();
-    }
-
-    @Override
-    public Collection<BgpRouteEntry> getBgpRoutes6() {
-        return bgpSessionManager.getBgpRoutes6();
-    }
-
-    @Override
-    public Collection<RouteEntry> getRoutes4() {
-        return router.getRoutes4();
-    }
-
-    @Override
-    public Collection<RouteEntry> getRoutes6() {
-        return router.getRoutes6();
-    }
-
-    @Override
     public void modifyPrimary(boolean isPrimary) {
         intentSynchronizer.leaderChanged(isPrimary);
     }
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpService.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpService.java
index aa71f02..dbb0d88 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpService.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/SdnIpService.java
@@ -15,49 +15,10 @@
  */
 package org.onosproject.sdnip;
 
-import java.util.Collection;
-
-import org.onosproject.sdnip.bgp.BgpRouteEntry;
-import org.onosproject.sdnip.bgp.BgpSession;
-
 /**
  * Service interface exported by SDN-IP.
  */
 public interface SdnIpService {
-    /**
-     * Gets the BGP sessions.
-     *
-     * @return the BGP sessions
-     */
-    public Collection<BgpSession> getBgpSessions();
-
-    /**
-     * Gets the selected IPv4 BGP routes among all BGP sessions.
-     *
-     * @return the selected IPv4 BGP routes among all BGP sessions
-     */
-    public Collection<BgpRouteEntry> getBgpRoutes4();
-
-    /**
-     * Gets the selected IPv6 BGP routes among all BGP sessions.
-     *
-     * @return the selected IPv6 BGP routes among all BGP sessions
-     */
-    public Collection<BgpRouteEntry> getBgpRoutes6();
-
-    /**
-     * Gets all IPv4 routes known to SDN-IP.
-     *
-     * @return the SDN-IP IPv4 routes
-     */
-    public Collection<RouteEntry> getRoutes4();
-
-    /**
-     * Gets all IPv6 routes known to SDN-IP.
-     *
-     * @return the SDN-IP IPv6 routes
-     */
-    public Collection<RouteEntry> getRoutes6();
 
     /**
      * Changes whether this SDN-IP instance is the primary or not based on the
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpConstants.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpConstants.java
deleted file mode 100644
index b009c17..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpConstants.java
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-/**
- * BGP related constants.
- */
-public final class BgpConstants {
-    /**
-     * Default constructor.
-     * <p>
-     * The constructor is private to prevent creating an instance of
-     * this utility class.
-     */
-    private BgpConstants() {
-    }
-
-    /** BGP port number (RFC 4271). */
-    public static final int BGP_PORT = 179;
-
-    /** BGP version. */
-    public static final int BGP_VERSION = 4;
-
-    /** BGP OPEN message type. */
-    public static final int BGP_TYPE_OPEN = 1;
-
-    /** BGP UPDATE message type. */
-    public static final int BGP_TYPE_UPDATE = 2;
-
-    /** BGP NOTIFICATION message type. */
-    public static final int BGP_TYPE_NOTIFICATION = 3;
-
-    /** BGP KEEPALIVE message type. */
-    public static final int BGP_TYPE_KEEPALIVE = 4;
-
-    /** BGP Header Marker field length. */
-    public static final int BGP_HEADER_MARKER_LENGTH = 16;
-
-    /** BGP Header length. */
-    public static final int BGP_HEADER_LENGTH = 19;
-
-    /** BGP message maximum length. */
-    public static final int BGP_MESSAGE_MAX_LENGTH = 4096;
-
-    /** BGP OPEN message minimum length (BGP Header included). */
-    public static final int BGP_OPEN_MIN_LENGTH = 29;
-
-    /** BGP UPDATE message minimum length (BGP Header included). */
-    public static final int BGP_UPDATE_MIN_LENGTH = 23;
-
-    /** BGP NOTIFICATION message minimum length (BGP Header included). */
-    public static final int BGP_NOTIFICATION_MIN_LENGTH = 21;
-
-    /** BGP KEEPALIVE message expected length (BGP Header included). */
-    public static final int BGP_KEEPALIVE_EXPECTED_LENGTH = 19;
-
-    /** BGP KEEPALIVE messages transmitted per Hold interval. */
-    public static final int BGP_KEEPALIVE_PER_HOLD_INTERVAL = 3;
-
-    /** BGP KEEPALIVE messages minimum Holdtime (in seconds). */
-    public static final int BGP_KEEPALIVE_MIN_HOLDTIME = 3;
-
-    /** BGP KEEPALIVE messages minimum transmission interval (in seconds). */
-    public static final int BGP_KEEPALIVE_MIN_INTERVAL = 1;
-
-    /** BGP AS 0 (zero) value. See draft-ietf-idr-as0-06.txt Internet Draft. */
-    public static final long BGP_AS_0 = 0;
-
-    /**
-     * BGP OPEN related constants.
-     */
-    public static final class Open {
-        /**
-         * Default constructor.
-         * <p>
-         * The constructor is private to prevent creating an instance of
-         * this utility class.
-         */
-        private Open() {
-        }
-
-        /**
-         * BGP OPEN: Optional Parameters related constants.
-         */
-        public static final class OptionalParameters {
-        }
-
-        /**
-         * BGP OPEN: Capabilities related constants (RFC 5492).
-         */
-        public static final class Capabilities {
-            /** BGP OPEN Optional Parameter Type: Capabilities. */
-            public static final int TYPE = 2;
-
-            /** BGP OPEN Optional Parameter minimum length. */
-            public static final int MIN_LENGTH = 2;
-
-            /**
-             * BGP OPEN: Multiprotocol Extensions Capabilities (RFC 4760).
-             */
-            public static final class MultiprotocolExtensions {
-                /** BGP OPEN Multiprotocol Extensions code. */
-                public static final int CODE = 1;
-
-                /** BGP OPEN Multiprotocol Extensions length. */
-                public static final int LENGTH = 4;
-
-                /** BGP OPEN Multiprotocol Extensions AFI: IPv4. */
-                public static final int AFI_IPV4 = 1;
-
-                /** BGP OPEN Multiprotocol Extensions AFI: IPv6. */
-                public static final int AFI_IPV6 = 2;
-
-                /** BGP OPEN Multiprotocol Extensions SAFI: unicast. */
-                public static final int SAFI_UNICAST = 1;
-
-                /** BGP OPEN Multiprotocol Extensions SAFI: multicast. */
-                public static final int SAFI_MULTICAST = 2;
-            }
-
-            /**
-             * BGP OPEN: Support for 4-octet AS Number Capability (RFC 6793).
-             */
-            public static final class As4Octet {
-                /** BGP OPEN Support for 4-octet AS Number Capability code. */
-                public static final int CODE = 65;
-
-                /** BGP OPEN 4-octet AS Number Capability length. */
-                public static final int LENGTH = 4;
-            }
-        }
-    }
-
-    /**
-     * BGP UPDATE related constants.
-     */
-    public static final class Update {
-        /**
-         * Default constructor.
-         * <p>
-         * The constructor is private to prevent creating an instance of
-         * this utility class.
-         */
-        private Update() {
-        }
-
-        /**
-         * BGP UPDATE: ORIGIN related constants.
-         */
-        public static final class Origin {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private Origin() {
-            }
-
-            /** BGP UPDATE Attributes Type Code ORIGIN. */
-            public static final int TYPE = 1;
-
-            /** BGP UPDATE Attributes Type Code ORIGIN length. */
-            public static final int LENGTH = 1;
-
-            /** BGP UPDATE ORIGIN: IGP. */
-            public static final int IGP = 0;
-
-            /** BGP UPDATE ORIGIN: EGP. */
-            public static final int EGP = 1;
-
-            /** BGP UPDATE ORIGIN: INCOMPLETE. */
-            public static final int INCOMPLETE = 2;
-
-            /**
-             * Gets the BGP UPDATE origin type as a string.
-             *
-             * @param type the BGP UPDATE origin type
-             * @return the BGP UPDATE origin type as a string
-             */
-            public static String typeToString(int type) {
-                String typeString = "UNKNOWN";
-
-                switch (type) {
-                case IGP:
-                    typeString = "IGP";
-                    break;
-                case EGP:
-                    typeString = "EGP";
-                    break;
-                case INCOMPLETE:
-                    typeString = "INCOMPLETE";
-                    break;
-                default:
-                    break;
-                }
-                return typeString;
-            }
-        }
-
-        /**
-         * BGP UPDATE: AS_PATH related constants.
-         */
-        public static final class AsPath {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private AsPath() {
-            }
-
-            /** BGP UPDATE Attributes Type Code AS_PATH. */
-            public static final int TYPE = 2;
-
-            /** BGP AS length. */
-            public static final int AS_LENGTH = 2;
-
-            /** BGP 4 Octet AS length (RFC 6793). */
-            public static final int AS_4OCTET_LENGTH = 4;
-
-            /** BGP UPDATE AS_PATH Type: AS_SET. */
-            public static final int AS_SET = 1;
-
-            /** BGP UPDATE AS_PATH Type: AS_SEQUENCE. */
-            public static final int AS_SEQUENCE = 2;
-
-            /** BGP UPDATE AS_PATH Type: AS_CONFED_SEQUENCE. */
-            public static final int AS_CONFED_SEQUENCE = 3;
-
-            /** BGP UPDATE AS_PATH Type: AS_CONFED_SET. */
-            public static final int AS_CONFED_SET = 4;
-
-            /**
-             * Gets the BGP AS_PATH type as a string.
-             *
-             * @param type the BGP AS_PATH type
-             * @return the BGP AS_PATH type as a string
-             */
-            public static String typeToString(int type) {
-                String typeString = "UNKNOWN";
-
-                switch (type) {
-                case AS_SET:
-                    typeString = "AS_SET";
-                    break;
-                case AS_SEQUENCE:
-                    typeString = "AS_SEQUENCE";
-                    break;
-                case AS_CONFED_SEQUENCE:
-                    typeString = "AS_CONFED_SEQUENCE";
-                    break;
-                case AS_CONFED_SET:
-                    typeString = "AS_CONFED_SET";
-                    break;
-                default:
-                    break;
-                }
-                return typeString;
-            }
-        }
-
-        /**
-         * BGP UPDATE: NEXT_HOP related constants.
-         */
-        public static final class NextHop {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private NextHop() {
-            }
-
-            /** BGP UPDATE Attributes Type Code NEXT_HOP. */
-            public static final int TYPE = 3;
-
-            /** BGP UPDATE Attributes Type Code NEXT_HOP length. */
-            public static final int LENGTH = 4;
-        }
-
-        /**
-         * BGP UPDATE: MULTI_EXIT_DISC related constants.
-         */
-        public static final class MultiExitDisc {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private MultiExitDisc() {
-            }
-
-            /** BGP UPDATE Attributes Type Code MULTI_EXIT_DISC. */
-            public static final int TYPE = 4;
-
-            /** BGP UPDATE Attributes Type Code MULTI_EXIT_DISC length. */
-            public static final int LENGTH = 4;
-
-            /** BGP UPDATE Attributes lowest MULTI_EXIT_DISC value. */
-            public static final int LOWEST_MULTI_EXIT_DISC = 0;
-        }
-
-        /**
-         * BGP UPDATE: LOCAL_PREF related constants.
-         */
-        public static final class LocalPref {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private LocalPref() {
-            }
-
-            /** BGP UPDATE Attributes Type Code LOCAL_PREF. */
-            public static final int TYPE = 5;
-
-            /** BGP UPDATE Attributes Type Code LOCAL_PREF length. */
-            public static final int LENGTH = 4;
-        }
-
-        /**
-         * BGP UPDATE: ATOMIC_AGGREGATE related constants.
-         */
-        public static final class AtomicAggregate {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private AtomicAggregate() {
-            }
-
-            /** BGP UPDATE Attributes Type Code ATOMIC_AGGREGATE. */
-            public static final int TYPE = 6;
-
-            /** BGP UPDATE Attributes Type Code ATOMIC_AGGREGATE length. */
-            public static final int LENGTH = 0;
-        }
-
-        /**
-         * BGP UPDATE: AGGREGATOR related constants.
-         */
-        public static final class Aggregator {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private Aggregator() {
-            }
-
-            /** BGP UPDATE Attributes Type Code AGGREGATOR. */
-            public static final int TYPE = 7;
-
-            /** BGP UPDATE Attributes Type Code AGGREGATOR length. */
-            public static final int LENGTH = 6;
-        }
-
-        /**
-         * BGP UPDATE: MP_REACH_NLRI related constants.
-         */
-        public static final class MpReachNlri {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private MpReachNlri() {
-            }
-
-            /** BGP UPDATE Attributes Type Code MP_REACH_NLRI. */
-            public static final int TYPE = 14;
-
-            /** BGP UPDATE Attributes Type Code MP_REACH_NLRI min length. */
-            public static final int MIN_LENGTH = 5;
-        }
-
-        /**
-         * BGP UPDATE: MP_UNREACH_NLRI related constants.
-         */
-        public static final class MpUnreachNlri {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private MpUnreachNlri() {
-            }
-
-            /** BGP UPDATE Attributes Type Code MP_UNREACH_NLRI. */
-            public static final int TYPE = 15;
-
-            /** BGP UPDATE Attributes Type Code MP_UNREACH_NLRI min length. */
-            public static final int MIN_LENGTH = 3;
-        }
-    }
-
-    /**
-     * BGP NOTIFICATION related constants.
-     */
-    public static final class Notifications {
-        /**
-         * Default constructor.
-         * <p>
-         * The constructor is private to prevent creating an instance of
-         * this utility class.
-         */
-        private Notifications() {
-        }
-
-        /**
-         * BGP NOTIFICATION: Message Header Error constants.
-         */
-        public static final class MessageHeaderError {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private MessageHeaderError() {
-            }
-
-            /** Message Header Error code. */
-            public static final int ERROR_CODE = 1;
-
-            /** Message Header Error subcode: Connection Not Synchronized. */
-            public static final int CONNECTION_NOT_SYNCHRONIZED = 1;
-
-            /** Message Header Error subcode: Bad Message Length. */
-            public static final int BAD_MESSAGE_LENGTH = 2;
-
-            /** Message Header Error subcode: Bad Message Type. */
-            public static final int BAD_MESSAGE_TYPE = 3;
-        }
-
-        /**
-         * BGP NOTIFICATION: OPEN Message Error constants.
-         */
-        public static final class OpenMessageError {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private OpenMessageError() {
-            }
-
-            /** OPEN Message Error code. */
-            public static final int ERROR_CODE = 2;
-
-            /** OPEN Message Error subcode: Unsupported Version Number. */
-            public static final int UNSUPPORTED_VERSION_NUMBER = 1;
-
-            /** OPEN Message Error subcode: Bad PEER AS. */
-            public static final int BAD_PEER_AS = 2;
-
-            /** OPEN Message Error subcode: Unacceptable Hold Time. */
-            public static final int UNACCEPTABLE_HOLD_TIME = 6;
-        }
-
-        /**
-         * BGP NOTIFICATION: UPDATE Message Error constants.
-         */
-        public static final class UpdateMessageError {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private UpdateMessageError() {
-            }
-
-            /** UPDATE Message Error code. */
-            public static final int ERROR_CODE = 3;
-
-            /** UPDATE Message Error subcode: Malformed Attribute List. */
-            public static final int MALFORMED_ATTRIBUTE_LIST = 1;
-
-            /** UPDATE Message Error subcode: Unrecognized Well-known Attribute. */
-            public static final int UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE = 2;
-
-            /** UPDATE Message Error subcode: Missing Well-known Attribute. */
-            public static final int MISSING_WELL_KNOWN_ATTRIBUTE = 3;
-
-           /** UPDATE Message Error subcode: Attribute Flags Error. */
-            public static final int ATTRIBUTE_FLAGS_ERROR = 4;
-
-            /** UPDATE Message Error subcode: Attribute Length Error. */
-            public static final int ATTRIBUTE_LENGTH_ERROR = 5;
-
-            /** UPDATE Message Error subcode: Invalid ORIGIN Attribute. */
-            public static final int INVALID_ORIGIN_ATTRIBUTE = 6;
-
-            /** UPDATE Message Error subcode: Invalid NEXT_HOP Attribute. */
-            public static final int INVALID_NEXT_HOP_ATTRIBUTE = 8;
-
-            /** UPDATE Message Error subcode: Optional Attribute Error. Unused. */
-            public static final int OPTIONAL_ATTRIBUTE_ERROR = 9;
-
-            /** UPDATE Message Error subcode: Invalid Network Field. */
-            public static final int INVALID_NETWORK_FIELD = 10;
-
-            /** UPDATE Message Error subcode: Malformed AS_PATH. */
-            public static final int MALFORMED_AS_PATH = 11;
-        }
-
-        /**
-         * BGP NOTIFICATION: Hold Timer Expired constants.
-         */
-        public static final class HoldTimerExpired {
-            /**
-             * Default constructor.
-             * <p>
-             * The constructor is private to prevent creating an instance of
-             * this utility class.
-             */
-            private HoldTimerExpired() {
-            }
-
-            /** Hold Timer Expired code. */
-            public static final int ERROR_CODE = 4;
-        }
-
-        /** BGP NOTIFICATION message Error subcode: Unspecific. */
-        public static final int ERROR_SUBCODE_UNSPECIFIC = 0;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpFrameDecoder.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpFrameDecoder.java
deleted file mode 100644
index 4c9b56e..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpFrameDecoder.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.frame.FrameDecoder;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class for handling the decoding of the BGP messages.
- */
-class BgpFrameDecoder extends FrameDecoder {
-    private static final Logger log =
-        LoggerFactory.getLogger(BgpFrameDecoder.class);
-
-    private final BgpSession bgpSession;
-
-    /**
-     * Constructor for a given BGP Session.
-     *
-     * @param bgpSession the BGP session state to use.
-     */
-    BgpFrameDecoder(BgpSession bgpSession) {
-        this.bgpSession = bgpSession;
-    }
-
-    @Override
-    protected Object decode(ChannelHandlerContext ctx,
-                            Channel channel,
-                            ChannelBuffer buf) throws Exception {
-        //
-        // NOTE: If we close the channel during the decoding, we might still
-        // see some incoming messages while the channel closing is completed.
-        //
-        if (bgpSession.isClosed()) {
-            return null;
-        }
-
-        log.trace("BGP Peer: decode(): remoteAddr = {} localAddr = {} " +
-                  "messageSize = {}",
-                  ctx.getChannel().getRemoteAddress(),
-                  ctx.getChannel().getLocalAddress(),
-                  buf.readableBytes());
-
-        // Test for minimum length of the BGP message
-        if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) {
-            // No enough data received
-            return null;
-        }
-
-        //
-        // Mark the current buffer position in case we haven't received
-        // the whole message.
-        //
-        buf.markReaderIndex();
-
-        //
-        // Read and check the BGP message Marker field: it must be all ones
-        // (See RFC 4271, Section 4.1)
-        //
-        byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH];
-        buf.readBytes(marker);
-        for (int i = 0; i < marker.length; i++) {
-            if (marker[i] != (byte) 0xff) {
-                log.debug("BGP RX Error: invalid marker {} at position {}",
-                          marker[i], i);
-                //
-                // ERROR: Connection Not Synchronized
-                //
-                // Send NOTIFICATION and close the connection
-                int errorCode = MessageHeaderError.ERROR_CODE;
-                int errorSubcode =
-                    MessageHeaderError.CONNECTION_NOT_SYNCHRONIZED;
-                ChannelBuffer txMessage =
-                    BgpNotification.prepareBgpNotification(errorCode,
-                                                           errorSubcode,
-                                                           null);
-                ctx.getChannel().write(txMessage);
-                bgpSession.closeSession(ctx);
-                return null;
-            }
-        }
-
-        //
-        // Read and check the BGP message Length field
-        //
-        int length = buf.readUnsignedShort();
-        if ((length < BgpConstants.BGP_HEADER_LENGTH) ||
-            (length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) {
-            log.debug("BGP RX Error: invalid Length field {}. " +
-                      "Must be between {} and {}",
-                      length,
-                      BgpConstants.BGP_HEADER_LENGTH,
-                      BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-            //
-            // ERROR: Bad Message Length
-            //
-            // Send NOTIFICATION and close the connection
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotificationBadMessageLength(length);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return null;
-        }
-
-        //
-        // Test whether the rest of the message is received:
-        // So far we have read the Marker (16 octets) and the
-        // Length (2 octets) fields.
-        //
-        int remainingMessageLen =
-            length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2;
-        if (buf.readableBytes() < remainingMessageLen) {
-            // No enough data received
-            buf.resetReaderIndex();
-            return null;
-        }
-
-        //
-        // Read the BGP message Type field, and process based on that type
-        //
-        int type = buf.readUnsignedByte();
-        remainingMessageLen--;      // Adjust after reading the type
-        ChannelBuffer message = buf.readBytes(remainingMessageLen);
-
-        //
-        // Process the remaining of the message based on the message type
-        //
-        switch (type) {
-        case BgpConstants.BGP_TYPE_OPEN:
-            BgpOpen.processBgpOpen(bgpSession, ctx, message);
-            break;
-        case BgpConstants.BGP_TYPE_UPDATE:
-            BgpUpdate.processBgpUpdate(bgpSession, ctx, message);
-            break;
-        case BgpConstants.BGP_TYPE_NOTIFICATION:
-            BgpNotification.processBgpNotification(bgpSession, ctx, message);
-            break;
-        case BgpConstants.BGP_TYPE_KEEPALIVE:
-            BgpKeepalive.processBgpKeepalive(bgpSession, ctx, message);
-            break;
-        default:
-            //
-            // ERROR: Bad Message Type
-            //
-            // Send NOTIFICATION and close the connection
-            int errorCode = MessageHeaderError.ERROR_CODE;
-            int errorSubcode = MessageHeaderError.BAD_MESSAGE_TYPE;
-            ChannelBuffer data = ChannelBuffers.buffer(1);
-            data.writeByte(type);
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                       data);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return null;
-        }
-        return null;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpKeepalive.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpKeepalive.java
deleted file mode 100644
index fe9404c..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpKeepalive.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A class for handling BGP KEEPALIVE messages.
- */
-final class BgpKeepalive {
-    private static final Logger log =
-        LoggerFactory.getLogger(BgpKeepalive.class);
-
-    /**
-     * Default constructor.
-     * <p>
-     * The constructor is private to prevent creating an instance of
-     * this utility class.
-     */
-    private BgpKeepalive() {
-    }
-
-    /**
-     * Processes BGP KEEPALIVE message.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param message the message to process
-     */
-    static void processBgpKeepalive(BgpSession bgpSession,
-                                    ChannelHandlerContext ctx,
-                                    ChannelBuffer message) {
-        if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
-            BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
-            log.debug("BGP RX KEEPALIVE Error from {}: " +
-                      "Invalid total message length {}. Expected {}",
-                      bgpSession.remoteInfo().address(),
-                      message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH,
-                      BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH);
-            //
-            // ERROR: Bad Message Length
-            //
-            // Send NOTIFICATION and close the connection
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotificationBadMessageLength(
-                message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return;
-        }
-
-        //
-        // Parse the KEEPALIVE message: nothing to do
-        //
-        log.trace("BGP RX KEEPALIVE message from {}",
-                  bgpSession.remoteInfo().address());
-
-        // Start the Session Timeout timer
-        bgpSession.restartSessionTimeoutTimer(ctx);
-    }
-
-    /**
-     * Prepares BGP KEEPALIVE message.
-     *
-     * @return the message to transmit (BGP header included)
-     */
-    static ChannelBuffer prepareBgpKeepalive() {
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
-        //
-        // Prepare the KEEPALIVE message payload: nothing to do
-        //
-        return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE,
-                                            message);
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpMessage.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpMessage.java
deleted file mode 100644
index 5c7053c..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpMessage.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A class for preparing BGP messages.
- */
-final class BgpMessage {
-    private static final Logger log =
-        LoggerFactory.getLogger(BgpMessage.class);
-
-    /**
-     * Default constructor.
-     * <p>
-     * The constructor is private to prevent creating an instance of
-     * this utility class.
-     */
-    private BgpMessage() {
-    }
-
-    /**
-     * Prepares BGP message.
-     *
-     * @param type the BGP message type
-     * @param payload the message payload to transmit (BGP header excluded)
-     * @return the message to transmit (BGP header included)
-     */
-    static ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
-                                  payload.readableBytes());
-
-        // Write the marker
-        for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
-            message.writeByte(0xff);
-        }
-
-        // Write the rest of the BGP header
-        message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
-                           payload.readableBytes());
-        message.writeByte(type);
-
-        // Write the payload
-        message.writeBytes(payload);
-        return message;
-    }
-
-    /**
-     * An exception indicating a parsing error of the BGP message.
-     */
-    static final class BgpParseException extends Exception {
-        /**
-         * Default constructor.
-         */
-        private BgpParseException() {
-            super();
-        }
-
-        /**
-         * Constructor for a specific exception details message.
-         *
-         * @param message the message with the exception details
-         */
-        BgpParseException(String message) {
-            super(message);
-        }
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpNotification.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpNotification.java
deleted file mode 100644
index cf6bbb7..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpNotification.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A class for handling BGP NOTIFICATION messages.
- */
-final class BgpNotification {
-    private static final Logger log =
-        LoggerFactory.getLogger(BgpNotification.class);
-
-    /**
-     * Default constructor.
-     * <p>
-     * The constructor is private to prevent creating an instance of
-     * this utility class.
-     */
-    private BgpNotification() {
-    }
-
-    /**
-     * Processes BGP NOTIFICATION message.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param message the message to process
-     */
-    static void processBgpNotification(BgpSession bgpSession,
-                                       ChannelHandlerContext ctx,
-                                       ChannelBuffer message) {
-        int minLength =
-            BgpConstants.BGP_NOTIFICATION_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
-        if (message.readableBytes() < minLength) {
-            log.debug("BGP RX NOTIFICATION Error from {}: " +
-                      "Message length {} too short. Must be at least {}",
-                      bgpSession.remoteInfo().address(),
-                      message.readableBytes(), minLength);
-            //
-            // ERROR: Bad Message Length
-            //
-            // NOTE: We do NOT send NOTIFICATION in response to a notification
-            return;
-        }
-
-        //
-        // Parse the NOTIFICATION message
-        //
-        int errorCode = message.readUnsignedByte();
-        int errorSubcode = message.readUnsignedByte();
-        int dataLength = message.readableBytes();
-
-        log.debug("BGP RX NOTIFICATION message from {}: Error Code {} " +
-                  "Error Subcode {} Data Length {}",
-                  bgpSession.remoteInfo().address(), errorCode, errorSubcode,
-                  dataLength);
-
-        //
-        // NOTE: If the peer sent a NOTIFICATION, we leave it to the peer to
-        // close the connection.
-        //
-
-        // Start the Session Timeout timer
-        bgpSession.restartSessionTimeoutTimer(ctx);
-    }
-
-    /**
-     * Prepares BGP NOTIFICATION message.
-     *
-     * @param errorCode the BGP NOTIFICATION Error Code
-     * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
-     * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
-     * @param data the BGP NOTIFICATION Data if applicable, otherwise null
-     * @return the message to transmit (BGP header included)
-     */
-    static ChannelBuffer prepareBgpNotification(int errorCode,
-                                                int errorSubcode,
-                                                ChannelBuffer data) {
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
-        //
-        // Prepare the NOTIFICATION message payload
-        //
-        message.writeByte(errorCode);
-        message.writeByte(errorSubcode);
-        if (data != null) {
-            message.writeBytes(data);
-        }
-        return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION,
-                                            message);
-    }
-
-    /**
-     * Prepares BGP NOTIFICATION message: Bad Message Length.
-     *
-     * @param length the erroneous Length field
-     * @return the message to transmit (BGP header included)
-     */
-    static ChannelBuffer prepareBgpNotificationBadMessageLength(int length) {
-        int errorCode = MessageHeaderError.ERROR_CODE;
-        int errorSubcode = MessageHeaderError.BAD_MESSAGE_LENGTH;
-        ChannelBuffer data = ChannelBuffers.buffer(2);
-        data.writeShort(length);
-
-        return prepareBgpNotification(errorCode, errorSubcode, data);
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpOpen.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpOpen.java
deleted file mode 100644
index 93ef852..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpOpen.java
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.onlab.packet.Ip4Address;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
-import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities;
-import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.MultiprotocolExtensions;
-import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.As4Octet;
-import org.onosproject.sdnip.bgp.BgpMessage.BgpParseException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A class for handling BGP OPEN messages.
- */
-final class BgpOpen {
-    private static final Logger log = LoggerFactory.getLogger(BgpOpen.class);
-
-    /**
-     * Default constructor.
-     * <p>
-     * The constructor is private to prevent creating an instance of
-     * this utility class.
-     */
-    private BgpOpen() {
-    }
-
-    /**
-     * Processes BGP OPEN message.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param message the message to process
-     */
-    static void processBgpOpen(BgpSession bgpSession,
-                               ChannelHandlerContext ctx,
-                               ChannelBuffer message) {
-        int minLength =
-            BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
-        if (message.readableBytes() < minLength) {
-            log.debug("BGP RX OPEN Error from {}: " +
-                      "Message length {} too short. Must be at least {}",
-                      bgpSession.remoteInfo().address(),
-                      message.readableBytes(), minLength);
-            //
-            // ERROR: Bad Message Length
-            //
-            // Send NOTIFICATION and close the connection
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotificationBadMessageLength(
-                        message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return;
-        }
-
-        //
-        // Parse the OPEN message
-        //
-        // Remote BGP version
-        int remoteBgpVersion = message.readUnsignedByte();
-        if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
-            log.debug("BGP RX OPEN Error from {}: " +
-                      "Unsupported BGP version {}. Should be {}",
-                      bgpSession.remoteInfo().address(), remoteBgpVersion,
-                      BgpConstants.BGP_VERSION);
-            //
-            // ERROR: Unsupported Version Number
-            //
-            // Send NOTIFICATION and close the connection
-            int errorCode = OpenMessageError.ERROR_CODE;
-            int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
-            ChannelBuffer data = ChannelBuffers.buffer(2);
-            data.writeShort(BgpConstants.BGP_VERSION);
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                       data);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return;
-        }
-        bgpSession.remoteInfo().setBgpVersion(remoteBgpVersion);
-
-        // Remote AS number
-        long remoteAs = message.readUnsignedShort();
-        bgpSession.remoteInfo().setAsNumber(remoteAs);
-        //
-        // NOTE: Currently, the local AS number is always set to the remote AS.
-        // This is done, because the peer setup is always iBGP.
-        // In the future, the local AS number should be configured as part
-        // of an explicit BGP peering configuration.
-        //
-        bgpSession.localInfo().setAsNumber(remoteAs);
-
-        // Remote Hold Time
-        long remoteHoldtime = message.readUnsignedShort();
-        if ((remoteHoldtime != 0) &&
-            (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
-            log.debug("BGP RX OPEN Error from {}: " +
-                      "Unacceptable Hold Time field {}. " +
-                      "Should be 0 or at least {}",
-                      bgpSession.remoteInfo().address(), remoteHoldtime,
-                      BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
-            //
-            // ERROR: Unacceptable Hold Time
-            //
-            // Send NOTIFICATION and close the connection
-            int errorCode = OpenMessageError.ERROR_CODE;
-            int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                       null);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return;
-        }
-        bgpSession.remoteInfo().setHoldtime(remoteHoldtime);
-        //
-        // NOTE: Currently. the local BGP Holdtime is always set to the remote
-        // BGP holdtime.
-        // In the future, the local BGP Holdtime should be configured as part
-        // of an explicit BGP peering configuration.
-        //
-        bgpSession.localInfo().setHoldtime(remoteHoldtime);
-
-        // Remote BGP Identifier
-        Ip4Address remoteBgpId =
-            Ip4Address.valueOf((int) message.readUnsignedInt());
-        bgpSession.remoteInfo().setBgpId(remoteBgpId);
-
-        // Parse the Optional Parameters
-        try {
-            parseOptionalParameters(bgpSession, ctx, message);
-        } catch (BgpParseException e) {
-            // ERROR: Error parsing optional parameters
-            log.debug("BGP RX OPEN Error from {}: " +
-                      "Exception parsing Optional Parameters: {}",
-                      bgpSession.remoteInfo().address(), e);
-            //
-            // ERROR: Invalid Optional Parameters: Unspecific
-            //
-            // Send NOTIFICATION and close the connection
-            int errorCode = OpenMessageError.ERROR_CODE;
-            int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                       null);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return;
-        }
-
-        //
-        // NOTE: Prepare the BGP OPEN message before the original local AS
-        // is overwritten by the 4-octet AS number
-        //
-        ChannelBuffer txOpenMessage = prepareBgpOpen(bgpSession.localInfo());
-
-        //
-        // Use the 4-octet AS number in lieu of the "My AS" field
-        // See RFC 6793, Section 4.1, second paragraph.
-        //
-        if (bgpSession.remoteInfo().as4OctetCapability()) {
-            long as4Number = bgpSession.remoteInfo().as4Number();
-            bgpSession.remoteInfo().setAsNumber(as4Number);
-            bgpSession.localInfo().setAsNumber(as4Number);
-        }
-
-        //
-        // Verify that the AS number is same for all other BGP Sessions
-        // NOTE: This check applies only for our use-case where all BGP
-        // sessions are iBGP.
-        //
-        for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
-            if ((bs.remoteInfo().asNumber() != 0) &&
-                (bgpSession.remoteInfo().asNumber() !=
-                 bs.remoteInfo().asNumber())) {
-                log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
-                          "Expected {}",
-                          bgpSession.remoteInfo().address(),
-                          bgpSession.remoteInfo().asNumber(),
-                          bs.remoteInfo().asNumber());
-                //
-                // ERROR: Bad Peer AS
-                //
-                // Send NOTIFICATION and close the connection
-                int errorCode = OpenMessageError.ERROR_CODE;
-                int errorSubcode = OpenMessageError.BAD_PEER_AS;
-                ChannelBuffer txMessage =
-                    BgpNotification.prepareBgpNotification(errorCode,
-                                                           errorSubcode, null);
-                ctx.getChannel().write(txMessage);
-                bgpSession.closeSession(ctx);
-                return;
-            }
-        }
-
-        log.debug("BGP RX OPEN message from {}: " +
-                  "BGPv{} AS {} BGP-ID {} Holdtime {}",
-                  bgpSession.remoteInfo().address(),
-                  bgpSession.remoteInfo().bgpVersion(),
-                  bgpSession.remoteInfo().asNumber(),
-                  bgpSession.remoteInfo().bgpId(),
-                  bgpSession.remoteInfo().holdtime());
-
-        // Send my OPEN followed by KEEPALIVE
-        ctx.getChannel().write(txOpenMessage);
-        //
-        ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
-        ctx.getChannel().write(txMessage);
-
-        // Start the KEEPALIVE timer
-        bgpSession.restartKeepaliveTimer(ctx);
-
-        // Start the Session Timeout timer
-        bgpSession.restartSessionTimeoutTimer(ctx);
-    }
-
-    /**
-     * Prepares BGP OPEN message.
-     *
-     * @param localInfo the BGP Session local information to use
-     * @return the message to transmit (BGP header included)
-     */
-    static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
-        //
-        // Prepare the OPEN message payload
-        //
-        message.writeByte(localInfo.bgpVersion());
-        message.writeShort((int) localInfo.asNumber());
-        message.writeShort((int) localInfo.holdtime());
-        message.writeInt(localInfo.bgpId().toInt());
-
-        // Prepare the optional BGP Capabilities
-        ChannelBuffer capabilitiesMessage =
-            prepareBgpOpenCapabilities(localInfo);
-        message.writeByte(capabilitiesMessage.readableBytes());
-        message.writeBytes(capabilitiesMessage);
-
-        return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
-                                            message);
-    }
-
-    /**
-     * Parses BGP OPEN Optional Parameters.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param message the message to process
-     * @throws BgpParseException
-     */
-    private static void parseOptionalParameters(BgpSession bgpSession,
-                                                ChannelHandlerContext ctx,
-                                                ChannelBuffer message)
-        throws BgpParseException {
-
-        //
-        // Get and verify the Optional Parameters Length
-        //
-        int optParamLength = message.readUnsignedByte();
-        if (optParamLength > message.readableBytes()) {
-            // ERROR: Invalid Optional Parameter Length
-            String errorMsg = "Invalid Optional Parameter Length field " +
-                optParamLength + ". Remaining Optional Parameters " +
-                message.readableBytes();
-            throw new BgpParseException(errorMsg);
-        }
-        if (optParamLength == 0) {
-            return;                     // No Optional Parameters
-        }
-
-        //
-        // Parse the Optional Parameters
-        //
-        int optParamEnd = message.readerIndex() + optParamLength;
-        while (message.readerIndex() < optParamEnd) {
-            int paramType = message.readUnsignedByte();
-            if (message.readerIndex() >= optParamEnd) {
-                // ERROR: Malformed Optional Parameters
-                String errorMsg = "Malformed Optional Parameters";
-                throw new BgpParseException(errorMsg);
-            }
-            int paramLen = message.readUnsignedByte();
-            if (message.readerIndex() + paramLen > optParamEnd) {
-                // ERROR: Malformed Optional Parameters
-                String errorMsg = "Malformed Optional Parameters";
-                throw new BgpParseException(errorMsg);
-            }
-
-            //
-            // Extract the Optional Parameter Value based on the Parameter Type
-            //
-            switch (paramType) {
-            case Capabilities.TYPE:
-                // Optional Parameter Type: Capabilities
-                if (paramLen < Capabilities.MIN_LENGTH) {
-                    // ERROR: Malformed Capability
-                    String errorMsg = "Malformed Capability Type " + paramType;
-                    throw new BgpParseException(errorMsg);
-                }
-                int capabEnd = message.readerIndex() + paramLen;
-                int capabCode = message.readUnsignedByte();
-                int capabLen = message.readUnsignedByte();
-                if (message.readerIndex() + capabLen > capabEnd) {
-                    // ERROR: Malformed Capability
-                    String errorMsg = "Malformed Capability Type " + paramType;
-                    throw new BgpParseException(errorMsg);
-                }
-
-                switch (capabCode) {
-                case MultiprotocolExtensions.CODE:
-                    // Multiprotocol Extensions Capabilities (RFC 4760)
-                    if (capabLen != MultiprotocolExtensions.LENGTH) {
-                        // ERROR: Multiprotocol Extension Length Error
-                        String errorMsg = "Multiprotocol Extension Length Error";
-                        throw new BgpParseException(errorMsg);
-                    }
-                    // Decode the AFI (2 octets) and SAFI (1 octet)
-                    int afi = message.readUnsignedShort();
-                    int reserved = message.readUnsignedByte();
-                    int safi = message.readUnsignedByte();
-                    log.debug("BGP RX OPEN Capability: AFI = {} SAFI = {}",
-                              afi, safi);
-                    //
-                    // Setup the AFI/SAFI in the BgpSession
-                    //
-                    // NOTE: For now we just copy the remote AFI/SAFI setting
-                    // to the local configuration.
-                    //
-                    if (afi == MultiprotocolExtensions.AFI_IPV4 &&
-                        safi == MultiprotocolExtensions.SAFI_UNICAST) {
-                        bgpSession.remoteInfo().setIpv4Unicast();
-                        bgpSession.localInfo().setIpv4Unicast();
-                    } else if (afi == MultiprotocolExtensions.AFI_IPV4 &&
-                               safi == MultiprotocolExtensions.SAFI_MULTICAST) {
-                        bgpSession.remoteInfo().setIpv4Multicast();
-                        bgpSession.localInfo().setIpv4Multicast();
-                    } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
-                               safi == MultiprotocolExtensions.SAFI_UNICAST) {
-                        bgpSession.remoteInfo().setIpv6Unicast();
-                        bgpSession.localInfo().setIpv6Unicast();
-                    } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
-                               safi == MultiprotocolExtensions.SAFI_MULTICAST) {
-                        bgpSession.remoteInfo().setIpv6Multicast();
-                        bgpSession.localInfo().setIpv6Multicast();
-                    } else {
-                        log.debug("BGP RX OPEN Capability: Unknown AFI = {} SAFI = {}",
-                                  afi, safi);
-                    }
-                    break;
-
-                case Capabilities.As4Octet.CODE:
-                    // Support for 4-octet AS Number Capabilities (RFC 6793)
-                    if (capabLen != Capabilities.As4Octet.LENGTH) {
-                        // ERROR: 4-octet AS Number Capability Length Error
-                        String errorMsg = "4-octet AS Number Capability Length Error";
-                        throw new BgpParseException(errorMsg);
-                    }
-                    long as4Number = message.readUnsignedInt();
-
-                    bgpSession.remoteInfo().setAs4OctetCapability();
-                    bgpSession.remoteInfo().setAs4Number(as4Number);
-
-                    //
-                    // Copy remote 4-octet AS Number Capabilities and AS
-                    // Number. This is a temporary setting until local AS
-                    // number configuration is supported.
-                    //
-                    bgpSession.localInfo().setAs4OctetCapability();
-                    bgpSession.localInfo().setAs4Number(as4Number);
-                    log.debug("BGP RX OPEN Capability: AS4 Number = {}",
-                              as4Number);
-                    break;
-
-                default:
-                    // Unknown Capability: ignore it
-                    log.debug("BGP RX OPEN Capability Code = {} Length = {}",
-                              capabCode, capabLen);
-                    message.readBytes(capabLen);
-                    break;
-                }
-
-                break;
-
-            default:
-                // Unknown Parameter Type: ignore it
-                log.debug("BGP RX OPEN Parameter Type = {} Length = {}",
-                          paramType, paramLen);
-                message.readBytes(paramLen);
-                break;
-            }
-        }
-    }
-
-    /**
-     * Prepares the Capabilities for the BGP OPEN message.
-     *
-     * @param localInfo the BGP Session local information to use
-     * @return the buffer with the BGP Capabilities to transmit
-     */
-    private static ChannelBuffer prepareBgpOpenCapabilities(
-                                        BgpSessionInfo localInfo) {
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
-        //
-        // Write the Multiprotocol Extensions Capabilities
-        //
-
-        // IPv4 unicast
-        if (localInfo.ipv4Unicast()) {
-            message.writeByte(Capabilities.TYPE);               // Param type
-            message.writeByte(Capabilities.MIN_LENGTH +
-                              MultiprotocolExtensions.LENGTH);  // Param len
-            message.writeByte(MultiprotocolExtensions.CODE);    // Capab. code
-            message.writeByte(MultiprotocolExtensions.LENGTH);  // Capab. len
-            message.writeShort(MultiprotocolExtensions.AFI_IPV4);
-            message.writeByte(0);               // Reserved field
-            message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
-        }
-        // IPv4 multicast
-        if (localInfo.ipv4Multicast()) {
-            message.writeByte(Capabilities.TYPE);               // Param type
-            message.writeByte(Capabilities.MIN_LENGTH +
-                              MultiprotocolExtensions.LENGTH);  // Param len
-            message.writeByte(MultiprotocolExtensions.CODE);    // Capab. code
-            message.writeByte(MultiprotocolExtensions.LENGTH);  // Capab. len
-            message.writeShort(MultiprotocolExtensions.AFI_IPV4);
-            message.writeByte(0);               // Reserved field
-            message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
-        }
-        // IPv6 unicast
-        if (localInfo.ipv6Unicast()) {
-            message.writeByte(Capabilities.TYPE);               // Param type
-            message.writeByte(Capabilities.MIN_LENGTH +
-                              MultiprotocolExtensions.LENGTH);  // Param len
-            message.writeByte(MultiprotocolExtensions.CODE);    // Capab. code
-            message.writeByte(MultiprotocolExtensions.LENGTH);  // Capab. len
-            message.writeShort(MultiprotocolExtensions.AFI_IPV6);
-            message.writeByte(0);               // Reserved field
-            message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
-        }
-        // IPv6 multicast
-        if (localInfo.ipv6Multicast()) {
-            message.writeByte(Capabilities.TYPE);               // Param type
-            message.writeByte(Capabilities.MIN_LENGTH +
-                              MultiprotocolExtensions.LENGTH);  // Param len
-            message.writeByte(MultiprotocolExtensions.CODE);    // Capab. code
-            message.writeByte(MultiprotocolExtensions.LENGTH);  // Capab. len
-            message.writeShort(MultiprotocolExtensions.AFI_IPV6);
-            message.writeByte(0);               // Reserved field
-            message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
-        }
-
-        // 4 octet AS path capability
-        if (localInfo.as4OctetCapability()) {
-            message.writeByte(Capabilities.TYPE);               // Param type
-            message.writeByte(Capabilities.MIN_LENGTH +
-                              As4Octet.LENGTH);                 // Param len
-            message.writeByte(As4Octet.CODE);                   // Capab. code
-            message.writeByte(As4Octet.LENGTH);                 // Capab. len
-            message.writeInt((int) localInfo.as4Number());
-        }
-        return message;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpRouteEntry.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpRouteEntry.java
deleted file mode 100644
index 3abdc79..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpRouteEntry.java
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.ArrayList;
-import java.util.Objects;
-
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.Ip4Address;
-import org.onosproject.sdnip.RouteEntry;
-import org.onosproject.sdnip.bgp.BgpConstants.Update;
-
-import com.google.common.base.MoreObjects;
-
-/**
- * Represents a route in BGP.
- */
-public class BgpRouteEntry extends RouteEntry {
-    private final BgpSession bgpSession; // The BGP Session the route was
-                                         // received on
-    private final byte origin;          // Route ORIGIN: IGP, EGP, INCOMPLETE
-    private final AsPath asPath;        // The AS Path
-    private final long localPref;       // The local preference for the route
-    private long multiExitDisc = Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
-
-    /**
-     * Class constructor.
-     *
-     * @param bgpSession the BGP Session the route was received on
-     * @param prefix the prefix of the route
-     * @param nextHop the next hop of the route
-     * @param origin the route origin: 0=IGP, 1=EGP, 2=INCOMPLETE
-     * @param asPath the AS path
-     * @param localPref the route local preference
-     */
-    public BgpRouteEntry(BgpSession bgpSession, IpPrefix prefix,
-                         IpAddress nextHop, byte origin,
-                         BgpRouteEntry.AsPath asPath, long localPref) {
-        super(prefix, nextHop);
-        this.bgpSession = checkNotNull(bgpSession);
-        this.origin = origin;
-        this.asPath = checkNotNull(asPath);
-        this.localPref = localPref;
-    }
-
-    /**
-     * Gets the BGP Session the route was received on.
-     *
-     * @return the BGP Session the route was received on
-     */
-    public BgpSession getBgpSession() {
-        return bgpSession;
-    }
-
-    /**
-     * Gets the route origin: 0=IGP, 1=EGP, 2=INCOMPLETE.
-     *
-     * @return the route origin: 0=IGP, 1=EGP, 2=INCOMPLETE
-     */
-    public byte getOrigin() {
-        return origin;
-    }
-
-    /**
-     * Gets the route AS path.
-     *
-     * @return the route AS path
-     */
-    public BgpRouteEntry.AsPath getAsPath() {
-        return asPath;
-    }
-
-    /**
-     * Gets the route local preference.
-     *
-     * @return the route local preference
-     */
-    public long getLocalPref() {
-        return localPref;
-    }
-
-    /**
-     * Gets the route MED (Multi-Exit Discriminator).
-     *
-     * @return the route MED (Multi-Exit Discriminator)
-     */
-    public long getMultiExitDisc() {
-        return multiExitDisc;
-    }
-
-    /**
-     * Sets the route MED (Multi-Exit Discriminator).
-     *
-     * @param multiExitDisc the route MED (Multi-Exit Discriminator) to set
-     */
-    void setMultiExitDisc(long multiExitDisc) {
-        this.multiExitDisc = multiExitDisc;
-    }
-
-    /**
-     * Tests whether the route is originated from the local AS.
-     * <p>
-     * The route is considered originated from the local AS if the AS Path
-     * is empty or if it begins with an AS_SET (after skipping
-     * AS_CONFED_SEQUENCE and AS_CONFED_SET).
-     * </p>
-     *
-     * @return true if the route is originated from the local AS, otherwise
-     * false
-     */
-    boolean isLocalRoute() {
-        PathSegment firstPathSegment = null;
-
-        // Find the first Path Segment by ignoring the AS_CONFED_* segments
-        for (PathSegment pathSegment : asPath.getPathSegments()) {
-            if ((pathSegment.getType() == Update.AsPath.AS_SET) ||
-                (pathSegment.getType() == Update.AsPath.AS_SEQUENCE)) {
-                firstPathSegment = pathSegment;
-                break;
-            }
-        }
-        if (firstPathSegment == null) {
-            return true;                // Local route: no path segments
-        }
-        // If the first path segment is AS_SET, the route is considered local
-        if (firstPathSegment.getType() == Update.AsPath.AS_SET) {
-            return true;
-        }
-
-        return false;                   // The route is not local
-    }
-
-    /**
-     * Gets the BGP Neighbor AS number the route was received from.
-     * <p>
-     * If the router is originated from the local AS, the return value is
-     * zero (BGP_AS_0).
-     * </p>
-     *
-     * @return the BGP Neighbor AS number the route was received from.
-     */
-    long getNeighborAs() {
-        PathSegment firstPathSegment = null;
-
-        if (isLocalRoute()) {
-            return BgpConstants.BGP_AS_0;
-        }
-
-        // Find the first Path Segment by ignoring the AS_CONFED_* segments
-        for (PathSegment pathSegment : asPath.getPathSegments()) {
-            if ((pathSegment.getType() == Update.AsPath.AS_SET) ||
-                (pathSegment.getType() == Update.AsPath.AS_SEQUENCE)) {
-                firstPathSegment = pathSegment;
-                break;
-            }
-        }
-        if (firstPathSegment == null) {
-            // NOTE: Shouldn't happen - should be captured by isLocalRoute()
-            return BgpConstants.BGP_AS_0;
-        }
-
-        if (firstPathSegment.getSegmentAsNumbers().isEmpty()) {
-            // NOTE: Shouldn't happen. Should check during the parsing.
-            return BgpConstants.BGP_AS_0;
-        }
-        return firstPathSegment.getSegmentAsNumbers().get(0);
-    }
-
-    /**
-     * Tests whether the AS Path contains a loop.
-     * <p>
-     * The test is done by comparing whether the AS Path contains the
-     * local AS number.
-     * </p>
-     *
-     * @param localAsNumber the local AS number to compare against
-     * @return true if the AS Path contains a loop, otherwise false
-     */
-    boolean hasAsPathLoop(long localAsNumber) {
-        for (PathSegment pathSegment : asPath.getPathSegments()) {
-            for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
-                if (asNumber.equals(localAsNumber)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Compares this BGP route against another BGP route by using the
-     * BGP Decision Process.
-     * <p>
-     * NOTE: The comparison needs to be performed only on routes that have
-     * same IP Prefix.
-     * </p>
-     *
-     * @param other the BGP route to compare against
-     * @return true if this BGP route is better than the other BGP route
-     * or same, otherwise false
-     */
-    boolean isBetterThan(BgpRouteEntry other) {
-        if (this == other) {
-            return true;        // Return true if same route
-        }
-
-        // Compare the LOCAL_PREF values: larger is better
-        if (getLocalPref() != other.getLocalPref()) {
-            return (getLocalPref() > other.getLocalPref());
-        }
-
-        // Compare the AS number in the path: smaller is better
-        if (getAsPath().getAsPathLength() !=
-            other.getAsPath().getAsPathLength()) {
-            return getAsPath().getAsPathLength() <
-                other.getAsPath().getAsPathLength();
-        }
-
-        // Compare the Origin number: lower is better
-        if (getOrigin() != other.getOrigin()) {
-            return (getOrigin() < other.getOrigin());
-        }
-
-        // Compare the MED if the neighbor AS is same: larger is better
-        medLabel: {
-            if (isLocalRoute() || other.isLocalRoute()) {
-                // Compare MEDs for non-local routes only
-                break medLabel;
-            }
-            long thisNeighborAs = getNeighborAs();
-            if (thisNeighborAs != other.getNeighborAs()) {
-                break medLabel;             // AS number is different
-            }
-            if (thisNeighborAs == BgpConstants.BGP_AS_0) {
-                break medLabel;             // Invalid AS number
-            }
-
-            // Compare the MED
-            if (getMultiExitDisc() != other.getMultiExitDisc()) {
-                return (getMultiExitDisc() > other.getMultiExitDisc());
-            }
-        }
-
-        // Compare the peer BGP ID: lower is better
-        Ip4Address peerBgpId = getBgpSession().remoteInfo().bgpId();
-        Ip4Address otherPeerBgpId = other.getBgpSession().remoteInfo().bgpId();
-        if (!peerBgpId.equals(otherPeerBgpId)) {
-            return (peerBgpId.compareTo(otherPeerBgpId) < 0);
-        }
-
-        // Compare the peer BGP address: lower is better
-        Ip4Address peerAddress = getBgpSession().remoteInfo().ip4Address();
-        Ip4Address otherPeerAddress =
-            other.getBgpSession().remoteInfo().ip4Address();
-        if (!peerAddress.equals(otherPeerAddress)) {
-            return (peerAddress.compareTo(otherPeerAddress) < 0);
-        }
-
-        return true;            // Routes are same. Shouldn't happen?
-    }
-
-    /**
-     * A class to represent AS Path Segment.
-     */
-    public static class PathSegment {
-        // Segment type: AS_SET(1), AS_SEQUENCE(2), AS_CONFED_SEQUENCE(3),
-        // AS_CONFED_SET(4)
-        private final byte type;
-        private final ArrayList<Long> segmentAsNumbers;   // Segment AS numbers
-
-        /**
-         * Constructor.
-         *
-         * @param type the Path Segment Type: AS_SET(1), AS_SEQUENCE(2),
-         * AS_CONFED_SEQUENCE(3), AS_CONFED_SET(4)
-         * @param segmentAsNumbers the Segment AS numbers
-         */
-        PathSegment(byte type, ArrayList<Long> segmentAsNumbers) {
-            this.type = type;
-            this.segmentAsNumbers = checkNotNull(segmentAsNumbers);
-        }
-
-        /**
-         * Gets the Path Segment Type: AS_SET(1), AS_SEQUENCE(2),
-         * AS_CONFED_SEQUENCE(3), AS_CONFED_SET(4).
-         *
-         * @return the Path Segment Type: AS_SET(1), AS_SEQUENCE(2),
-         * AS_CONFED_SEQUENCE(3), AS_CONFED_SET(4)
-         */
-        public byte getType() {
-            return type;
-        }
-
-        /**
-         * Gets the Path Segment AS Numbers.
-         *
-         * @return the Path Segment AS Numbers
-         */
-        public ArrayList<Long> getSegmentAsNumbers() {
-            return segmentAsNumbers;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-
-            if (!(other instanceof PathSegment)) {
-                return false;
-            }
-
-            PathSegment otherPathSegment = (PathSegment) other;
-            return Objects.equals(this.type, otherPathSegment.type) &&
-                Objects.equals(this.segmentAsNumbers,
-                               otherPathSegment.segmentAsNumbers);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(type, segmentAsNumbers);
-        }
-
-        @Override
-        public String toString() {
-            return MoreObjects.toStringHelper(getClass())
-                .add("type", Update.AsPath.typeToString(type))
-                .add("segmentAsNumbers", this.segmentAsNumbers)
-                .toString();
-        }
-    }
-
-    /**
-     * A class to represent AS Path.
-     */
-    public static class AsPath {
-        private final ArrayList<PathSegment> pathSegments;
-        private final int asPathLength;         // Precomputed AS Path Length
-
-        /**
-         * Constructor.
-         *
-         * @param pathSegments the Path Segments of the Path
-         */
-         AsPath(ArrayList<PathSegment> pathSegments) {
-             this.pathSegments = checkNotNull(pathSegments);
-
-             //
-             // Precompute the AS Path Length:
-             // - AS_SET counts as 1
-             // - AS_SEQUENCE counts how many AS numbers are included
-             // - AS_CONFED_SEQUENCE and AS_CONFED_SET are ignored
-             //
-             int pl = 0;
-             for (PathSegment pathSegment : pathSegments) {
-                 switch (pathSegment.getType()) {
-                 case Update.AsPath.AS_SET:
-                     pl++;              // AS_SET counts as 1
-                     break;
-                 case Update.AsPath.AS_SEQUENCE:
-                     // Count each AS number
-                     pl += pathSegment.getSegmentAsNumbers().size();
-                     break;
-                 case Update.AsPath.AS_CONFED_SEQUENCE:
-                     break;             // Ignore
-                 case Update.AsPath.AS_CONFED_SET:
-                     break;             // Ignore
-                 default:
-                     // NOTE: What to do if the Path Segment type is unknown?
-                     break;
-                 }
-             }
-             asPathLength = pl;
-         }
-
-        /**
-         * Gets the AS Path Segments.
-         *
-         * @return the AS Path Segments
-         */
-        public ArrayList<PathSegment> getPathSegments() {
-            return pathSegments;
-        }
-
-        /**
-         * Gets the AS Path Length as considered by the BGP Decision Process.
-         *
-         * @return the AS Path Length as considered by the BGP Decision Process
-         */
-        int getAsPathLength() {
-            return asPathLength;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-
-            if (!(other instanceof AsPath)) {
-                return false;
-            }
-
-            AsPath otherAsPath = (AsPath) other;
-            return Objects.equals(this.pathSegments, otherAsPath.pathSegments);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(pathSegments);
-        }
-
-        @Override
-        public String toString() {
-            return MoreObjects.toStringHelper(getClass())
-                .add("pathSegments", this.pathSegments)
-                .toString();
-        }
-    }
-
-    /**
-     * Compares whether two objects are equal.
-     * <p>
-     * NOTE: The bgpSession field is excluded from the comparison.
-     * </p>
-     *
-     * @return true if the two objects are equal, otherwise false.
-     */
-    @Override
-    public boolean equals(Object other) {
-        if (this == other) {
-            return true;
-        }
-
-        //
-        // NOTE: Subclasses are considered as change of identity, hence
-        // equals() will return false if the class type doesn't match.
-        //
-        if (other == null || getClass() != other.getClass()) {
-            return false;
-        }
-
-        if (!super.equals(other)) {
-            return false;
-        }
-
-        // NOTE: The bgpSession field is excluded from the comparison
-        BgpRouteEntry otherRoute = (BgpRouteEntry) other;
-        return (this.origin == otherRoute.origin) &&
-            Objects.equals(this.asPath, otherRoute.asPath) &&
-            (this.localPref == otherRoute.localPref) &&
-            (this.multiExitDisc == otherRoute.multiExitDisc);
-    }
-
-    /**
-     * Computes the hash code.
-     * <p>
-     * NOTE: We return the base class hash code to avoid expensive computation
-     * </p>
-     *
-     * @return the object hash code
-     */
-    @Override
-    public int hashCode() {
-        return super.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(getClass())
-            .add("prefix", prefix())
-            .add("nextHop", nextHop())
-            .add("bgpId", bgpSession.remoteInfo().bgpId())
-            .add("origin", Update.Origin.typeToString(origin))
-            .add("asPath", asPath)
-            .add("localPref", localPref)
-            .add("multiExitDisc", multiExitDisc)
-            .toString();
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpRouteSelector.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpRouteSelector.java
deleted file mode 100644
index 1569c07..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpRouteSelector.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.onlab.packet.IpPrefix;
-import org.onosproject.sdnip.RouteUpdate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class to receive and process the BGP routes from each BGP Session/Peer.
- */
-class BgpRouteSelector {
-    private static final Logger log =
-        LoggerFactory.getLogger(BgpRouteSelector.class);
-
-    private BgpSessionManager bgpSessionManager;
-
-    /**
-     * Constructor.
-     *
-     * @param bgpSessionManager the BGP Session Manager to use
-     */
-    BgpRouteSelector(BgpSessionManager bgpSessionManager) {
-        this.bgpSessionManager = bgpSessionManager;
-    }
-
-    /**
-     * Processes route entry updates: added/updated and deleted route
-     * entries.
-     *
-     * @param bgpSession the BGP session the route entry updates were
-     * received on
-     * @param addedBgpRouteEntries the added/updated route entries to process
-     * @param deletedBgpRouteEntries the deleted route entries to process
-     */
-    synchronized void routeUpdates(BgpSession bgpSession,
-                        Collection<BgpRouteEntry> addedBgpRouteEntries,
-                        Collection<BgpRouteEntry> deletedBgpRouteEntries) {
-        Collection<RouteUpdate> routeUpdates = new LinkedList<>();
-        RouteUpdate routeUpdate;
-
-        if (bgpSessionManager.isShutdown()) {
-            return;         // Ignore any leftover updates if shutdown
-        }
-        // Process the deleted route entries
-        for (BgpRouteEntry bgpRouteEntry : deletedBgpRouteEntries) {
-            routeUpdate = processDeletedRoute(bgpSession, bgpRouteEntry);
-            if (routeUpdate != null) {
-                routeUpdates.add(routeUpdate);
-            }
-        }
-
-        // Process the added/updated route entries
-        for (BgpRouteEntry bgpRouteEntry : addedBgpRouteEntries) {
-            routeUpdate = processAddedRoute(bgpSession, bgpRouteEntry);
-            if (routeUpdate != null) {
-                routeUpdates.add(routeUpdate);
-            }
-        }
-        bgpSessionManager.getRouteListener().update(routeUpdates);
-    }
-
-    /**
-     * Processes an added/updated route entry.
-     *
-     * @param bgpSession the BGP session the route entry update was received on
-     * @param bgpRouteEntry the added/updated route entry
-     * @return the result route update that should be forwarded to the
-     * Route Listener, or null if no route update should be forwarded
-     */
-    private RouteUpdate processAddedRoute(BgpSession bgpSession,
-                                          BgpRouteEntry bgpRouteEntry) {
-        RouteUpdate routeUpdate;
-        BgpRouteEntry bestBgpRouteEntry =
-            bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
-
-        //
-        // Install the new route entry if it is better than the
-        // current best route.
-        //
-        if ((bestBgpRouteEntry == null) ||
-            bgpRouteEntry.isBetterThan(bestBgpRouteEntry)) {
-            bgpSessionManager.addBgpRoute(bgpRouteEntry);
-            routeUpdate =
-                new RouteUpdate(RouteUpdate.Type.UPDATE, bgpRouteEntry);
-            return routeUpdate;
-        }
-
-        //
-        // If the route entry arrived on the same BGP Session as
-        // the current best route, then elect the next best route
-        // and install it.
-        //
-        if (bestBgpRouteEntry.getBgpSession() !=
-            bgpRouteEntry.getBgpSession()) {
-            return null;            // Nothing to do
-        }
-
-        // Find the next best route
-        bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
-        if (bestBgpRouteEntry == null) {
-            //
-            // TODO: Shouldn't happen. Install the new route as a
-            // pre-caution.
-            //
-            log.debug("BGP next best route for prefix {} is missing. " +
-                      "Adding the route that is currently processed.",
-                      bgpRouteEntry.prefix());
-            bestBgpRouteEntry = bgpRouteEntry;
-        }
-
-        // Install the next best route
-        bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
-        routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                      bestBgpRouteEntry);
-        return routeUpdate;
-    }
-
-    /**
-     * Processes a deleted route entry.
-     *
-     * @param bgpSession the BGP session the route entry update was received on
-     * @param bgpRouteEntry the deleted route entry
-     * @return the result route update that should be forwarded to the
-     * Route Listener, or null if no route update should be forwarded
-     */
-    private RouteUpdate processDeletedRoute(BgpSession bgpSession,
-                                            BgpRouteEntry bgpRouteEntry) {
-        RouteUpdate routeUpdate;
-        BgpRouteEntry bestBgpRouteEntry =
-            bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
-
-        //
-        // Remove the route entry only if it was the best one.
-        // Install the the next best route if it exists.
-        //
-        // NOTE: We intentionally use "==" instead of method equals(),
-        // because we need to check whether this is same object.
-        //
-        if (bgpRouteEntry != bestBgpRouteEntry) {
-            return null;            // Nothing to do
-        }
-
-        //
-        // Find the next best route
-        //
-        bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
-        if (bestBgpRouteEntry != null) {
-            // Install the next best route
-            bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
-            routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                          bestBgpRouteEntry);
-            return routeUpdate;
-        }
-
-        //
-        // No route found. Remove the route entry
-        //
-        bgpSessionManager.removeBgpRoute(bgpRouteEntry.prefix());
-        routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE, bgpRouteEntry);
-        return routeUpdate;
-    }
-
-    /**
-     * Finds the best route entry among all BGP Sessions.
-     *
-     * @param prefix the prefix of the route
-     * @return the best route if found, otherwise null
-     */
-    private BgpRouteEntry findBestBgpRoute(IpPrefix prefix) {
-        BgpRouteEntry bestRoute = null;
-
-        // Iterate across all BGP Sessions and select the best route
-        for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
-            BgpRouteEntry route = bgpSession.findBgpRoute(prefix);
-            if (route == null) {
-                continue;
-            }
-            if ((bestRoute == null) || route.isBetterThan(bestRoute)) {
-                bestRoute = route;
-            }
-        }
-        return bestRoute;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
deleted file mode 100644
index ace6b53..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.SimpleChannelHandler;
-import org.jboss.netty.util.HashedWheelTimer;
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.Timer;
-import org.jboss.netty.util.TimerTask;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.Ip6Prefix;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.HoldTimerExpired;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class for handling the BGP peer sessions.
- * There is one instance per each BGP peer session.
- */
-public class BgpSession extends SimpleChannelHandler {
-    private static final Logger log =
-        LoggerFactory.getLogger(BgpSession.class);
-
-    private final BgpSessionManager bgpSessionManager;
-
-    // Local flag to indicate the session is closed.
-    // It is used to avoid the Netty's asynchronous closing of a channel.
-    private boolean isClosed = false;
-
-    // BGP session info: local and remote
-    private final BgpSessionInfo localInfo;     // BGP session local info
-    private final BgpSessionInfo remoteInfo;    // BGP session remote info
-
-    // Timers state
-    private Timer timer = new HashedWheelTimer();
-    private volatile Timeout keepaliveTimeout;  // Periodic KEEPALIVE
-    private volatile Timeout sessionTimeout;    // Session timeout
-
-    // BGP RIB-IN routing entries from this peer
-    private ConcurrentMap<Ip4Prefix, BgpRouteEntry> bgpRibIn4 =
-        new ConcurrentHashMap<>();
-    private ConcurrentMap<Ip6Prefix, BgpRouteEntry> bgpRibIn6 =
-        new ConcurrentHashMap<>();
-
-    /**
-     * Constructor for a given BGP Session Manager.
-     *
-     * @param bgpSessionManager the BGP Session Manager to use
-     */
-    BgpSession(BgpSessionManager bgpSessionManager) {
-        this.bgpSessionManager = bgpSessionManager;
-        this.localInfo = new BgpSessionInfo();
-        this.remoteInfo = new BgpSessionInfo();
-
-        // NOTE: We support only BGP4
-        this.localInfo.setBgpVersion(BgpConstants.BGP_VERSION);
-    }
-
-    /**
-     * Gets the BGP Session Manager.
-     *
-     * @return the BGP Session Manager
-     */
-    BgpSessionManager getBgpSessionManager() {
-        return bgpSessionManager;
-    }
-
-    /**
-     * Gets the BGP Session local information.
-     *
-     * @return the BGP Session local information.
-     */
-    public BgpSessionInfo localInfo() {
-        return localInfo;
-    }
-
-    /**
-     * Gets the BGP Session remote information.
-     *
-     * @return the BGP Session remote information.
-     */
-    public BgpSessionInfo remoteInfo() {
-        return remoteInfo;
-    }
-
-    /**
-     * Gets the BGP Multiprotocol Extensions for the session.
-     *
-     * @return true if the BGP Multiprotocol Extensions are enabled for the
-     * session, otherwise false
-     */
-    public boolean mpExtensions() {
-        return remoteInfo.mpExtensions() && localInfo.mpExtensions();
-    }
-
-    /**
-     * Gets the BGP session 4 octet AS path capability.
-     *
-     * @return true when the BGP session is 4 octet AS path capable
-     */
-    public boolean isAs4OctetCapable() {
-        return remoteInfo.as4OctetCapability() &&
-            localInfo.as4OctetCapability();
-    }
-
-    /**
-     * Gets the IPv4 BGP RIB-IN routing entries.
-     *
-     * @return the IPv4 BGP RIB-IN routing entries
-     */
-    public Collection<BgpRouteEntry> getBgpRibIn4() {
-        return bgpRibIn4.values();
-    }
-
-    /**
-     * Gets the IPv6 BGP RIB-IN routing entries.
-     *
-     * @return the IPv6 BGP RIB-IN routing entries
-     */
-    public Collection<BgpRouteEntry> getBgpRibIn6() {
-        return bgpRibIn6.values();
-    }
-
-    /**
-     * Finds an IPv4 BGP routing entry for a prefix in the IPv4 BGP RIB-IN.
-     *
-     * @param prefix the IPv4 prefix of the route to search for
-     * @return the IPv4 BGP routing entry if found, otherwise null
-     */
-    public BgpRouteEntry findBgpRoute(Ip4Prefix prefix) {
-        return bgpRibIn4.get(prefix);
-    }
-
-    /**
-     * Finds an IPv6 BGP routing entry for a prefix in the IPv6 BGP RIB-IN.
-     *
-     * @param prefix the IPv6 prefix of the route to search for
-     * @return the IPv6 BGP routing entry if found, otherwise null
-     */
-    public BgpRouteEntry findBgpRoute(Ip6Prefix prefix) {
-        return bgpRibIn6.get(prefix);
-    }
-
-    /**
-     * Finds a BGP routing entry for a prefix in the BGP RIB-IN. The prefix
-     * can be either IPv4 or IPv6.
-     *
-     * @param prefix the IP prefix of the route to search for
-     * @return the BGP routing entry if found, otherwise null
-     */
-    public BgpRouteEntry findBgpRoute(IpPrefix prefix) {
-        if (prefix.version() == Ip4Address.VERSION) {
-            // IPv4 prefix
-            Ip4Prefix ip4Prefix = prefix.getIp4Prefix();
-            return bgpRibIn4.get(ip4Prefix);
-        }
-
-        // IPv6 prefix
-        Ip6Prefix ip6Prefix = prefix.getIp6Prefix();
-        return bgpRibIn6.get(ip6Prefix);
-    }
-
-    /**
-     * Adds a BGP route. The route can be either IPv4 or IPv6.
-     *
-     * @param bgpRouteEntry the BGP route entry to use
-     */
-    void addBgpRoute(BgpRouteEntry bgpRouteEntry) {
-        if (bgpRouteEntry.version() == Ip4Address.VERSION) {
-            // IPv4 route
-            Ip4Prefix ip4Prefix = bgpRouteEntry.prefix().getIp4Prefix();
-            bgpRibIn4.put(ip4Prefix, bgpRouteEntry);
-        } else {
-            // IPv6 route
-            Ip6Prefix ip6Prefix = bgpRouteEntry.prefix().getIp6Prefix();
-            bgpRibIn6.put(ip6Prefix, bgpRouteEntry);
-        }
-    }
-
-    /**
-     * Removes an IPv4 BGP route for a prefix.
-     *
-     * @param prefix the prefix to use
-     * @return true if the route was found and removed, otherwise false
-     */
-    boolean removeBgpRoute(Ip4Prefix prefix) {
-        return (bgpRibIn4.remove(prefix) != null);
-    }
-
-    /**
-     * Removes an IPv6 BGP route for a prefix.
-     *
-     * @param prefix the prefix to use
-     * @return true if the route was found and removed, otherwise false
-     */
-    boolean removeBgpRoute(Ip6Prefix prefix) {
-        return (bgpRibIn6.remove(prefix) != null);
-    }
-
-    /**
-     * Removes a BGP route for a prefix. The prefix can be either IPv4 or IPv6.
-     *
-     * @param prefix the prefix to use
-     * @return true if the route was found and removed, otherwise false
-     */
-    boolean removeBgpRoute(IpPrefix prefix) {
-        if (prefix.version() == Ip4Address.VERSION) {
-            return (bgpRibIn4.remove(prefix.getIp4Prefix()) != null);   // IPv4
-        }
-        return (bgpRibIn6.remove(prefix.getIp6Prefix()) != null);       // IPv6
-    }
-
-    /**
-     * Tests whether the session is closed.
-     * <p>
-     * NOTE: We use this method to avoid the Netty's asynchronous closing
-     * of a channel.
-     * </p>
-     * @return true if the session is closed
-     */
-    boolean isClosed() {
-        return isClosed;
-    }
-
-    /**
-     * Closes the session.
-     *
-     * @param ctx the Channel Handler Context
-     */
-    void closeSession(ChannelHandlerContext ctx) {
-        timer.stop();
-        closeChannel(ctx);
-    }
-
-    /**
-     * Closes the Netty channel.
-     *
-     * @param ctx the Channel Handler Context
-     */
-    void closeChannel(ChannelHandlerContext ctx) {
-        isClosed = true;
-        ctx.getChannel().close();
-    }
-
-    @Override
-    public void channelOpen(ChannelHandlerContext ctx,
-                            ChannelStateEvent channelEvent) {
-        bgpSessionManager.addSessionChannel(channelEvent.getChannel());
-    }
-
-    @Override
-    public void channelClosed(ChannelHandlerContext ctx,
-                              ChannelStateEvent channelEvent) {
-        bgpSessionManager.removeSessionChannel(channelEvent.getChannel());
-    }
-
-    @Override
-    public void channelConnected(ChannelHandlerContext ctx,
-                                 ChannelStateEvent channelEvent) {
-        localInfo.setAddress(ctx.getChannel().getLocalAddress());
-        remoteInfo.setAddress(ctx.getChannel().getRemoteAddress());
-
-        // Assign the local and remote IPv4 addresses
-        InetAddress inetAddr;
-        if (localInfo.address() instanceof InetSocketAddress) {
-            inetAddr = ((InetSocketAddress) localInfo.address()).getAddress();
-            localInfo.setIp4Address(Ip4Address.valueOf(inetAddr.getAddress()));
-        }
-        if (remoteInfo.address() instanceof InetSocketAddress) {
-            inetAddr = ((InetSocketAddress) remoteInfo.address()).getAddress();
-            remoteInfo.setIp4Address(Ip4Address.valueOf(inetAddr.getAddress()));
-        }
-
-        log.debug("BGP Session Connected from {} on {}",
-                  remoteInfo.address(), localInfo.address());
-        if (!bgpSessionManager.peerConnected(this)) {
-            log.debug("Cannot setup BGP Session Connection from {}. Closing...",
-                      remoteInfo.address());
-            ctx.getChannel().close();
-        }
-
-        //
-        // Assign the local BGP ID
-        // NOTE: This should be configuration-based
-        //
-        localInfo.setBgpId(bgpSessionManager.getMyBgpId());
-    }
-
-    @Override
-    public void channelDisconnected(ChannelHandlerContext ctx,
-                                    ChannelStateEvent channelEvent) {
-        log.debug("BGP Session Disconnected from {} on {}",
-                  ctx.getChannel().getRemoteAddress(),
-                  ctx.getChannel().getLocalAddress());
-        processChannelDisconnected();
-    }
-
-    @Override
-    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
-        log.debug("BGP Session Exception Caught from {} on {}: {}",
-                  ctx.getChannel().getRemoteAddress(),
-                  ctx.getChannel().getLocalAddress(),
-                  e);
-        processChannelDisconnected();
-    }
-
-    /**
-     * Processes the channel being disconnected.
-     */
-    private void processChannelDisconnected() {
-        //
-        // Withdraw the routes advertised by this BGP peer
-        //
-        // NOTE: We must initialize the RIB-IN before propagating the withdraws
-        // for further processing. Otherwise, the BGP Decision Process
-        // will use those routes again.
-        //
-        Collection<BgpRouteEntry> deletedRoutes4 = bgpRibIn4.values();
-        Collection<BgpRouteEntry> deletedRoutes6 = bgpRibIn6.values();
-        bgpRibIn4 = new ConcurrentHashMap<>();
-        bgpRibIn6 = new ConcurrentHashMap<>();
-
-        // Push the updates to the BGP Merged RIB
-        BgpRouteSelector bgpRouteSelector =
-            bgpSessionManager.getBgpRouteSelector();
-        Collection<BgpRouteEntry> addedRoutes = Collections.emptyList();
-        bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes4);
-        bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes6);
-
-        bgpSessionManager.peerDisconnected(this);
-    }
-
-    /**
-     * Restarts the BGP KeepaliveTimer.
-     *
-     * @param ctx the Channel Handler Context to use
-     */
-    void restartKeepaliveTimer(ChannelHandlerContext ctx) {
-        long localKeepaliveInterval = 0;
-
-        //
-        // Compute the local Keepalive interval
-        //
-        if (localInfo.holdtime() != 0) {
-            localKeepaliveInterval = Math.max(localInfo.holdtime() /
-                         BgpConstants.BGP_KEEPALIVE_PER_HOLD_INTERVAL,
-                         BgpConstants.BGP_KEEPALIVE_MIN_INTERVAL);
-        }
-
-        // Restart the Keepalive timer
-        if (localKeepaliveInterval == 0) {
-            return;                 // Nothing to do
-        }
-        keepaliveTimeout = timer.newTimeout(new TransmitKeepaliveTask(ctx),
-                                            localKeepaliveInterval,
-                                            TimeUnit.SECONDS);
-    }
-
-    /**
-     * Task class for transmitting KEEPALIVE messages.
-     */
-    private final class TransmitKeepaliveTask implements TimerTask {
-        private final ChannelHandlerContext ctx;
-
-        /**
-         * Constructor for given Channel Handler Context.
-         *
-         * @param ctx the Channel Handler Context to use
-         */
-        TransmitKeepaliveTask(ChannelHandlerContext ctx) {
-            this.ctx = ctx;
-        }
-
-        @Override
-        public void run(Timeout timeout) throws Exception {
-            if (timeout.isCancelled()) {
-                return;
-            }
-            if (!ctx.getChannel().isOpen()) {
-                return;
-            }
-
-            // Transmit the KEEPALIVE
-            ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
-            ctx.getChannel().write(txMessage);
-
-            // Restart the KEEPALIVE timer
-            restartKeepaliveTimer(ctx);
-        }
-    }
-
-    /**
-     * Restarts the BGP Session Timeout Timer.
-     *
-     * @param ctx the Channel Handler Context to use
-     */
-    void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
-        if (remoteInfo.holdtime() == 0) {
-            return;                 // Nothing to do
-        }
-        if (sessionTimeout != null) {
-            sessionTimeout.cancel();
-        }
-        sessionTimeout = timer.newTimeout(new SessionTimeoutTask(ctx),
-                                          remoteInfo.holdtime(),
-                                          TimeUnit.SECONDS);
-    }
-
-    /**
-     * Task class for BGP Session timeout.
-     */
-    private final class SessionTimeoutTask implements TimerTask {
-        private final ChannelHandlerContext ctx;
-
-        /**
-         * Constructor for given Channel Handler Context.
-         *
-         * @param ctx the Channel Handler Context to use
-         */
-        SessionTimeoutTask(ChannelHandlerContext ctx) {
-            this.ctx = ctx;
-        }
-
-        @Override
-        public void run(Timeout timeout) throws Exception {
-            if (timeout.isCancelled()) {
-                return;
-            }
-            if (!ctx.getChannel().isOpen()) {
-                return;
-            }
-
-            log.debug("BGP Session Timeout: peer {}", remoteInfo.address());
-            //
-            // ERROR: Invalid Optional Parameter Length field: Unspecific
-            //
-            // Send NOTIFICATION and close the connection
-            int errorCode = HoldTimerExpired.ERROR_CODE;
-            int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                       null);
-            ctx.getChannel().write(txMessage);
-            closeChannel(ctx);
-        }
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSessionInfo.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSessionInfo.java
deleted file mode 100644
index a492d80..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSessionInfo.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import java.net.SocketAddress;
-import org.onlab.packet.Ip4Address;
-
-/**
- * Class for keeping information about a BGP session.
- *
- * There are two instances per each BGP peer session: one to keep the local
- * information about the BGP session, and another to keep information about
- * the remote BGP peer.
- */
-public class BgpSessionInfo {
-    private SocketAddress address;              // IP addr/port
-    private Ip4Address ip4Address;              // IPv4 address
-    private int bgpVersion;                     // 1 octet
-    private long asNumber;                      // AS number: 2 octets
-    private long as4Number;                     // AS4 number: 4 octets
-    private long holdtime;                      // 2 octets
-    private Ip4Address bgpId;                   // 4 octets -> IPv4 address
-    private boolean mpExtensions;               // Multiprotocol Extensions
-                                                // enabled: RFC 4760
-    private boolean ipv4Unicast;                // IPv4/UNICAST AFI/SAFI
-    private boolean ipv4Multicast;              // IPv4/MULTICAST AFI/SAFI
-    private boolean ipv6Unicast;                // IPv6/UNICAST AFI/SAFI
-    private boolean ipv6Multicast;              // IPv6/MULTICAST AFI/SAFI
-    private boolean as4OctetCapability;         // AS 4 octet path capability
-
-    /**
-     * Gets the BGP session address: local or remote.
-     *
-     * @return the BGP session address
-     */
-    public SocketAddress address() {
-        return this.address;
-    }
-
-    /**
-     * Sets the BGP session address: local or remote.
-     *
-     * @param address the BGP session address to set
-     */
-    public void setAddress(SocketAddress address) {
-        this.address = address;
-    }
-
-    /**
-     * Gets the BGP session IPv4 address: local or remote.
-     *
-     * @return the BGP session IPv4 address
-     */
-    public Ip4Address ip4Address() {
-        return this.ip4Address;
-    }
-
-    /**
-     * Sets the BGP session IPv4 address: local or remote.
-     *
-     * @param ip4Address the BGP session IPv4 address to set
-     */
-    public void setIp4Address(Ip4Address ip4Address) {
-        this.ip4Address = ip4Address;
-    }
-
-    /**
-     * Gets the BGP session BGP version: local or remote.
-     *
-     * @return the BGP session BGP version
-     */
-    public int bgpVersion() {
-        return this.bgpVersion;
-    }
-
-    /**
-     * Sets the BGP session BGP version: local or remote.
-     *
-     * @param bgpVersion the BGP session BGP version to set
-     */
-    public void setBgpVersion(int bgpVersion) {
-        this.bgpVersion = bgpVersion;
-    }
-
-    /**
-     * Gets the BGP session AS number: local or remote.
-     *
-     * @return the BGP session AS number
-     */
-    public long asNumber() {
-        return this.asNumber;
-    }
-
-    /**
-     * Sets the BGP session AS number: local or remote.
-     *
-     * @param asNumber the BGP session AS number to set
-     */
-    public void setAsNumber(long asNumber) {
-        this.asNumber = asNumber;
-    }
-
-    /**
-     * Gets the BGP session AS4 number: local or remote.
-     *
-     * @return the BGP session AS4 number
-     */
-    public long as4Number() {
-        return this.as4Number;
-    }
-
-    /**
-     * Sets the BGP session AS4 number: local or remote.
-     *
-     * @param as4Number the BGP session AS4 number to set
-     */
-    public void setAs4Number(long as4Number) {
-        this.as4Number = as4Number;
-    }
-
-    /**
-     * Gets the BGP session holdtime: local or remote.
-     *
-     * @return the BGP session holdtime
-     */
-    public long holdtime() {
-        return this.holdtime;
-    }
-
-    /**
-     * Sets the BGP session holdtime: local or remote.
-     *
-     * @param holdtime the BGP session holdtime to set
-     */
-    public void setHoldtime(long holdtime) {
-        this.holdtime = holdtime;
-    }
-
-    /**
-     * Gets the BGP session BGP Identifier as an IPv4 address: local or remote.
-     *
-     * @return the BGP session BGP Identifier as an IPv4 address
-     */
-    public Ip4Address bgpId() {
-        return this.bgpId;
-    }
-
-    /**
-     * Sets the BGP session BGP Identifier as an IPv4 address: local or remote.
-     *
-     * @param bgpId the BGP session BGP Identifier to set
-     */
-    public void setBgpId(Ip4Address bgpId) {
-        this.bgpId = bgpId;
-    }
-
-    /**
-     * Gets the BGP Multiprotocol Extensions: local or remote.
-     *
-     * @return true if the BGP Multiprotocol Extensions are enabled, otherwise
-     * false
-     */
-    public boolean mpExtensions() {
-        return this.mpExtensions;
-    }
-
-    /**
-     * Gets the BGP session AFI/SAFI configuration for IPv4 unicast: local or
-     * remote.
-     *
-     * @return the BGP session AFI/SAFI configuration for IPv4 unicast
-     */
-    public boolean ipv4Unicast() {
-        return ipv4Unicast;
-    }
-
-    /**
-     * Sets the BGP session AFI/SAFI configuration for IPv4 unicast: local or
-     * remote.
-     */
-    public void setIpv4Unicast() {
-        this.mpExtensions = true;
-        this.ipv4Unicast = true;
-    }
-
-    /**
-     * Gets the BGP session AFI/SAFI configuration for IPv4 multicast: local or
-     * remote.
-     *
-     * @return the BGP session AFI/SAFI configuration for IPv4 multicast
-     */
-    public boolean ipv4Multicast() {
-        return ipv4Multicast;
-    }
-
-    /**
-     * Sets the BGP session AFI/SAFI configuration for IPv4 multicast: local or
-     * remote.
-     */
-    public void setIpv4Multicast() {
-        this.mpExtensions = true;
-        this.ipv4Multicast = true;
-    }
-
-    /**
-     * Gets the BGP session AFI/SAFI configuration for IPv6 unicast: local or
-     * remote.
-     *
-     * @return the BGP session AFI/SAFI configuration for IPv6 unicast
-     */
-    public boolean ipv6Unicast() {
-        return ipv6Unicast;
-    }
-
-    /**
-     * Sets the BGP session AFI/SAFI configuration for IPv6 unicast: local or
-     * remote.
-     */
-    void setIpv6Unicast() {
-        this.mpExtensions = true;
-        this.ipv6Unicast = true;
-    }
-
-    /**
-     * Gets the BGP session AFI/SAFI configuration for IPv6 multicast: local or
-     * remote.
-     *
-     * @return the BGP session AFI/SAFI configuration for IPv6 multicast
-     */
-    public boolean ipv6Multicast() {
-        return ipv6Multicast;
-    }
-
-    /**
-     * Sets the BGP session AFI/SAFI configuration for IPv6 multicast: local or
-     * remote.
-     */
-    public void setIpv6Multicast() {
-        this.mpExtensions = true;
-        this.ipv6Multicast = true;
-    }
-
-    /**
-     * Gets the BGP session 4 octet AS path capability: local or remote.
-     *
-     * @return true when the BGP session has 4 octet AS path capability
-     */
-    public boolean as4OctetCapability() {
-        return this.as4OctetCapability;
-    }
-
-    /**
-     * Sets the BGP session 4 octet AS path capability.
-     */
-    public void setAs4OctetCapability() {
-        this.as4OctetCapability = true;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSessionManager.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSessionManager.java
deleted file mode 100644
index 2ca2972..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSessionManager.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import org.jboss.netty.bootstrap.ServerBootstrap;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelException;
-import org.jboss.netty.channel.ChannelFactory;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.channel.group.ChannelGroup;
-import org.jboss.netty.channel.group.DefaultChannelGroup;
-import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.Ip6Prefix;
-import org.onlab.packet.IpPrefix;
-import org.onosproject.sdnip.RouteListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.Collection;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newCachedThreadPool;
-import static org.onlab.util.Tools.namedThreads;
-
-/**
- * BGP Session Manager class.
- */
-public class BgpSessionManager {
-    private static final Logger log =
-            LoggerFactory.getLogger(BgpSessionManager.class);
-
-    boolean isShutdown = true;
-    private Channel serverChannel;     // Listener for incoming BGP connections
-    private ServerBootstrap serverBootstrap;
-    private ChannelGroup allChannels = new DefaultChannelGroup();
-    private ConcurrentMap<SocketAddress, BgpSession> bgpSessions =
-            new ConcurrentHashMap<>();
-    private Ip4Address myBgpId;        // Same BGP ID for all peers
-
-    private BgpRouteSelector bgpRouteSelector = new BgpRouteSelector(this);
-    private ConcurrentMap<Ip4Prefix, BgpRouteEntry> bgpRoutes4 =
-            new ConcurrentHashMap<>();
-    private ConcurrentMap<Ip6Prefix, BgpRouteEntry> bgpRoutes6 =
-            new ConcurrentHashMap<>();
-
-    private final RouteListener routeListener;
-
-    /**
-     * Constructor for given route listener.
-     *
-     * @param routeListener the route listener to use
-     */
-    public BgpSessionManager(RouteListener routeListener) {
-        this.routeListener = checkNotNull(routeListener);
-    }
-
-    /**
-     * Checks whether the BGP Session Manager is shutdown.
-     *
-     * @return true if the BGP Session Manager is shutdown, otherwise false
-     */
-    boolean isShutdown() {
-        return this.isShutdown;
-    }
-
-    /**
-     * Gets the route listener.
-     *
-     * @return the route listener to use
-     */
-    RouteListener getRouteListener() {
-        return routeListener;
-    }
-
-    /**
-     * Gets the BGP sessions.
-     *
-     * @return the BGP sessions
-     */
-    public Collection<BgpSession> getBgpSessions() {
-        return bgpSessions.values();
-    }
-
-    /**
-     * Gets the selected IPv4 BGP routes among all BGP sessions.
-     *
-     * @return the selected IPv4 BGP routes among all BGP sessions
-     */
-    public Collection<BgpRouteEntry> getBgpRoutes4() {
-        return bgpRoutes4.values();
-    }
-
-    /**
-     * Gets the selected IPv6 BGP routes among all BGP sessions.
-     *
-     * @return the selected IPv6 BGP routes among all BGP sessions
-     */
-    public Collection<BgpRouteEntry> getBgpRoutes6() {
-        return bgpRoutes6.values();
-    }
-
-    /**
-     * Finds a BGP route for a prefix. The prefix can be either IPv4 or IPv6.
-     *
-     * @param prefix the prefix to use
-     * @return the BGP route if found, otherwise null
-     */
-    BgpRouteEntry findBgpRoute(IpPrefix prefix) {
-        if (prefix.version() == Ip4Address.VERSION) {
-            return bgpRoutes4.get(prefix.getIp4Prefix());               // IPv4
-        }
-        return bgpRoutes6.get(prefix.getIp6Prefix());                   // IPv6
-    }
-
-    /**
-     * Adds a BGP route. The route can be either IPv4 or IPv6.
-     *
-     * @param bgpRouteEntry the BGP route entry to use
-     */
-    void addBgpRoute(BgpRouteEntry bgpRouteEntry) {
-        if (bgpRouteEntry.version() == Ip4Address.VERSION) {
-            bgpRoutes4.put(bgpRouteEntry.prefix().getIp4Prefix(),       // IPv4
-                           bgpRouteEntry);
-        } else {
-            bgpRoutes6.put(bgpRouteEntry.prefix().getIp6Prefix(),       // IPv6
-                           bgpRouteEntry);
-        }
-    }
-
-    /**
-     * Removes a BGP route for a prefix. The prefix can be either IPv4 or IPv6.
-     *
-     * @param prefix the prefix to use
-     * @return true if the route was found and removed, otherwise false
-     */
-    boolean removeBgpRoute(IpPrefix prefix) {
-        if (prefix.version() == Ip4Address.VERSION) {
-            return (bgpRoutes4.remove(prefix.getIp4Prefix()) != null);  // IPv4
-        }
-        return (bgpRoutes6.remove(prefix.getIp6Prefix()) != null);      // IPv6
-    }
-
-    /**
-     * Adds the channel for a BGP session.
-     *
-     * @param channel the channel to add
-     */
-    void addSessionChannel(Channel channel) {
-        allChannels.add(channel);
-    }
-
-    /**
-     * Removes the channel for a BGP session.
-     *
-     * @param channel the channel to remove
-     */
-    void removeSessionChannel(Channel channel) {
-        allChannels.remove(channel);
-    }
-
-    /**
-     * Processes the connection from a BGP peer.
-     *
-     * @param bgpSession the BGP session for the peer
-     * @return true if the connection can be established, otherwise false
-     */
-    boolean peerConnected(BgpSession bgpSession) {
-
-        // Test whether there is already a session from the same remote
-        if (bgpSessions.get(bgpSession.remoteInfo().address()) != null) {
-            return false;               // Duplicate BGP session
-        }
-        bgpSessions.put(bgpSession.remoteInfo().address(), bgpSession);
-
-        //
-        // If the first connection, set my BGP ID to the local address
-        // of the socket.
-        //
-        if (bgpSession.localInfo().address() instanceof InetSocketAddress) {
-            InetAddress inetAddr =
-                ((InetSocketAddress) bgpSession.localInfo().address()).getAddress();
-            Ip4Address ip4Address = Ip4Address.valueOf(inetAddr.getAddress());
-            updateMyBgpId(ip4Address);
-        }
-        return true;
-    }
-
-    /**
-     * Processes the disconnection from a BGP peer.
-     *
-     * @param bgpSession the BGP session for the peer
-     */
-    void peerDisconnected(BgpSession bgpSession) {
-        bgpSessions.remove(bgpSession.remoteInfo().address());
-    }
-
-    /**
-     * Conditionally updates the local BGP ID if it wasn't set already.
-     * <p/>
-     * NOTE: A BGP instance should use same BGP ID across all BGP sessions.
-     *
-     * @param ip4Address the IPv4 address to use as BGP ID
-     */
-    private synchronized void updateMyBgpId(Ip4Address ip4Address) {
-        if (myBgpId == null) {
-            myBgpId = ip4Address;
-            log.debug("BGP: My BGP ID is {}", myBgpId);
-        }
-    }
-
-    /**
-     * Gets the local BGP Identifier as an IPv4 address.
-     *
-     * @return the local BGP Identifier as an IPv4 address
-     */
-    Ip4Address getMyBgpId() {
-        return myBgpId;
-    }
-
-    /**
-     * Gets the BGP Route Selector.
-     *
-     * @return the BGP Route Selector
-     */
-    BgpRouteSelector getBgpRouteSelector() {
-        return bgpRouteSelector;
-    }
-
-    /**
-     * Starts up BGP Session Manager operation.
-     *
-     * @param listenPortNumber the port number to listen on. By default
-     *                         it should be BgpConstants.BGP_PORT (179)
-     */
-    public void start(int listenPortNumber) {
-        log.debug("BGP Session Manager start.");
-        isShutdown = false;
-
-        ChannelFactory channelFactory = new NioServerSocketChannelFactory(
-                newCachedThreadPool(namedThreads("onos-bgp-sm-boss-%d")),
-                newCachedThreadPool(namedThreads("onos-bgp-sm-worker-%d")));
-        ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() {
-            @Override
-            public ChannelPipeline getPipeline() throws Exception {
-                // Allocate a new session per connection
-                BgpSession bgpSessionHandler =
-                        new BgpSession(BgpSessionManager.this);
-                BgpFrameDecoder bgpFrameDecoder =
-                        new BgpFrameDecoder(bgpSessionHandler);
-
-                // Setup the processing pipeline
-                ChannelPipeline pipeline = Channels.pipeline();
-                pipeline.addLast("BgpFrameDecoder", bgpFrameDecoder);
-                pipeline.addLast("BgpSession", bgpSessionHandler);
-                return pipeline;
-            }
-        };
-        InetSocketAddress listenAddress =
-                new InetSocketAddress(listenPortNumber);
-
-        serverBootstrap = new ServerBootstrap(channelFactory);
-        // serverBootstrap.setOptions("reuseAddr", true);
-        serverBootstrap.setOption("child.keepAlive", true);
-        serverBootstrap.setOption("child.tcpNoDelay", true);
-        serverBootstrap.setPipelineFactory(pipelineFactory);
-        try {
-            serverChannel = serverBootstrap.bind(listenAddress);
-            allChannels.add(serverChannel);
-        } catch (ChannelException e) {
-            log.debug("Exception binding to BGP port {}: ",
-                      listenAddress.getPort(), e);
-        }
-    }
-
-    /**
-     * Stops the BGP Session Manager operation.
-     */
-    public void stop() {
-        isShutdown = true;
-        allChannels.close().awaitUninterruptibly();
-        serverBootstrap.releaseExternalResources();
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpUpdate.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpUpdate.java
deleted file mode 100644
index 2068324..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpUpdate.java
+++ /dev/null
@@ -1,1699 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.lang3.tuple.Pair;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.Ip6Address;
-import org.onlab.packet.Ip6Prefix;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
-import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.MultiprotocolExtensions;
-import org.onosproject.sdnip.bgp.BgpConstants.Update;
-import org.onosproject.sdnip.bgp.BgpConstants.Update.AsPath;
-import org.onosproject.sdnip.bgp.BgpMessage.BgpParseException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A class for handling BGP UPDATE messages.
- */
-final class BgpUpdate {
-    private static final Logger log = LoggerFactory.getLogger(BgpUpdate.class);
-
-    /**
-     * Default constructor.
-     * <p>
-     * The constructor is private to prevent creating an instance of
-     * this utility class.
-     */
-    private BgpUpdate() {
-    }
-
-    /**
-     * Processes BGP UPDATE message.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param message the message to process
-     */
-    static void processBgpUpdate(BgpSession bgpSession,
-                                 ChannelHandlerContext ctx,
-                                 ChannelBuffer message) {
-        DecodedBgpRoutes decodedBgpRoutes = new DecodedBgpRoutes();
-
-        int minLength =
-            BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
-        if (message.readableBytes() < minLength) {
-            log.debug("BGP RX UPDATE Error from {}: " +
-                      "Message length {} too short. Must be at least {}",
-                      bgpSession.remoteInfo().address(),
-                      message.readableBytes(), minLength);
-            //
-            // ERROR: Bad Message Length
-            //
-            // Send NOTIFICATION and close the connection
-            ChannelBuffer txMessage =
-                BgpNotification.prepareBgpNotificationBadMessageLength(
-                message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
-            ctx.getChannel().write(txMessage);
-            bgpSession.closeSession(ctx);
-            return;
-        }
-
-        log.debug("BGP RX UPDATE message from {}",
-                  bgpSession.remoteInfo().address());
-
-        //
-        // Parse the UPDATE message
-        //
-
-        //
-        // Parse the Withdrawn Routes
-        //
-        int withdrawnRoutesLength = message.readUnsignedShort();
-        if (withdrawnRoutesLength > message.readableBytes()) {
-            // ERROR: Malformed Attribute List
-            actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
-            return;
-        }
-        Collection<Ip4Prefix> withdrawnPrefixes = null;
-        try {
-            withdrawnPrefixes = parsePackedIp4Prefixes(withdrawnRoutesLength,
-                                                       message);
-        } catch (BgpParseException e) {
-            // ERROR: Invalid Network Field
-            log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
-                      bgpSession.remoteInfo().bgpId(), e);
-            actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
-            return;
-        }
-        for (Ip4Prefix prefix : withdrawnPrefixes) {
-            log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
-                      bgpSession.remoteInfo().address(), prefix);
-            BgpRouteEntry bgpRouteEntry = bgpSession.findBgpRoute(prefix);
-            if (bgpRouteEntry != null) {
-                decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
-                                                           bgpRouteEntry);
-            }
-        }
-
-        //
-        // Parse the Path Attributes
-        //
-        try {
-            parsePathAttributes(bgpSession, ctx, message, decodedBgpRoutes);
-        } catch (BgpParseException e) {
-            log.debug("Exception parsing Path Attributes from BGP peer {}: ",
-                      bgpSession.remoteInfo().bgpId(), e);
-            // NOTE: The session was already closed, so nothing else to do
-            return;
-        }
-
-        //
-        // Update the BGP RIB-IN
-        //
-        for (Ip4Prefix ip4Prefix :
-                 decodedBgpRoutes.deletedUnicastRoutes4.keySet()) {
-            bgpSession.removeBgpRoute(ip4Prefix);
-        }
-        //
-        for (BgpRouteEntry bgpRouteEntry :
-                 decodedBgpRoutes.addedUnicastRoutes4.values()) {
-            bgpSession.addBgpRoute(bgpRouteEntry);
-        }
-        //
-        for (Ip6Prefix ip6Prefix :
-                 decodedBgpRoutes.deletedUnicastRoutes6.keySet()) {
-            bgpSession.removeBgpRoute(ip6Prefix);
-        }
-        //
-        for (BgpRouteEntry bgpRouteEntry :
-                 decodedBgpRoutes.addedUnicastRoutes6.values()) {
-            bgpSession.addBgpRoute(bgpRouteEntry);
-        }
-
-        //
-        // Push the updates to the BGP Merged RIB
-        //
-        BgpRouteSelector bgpRouteSelector =
-            bgpSession.getBgpSessionManager().getBgpRouteSelector();
-        bgpRouteSelector.routeUpdates(bgpSession,
-                                decodedBgpRoutes.addedUnicastRoutes4.values(),
-                                decodedBgpRoutes.deletedUnicastRoutes4.values());
-        bgpRouteSelector.routeUpdates(bgpSession,
-                                decodedBgpRoutes.addedUnicastRoutes6.values(),
-                                decodedBgpRoutes.deletedUnicastRoutes6.values());
-
-        // Start the Session Timeout timer
-        bgpSession.restartSessionTimeoutTimer(ctx);
-    }
-
-    /**
-     * Parse BGP Path Attributes from the BGP UPDATE message.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param message the message to parse
-     * @param decodedBgpRoutes the container to store the decoded BGP Route
-     * Entries. It might already contain some route entries such as withdrawn
-     * IPv4 prefixes
-     * @throws BgpParseException
-     */
-    // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES
-    private static void parsePathAttributes(
-                                        BgpSession bgpSession,
-                                        ChannelHandlerContext ctx,
-                                        ChannelBuffer message,
-                                        DecodedBgpRoutes decodedBgpRoutes)
-        throws BgpParseException {
-
-        //
-        // Parsed values
-        //
-        Short origin = -1;                      // Mandatory
-        BgpRouteEntry.AsPath asPath = null;     // Mandatory
-        // Legacy NLRI (RFC 4271). Mandatory NEXT_HOP if legacy NLRI is used
-        MpNlri legacyNlri = new MpNlri(MultiprotocolExtensions.AFI_IPV4,
-                                       MultiprotocolExtensions.SAFI_UNICAST);
-        long multiExitDisc =                    // Optional
-            Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
-        Long localPref = null;                  // Mandatory
-        Long aggregatorAsNumber = null;         // Optional: unused
-        Ip4Address aggregatorIpAddress = null;  // Optional: unused
-        Collection<MpNlri> mpNlriReachList = new ArrayList<>();   // Optional
-        Collection<MpNlri> mpNlriUnreachList = new ArrayList<>(); // Optional
-
-        //
-        // Get and verify the Path Attributes Length
-        //
-        int pathAttributeLength = message.readUnsignedShort();
-        if (pathAttributeLength > message.readableBytes()) {
-            // ERROR: Malformed Attribute List
-            actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
-            String errorMsg = "Malformed Attribute List";
-            throw new BgpParseException(errorMsg);
-        }
-        if (pathAttributeLength == 0) {
-            return;
-        }
-
-        //
-        // Parse the Path Attributes
-        //
-        int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
-        while (message.readerIndex() < pathAttributeEnd) {
-            int attrFlags = message.readUnsignedByte();
-            if (message.readerIndex() >= pathAttributeEnd) {
-                // ERROR: Malformed Attribute List
-                actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
-                String errorMsg = "Malformed Attribute List";
-                throw new BgpParseException(errorMsg);
-            }
-            int attrTypeCode = message.readUnsignedByte();
-
-            // The Attribute Flags
-            boolean optionalBit =       ((0x80 & attrFlags) != 0);
-            boolean transitiveBit =     ((0x40 & attrFlags) != 0);
-            boolean partialBit =        ((0x20 & attrFlags) != 0);
-            boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
-
-            // The Attribute Length
-            int attrLen = 0;
-            int attrLenOctets = 1;
-            if (extendedLengthBit) {
-                attrLenOctets = 2;
-            }
-            if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
-                // ERROR: Malformed Attribute List
-                actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
-                String errorMsg = "Malformed Attribute List";
-                throw new BgpParseException(errorMsg);
-            }
-            if (extendedLengthBit) {
-                attrLen = message.readUnsignedShort();
-            } else {
-                attrLen = message.readUnsignedByte();
-            }
-            if (message.readerIndex() + attrLen > pathAttributeEnd) {
-                // ERROR: Malformed Attribute List
-                actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
-                String errorMsg = "Malformed Attribute List";
-                throw new BgpParseException(errorMsg);
-            }
-
-            // Verify the Attribute Flags
-            verifyBgpUpdateAttributeFlags(bgpSession, ctx, attrTypeCode,
-                                          attrLen, attrFlags, message);
-
-            //
-            // Extract the Attribute Value based on the Attribute Type Code
-            //
-            switch (attrTypeCode) {
-
-            case Update.Origin.TYPE:
-                // Attribute Type Code ORIGIN
-                origin = parseAttributeTypeOrigin(bgpSession, ctx,
-                                                  attrTypeCode, attrLen,
-                                                  attrFlags, message);
-                break;
-
-            case Update.AsPath.TYPE:
-                // Attribute Type Code AS_PATH
-                asPath = parseAttributeTypeAsPath(bgpSession, ctx,
-                                                  attrTypeCode, attrLen,
-                                                  attrFlags, message);
-                break;
-
-            case Update.NextHop.TYPE:
-                // Attribute Type Code NEXT_HOP
-                legacyNlri.nextHop4 =
-                    parseAttributeTypeNextHop(bgpSession, ctx,
-                                              attrTypeCode, attrLen,
-                                              attrFlags, message);
-                break;
-
-            case Update.MultiExitDisc.TYPE:
-                // Attribute Type Code MULTI_EXIT_DISC
-                multiExitDisc =
-                    parseAttributeTypeMultiExitDisc(bgpSession, ctx,
-                                                    attrTypeCode, attrLen,
-                                                    attrFlags, message);
-                break;
-
-            case Update.LocalPref.TYPE:
-                // Attribute Type Code LOCAL_PREF
-                localPref =
-                    parseAttributeTypeLocalPref(bgpSession, ctx,
-                                                attrTypeCode, attrLen,
-                                                attrFlags, message);
-                break;
-
-            case Update.AtomicAggregate.TYPE:
-                // Attribute Type Code ATOMIC_AGGREGATE
-                parseAttributeTypeAtomicAggregate(bgpSession, ctx,
-                                                  attrTypeCode, attrLen,
-                                                  attrFlags, message);
-                // Nothing to do: this attribute is primarily informational
-                break;
-
-            case Update.Aggregator.TYPE:
-                // Attribute Type Code AGGREGATOR
-                Pair<Long, Ip4Address> aggregator =
-                    parseAttributeTypeAggregator(bgpSession, ctx,
-                                                 attrTypeCode, attrLen,
-                                                 attrFlags, message);
-                aggregatorAsNumber = aggregator.getLeft();
-                aggregatorIpAddress = aggregator.getRight();
-                break;
-
-            case Update.MpReachNlri.TYPE:
-                // Attribute Type Code MP_REACH_NLRI
-                MpNlri mpNlriReach =
-                    parseAttributeTypeMpReachNlri(bgpSession, ctx,
-                                                  attrTypeCode,
-                                                  attrLen,
-                                                  attrFlags, message);
-                if (mpNlriReach != null) {
-                    mpNlriReachList.add(mpNlriReach);
-                }
-                break;
-
-            case Update.MpUnreachNlri.TYPE:
-                // Attribute Type Code MP_UNREACH_NLRI
-                MpNlri mpNlriUnreach =
-                    parseAttributeTypeMpUnreachNlri(bgpSession, ctx,
-                                                    attrTypeCode, attrLen,
-                                                    attrFlags, message);
-                if (mpNlriUnreach != null) {
-                    mpNlriUnreachList.add(mpNlriUnreach);
-                }
-                break;
-
-            default:
-                // NOTE: Parse any new Attribute Types if needed
-                if (!optionalBit) {
-                    // ERROR: Unrecognized Well-known Attribute
-                    actionsBgpUpdateUnrecognizedWellKnownAttribute(
-                        bgpSession, ctx, attrTypeCode, attrLen, attrFlags,
-                        message);
-                    String errorMsg = "Unrecognized Well-known Attribute: " +
-                        attrTypeCode;
-                    throw new BgpParseException(errorMsg);
-                }
-
-                // Skip the data from the unrecognized attribute
-                log.debug("BGP RX UPDATE message from {}: " +
-                          "Unrecognized Attribute Type {}",
-                          bgpSession.remoteInfo().address(), attrTypeCode);
-                message.skipBytes(attrLen);
-                break;
-            }
-        }
-
-        //
-        // Parse the NLRI (Network Layer Reachability Information)
-        //
-        int nlriLength = message.readableBytes();
-        try {
-            Collection<Ip4Prefix> addedPrefixes4 =
-                parsePackedIp4Prefixes(nlriLength, message);
-            // Store it inside the legacy NLRI wrapper
-            legacyNlri.nlri4 = addedPrefixes4;
-        } catch (BgpParseException e) {
-            // ERROR: Invalid Network Field
-            log.debug("Exception parsing NLRI from BGP peer {}: ",
-                      bgpSession.remoteInfo().bgpId(), e);
-            actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
-            // Rethrow the exception
-            throw e;
-        }
-
-        // Verify the Well-known Attributes
-        verifyBgpUpdateWellKnownAttributes(bgpSession, ctx, origin, asPath,
-                                           localPref, legacyNlri,
-                                           mpNlriReachList);
-
-        //
-        // Generate the deleted routes
-        //
-        for (MpNlri mpNlri : mpNlriUnreachList) {
-            BgpRouteEntry bgpRouteEntry;
-
-            // The deleted IPv4 routes
-            for (Ip4Prefix prefix : mpNlri.nlri4) {
-                bgpRouteEntry = bgpSession.findBgpRoute(prefix);
-                if (bgpRouteEntry != null) {
-                    decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
-                                                               bgpRouteEntry);
-                }
-            }
-
-            // The deleted IPv6 routes
-            for (Ip6Prefix prefix : mpNlri.nlri6) {
-                bgpRouteEntry = bgpSession.findBgpRoute(prefix);
-                if (bgpRouteEntry != null) {
-                    decodedBgpRoutes.deletedUnicastRoutes6.put(prefix,
-                                                               bgpRouteEntry);
-                }
-            }
-        }
-
-        //
-        // Generate the added routes
-        //
-        mpNlriReachList.add(legacyNlri);
-        for (MpNlri mpNlri : mpNlriReachList) {
-            BgpRouteEntry bgpRouteEntry;
-
-            // The added IPv4 routes
-            for (Ip4Prefix prefix : mpNlri.nlri4) {
-                bgpRouteEntry =
-                    new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop4,
-                                      origin.byteValue(), asPath, localPref);
-                bgpRouteEntry.setMultiExitDisc(multiExitDisc);
-                if (bgpRouteEntry.hasAsPathLoop(bgpSession.localInfo().asNumber())) {
-                    log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
-                              "nextHop {}: contains AS Path loop",
-                              bgpSession.remoteInfo().address(), prefix,
-                              mpNlri.nextHop4);
-                    continue;
-                } else {
-                    log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
-                              bgpSession.remoteInfo().address(), prefix,
-                              mpNlri.nextHop4);
-                }
-                // Remove from the collection of deleted routes
-                decodedBgpRoutes.deletedUnicastRoutes4.remove(prefix);
-                decodedBgpRoutes.addedUnicastRoutes4.put(prefix,
-                                                         bgpRouteEntry);
-            }
-
-            // The added IPv6 routes
-            for (Ip6Prefix prefix : mpNlri.nlri6) {
-                bgpRouteEntry =
-                    new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop6,
-                                      origin.byteValue(), asPath, localPref);
-                bgpRouteEntry.setMultiExitDisc(multiExitDisc);
-                if (bgpRouteEntry.hasAsPathLoop(bgpSession.localInfo().asNumber())) {
-                    log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
-                              "nextHop {}: contains AS Path loop",
-                              bgpSession.remoteInfo().address(), prefix,
-                              mpNlri.nextHop6);
-                    continue;
-                } else {
-                    log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
-                              bgpSession.remoteInfo().address(), prefix,
-                              mpNlri.nextHop6);
-                }
-                // Remove from the collection of deleted routes
-                decodedBgpRoutes.deletedUnicastRoutes6.remove(prefix);
-                decodedBgpRoutes.addedUnicastRoutes6.put(prefix,
-                                                         bgpRouteEntry);
-            }
-        }
-    }
-
-    /**
-     * Verifies BGP UPDATE Well-known Attributes.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param origin the ORIGIN well-known mandatory attribute
-     * @param asPath the AS_PATH well-known mandatory attribute
-     * @param localPref the LOCAL_PREF required attribute
-     * @param legacyNlri the legacy NLRI. Encapsulates the NEXT_HOP well-known
-     * mandatory attribute (mandatory if legacy NLRI is used).
-     * @param mpNlriReachList the Multiprotocol NLRI attributes
-     * @throws BgpParseException
-     */
-    private static void verifyBgpUpdateWellKnownAttributes(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                Short origin,
-                                BgpRouteEntry.AsPath asPath,
-                                Long localPref,
-                                MpNlri legacyNlri,
-                                Collection<MpNlri> mpNlriReachList)
-        throws BgpParseException {
-        boolean hasNlri = false;
-        boolean hasLegacyNlri = false;
-
-        //
-        // Convenience flags that are used to check for missing attributes.
-        //
-        // NOTE: The hasLegacyNlri flag is always set to true if the
-        // Multiprotocol Extensions are not enabled, even if the UPDATE
-        // message doesn't contain the legacy NLRI (per RFC 4271).
-        //
-        if (!bgpSession.mpExtensions()) {
-            hasNlri = true;
-            hasLegacyNlri = true;
-        } else {
-            if (!legacyNlri.nlri4.isEmpty()) {
-                hasNlri = true;
-                hasLegacyNlri = true;
-            }
-            if (!mpNlriReachList.isEmpty()) {
-                hasNlri = true;
-            }
-        }
-
-        //
-        // Check for Missing Well-known Attributes
-        //
-        if (hasNlri && ((origin == null) || (origin == -1))) {
-            // Missing Attribute Type Code ORIGIN
-            int type = Update.Origin.TYPE;
-            actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
-            String errorMsg = "Missing Well-known Attribute: ORIGIN";
-            throw new BgpParseException(errorMsg);
-        }
-        if (hasNlri && (asPath == null)) {
-            // Missing Attribute Type Code AS_PATH
-            int type = Update.AsPath.TYPE;
-            actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
-            String errorMsg = "Missing Well-known Attribute: AS_PATH";
-            throw new BgpParseException(errorMsg);
-        }
-        if (hasNlri && (localPref == null)) {
-            // Missing Attribute Type Code LOCAL_PREF
-            // NOTE: Required for iBGP
-            int type = Update.LocalPref.TYPE;
-            actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
-            String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
-            throw new BgpParseException(errorMsg);
-        }
-        if (hasLegacyNlri && (legacyNlri.nextHop4 == null)) {
-            // Missing Attribute Type Code NEXT_HOP
-            int type = Update.NextHop.TYPE;
-            actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
-            String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
-            throw new BgpParseException(errorMsg);
-        }
-    }
-
-    /**
-     * Verifies the BGP UPDATE Attribute Flags.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @throws BgpParseException
-     */
-    private static void verifyBgpUpdateAttributeFlags(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message)
-        throws BgpParseException {
-
-        //
-        // Assign the Attribute Type Name and the Well-known flag
-        //
-        String typeName = "UNKNOWN";
-        boolean isWellKnown = false;
-        switch (attrTypeCode) {
-        case Update.Origin.TYPE:
-            isWellKnown = true;
-            typeName = "ORIGIN";
-            break;
-        case Update.AsPath.TYPE:
-            isWellKnown = true;
-            typeName = "AS_PATH";
-            break;
-        case Update.NextHop.TYPE:
-            isWellKnown = true;
-            typeName = "NEXT_HOP";
-            break;
-        case Update.MultiExitDisc.TYPE:
-            isWellKnown = false;
-            typeName = "MULTI_EXIT_DISC";
-            break;
-        case Update.LocalPref.TYPE:
-            isWellKnown = true;
-            typeName = "LOCAL_PREF";
-            break;
-        case Update.AtomicAggregate.TYPE:
-            isWellKnown = true;
-            typeName = "ATOMIC_AGGREGATE";
-            break;
-        case Update.Aggregator.TYPE:
-            isWellKnown = false;
-            typeName = "AGGREGATOR";
-            break;
-        case Update.MpReachNlri.TYPE:
-            isWellKnown = false;
-            typeName = "MP_REACH_NLRI";
-            break;
-        case Update.MpUnreachNlri.TYPE:
-            isWellKnown = false;
-            typeName = "MP_UNREACH_NLRI";
-            break;
-        default:
-            isWellKnown = false;
-            typeName = "UNKNOWN(" + attrTypeCode + ")";
-            break;
-        }
-
-        //
-        // Verify the Attribute Flags
-        //
-        boolean optionalBit =       ((0x80 & attrFlags) != 0);
-        boolean transitiveBit =     ((0x40 & attrFlags) != 0);
-        boolean partialBit =        ((0x20 & attrFlags) != 0);
-        if ((isWellKnown && optionalBit) ||
-            (isWellKnown && (!transitiveBit)) ||
-            (isWellKnown && partialBit) ||
-            (optionalBit && (!transitiveBit) && partialBit)) {
-            //
-            // ERROR: The Optional bit cannot be set for Well-known attributes
-            // ERROR: The Transtive bit MUST be 1 for well-known attributes
-            // ERROR: The Partial bit MUST be 0 for well-known attributes
-            // ERROR: The Partial bit MUST be 0 for optional non-transitive
-            //        attributes
-            //
-            actionsBgpUpdateAttributeFlagsError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Flags Error for " + typeName + ": " +
-                attrFlags;
-            throw new BgpParseException(errorMsg);
-        }
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type ORIGIN.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed ORIGIN value
-     * @throws BgpParseException
-     */
-    private static short parseAttributeTypeOrigin(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message)
-        throws BgpParseException {
-
-        // Check the Attribute Length
-        if (attrLen != Update.Origin.LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        message.markReaderIndex();
-        short origin = message.readUnsignedByte();
-        switch (origin) {
-        case Update.Origin.IGP:
-            // FALLTHROUGH
-        case Update.Origin.EGP:
-            // FALLTHROUGH
-        case Update.Origin.INCOMPLETE:
-            break;
-        default:
-            // ERROR: Invalid ORIGIN Attribute
-            message.resetReaderIndex();
-            actionsBgpUpdateInvalidOriginAttribute(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
-                origin);
-            String errorMsg = "Invalid ORIGIN Attribute: " + origin;
-            throw new BgpParseException(errorMsg);
-        }
-
-        return origin;
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute AS Path.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed AS Path
-     * @throws BgpParseException
-     */
-    private static BgpRouteEntry.AsPath parseAttributeTypeAsPath(
-                                                BgpSession bgpSession,
-                                                ChannelHandlerContext ctx,
-                                                int attrTypeCode,
-                                                int attrLen,
-                                                int attrFlags,
-                                                ChannelBuffer message)
-        throws BgpParseException {
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-
-        //
-        // Parse the message
-        //
-        while (attrLen > 0) {
-            if (attrLen < 2) {
-                // ERROR: Malformed AS_PATH
-                actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
-                String errorMsg = "Malformed AS Path";
-                throw new BgpParseException(errorMsg);
-            }
-            // Get the Path Segment Type and Length (in number of ASes)
-            short pathSegmentType = message.readUnsignedByte();
-            short pathSegmentLength = message.readUnsignedByte();
-            attrLen -= 2;
-
-            // Verify the Path Segment Type
-            switch (pathSegmentType) {
-            case Update.AsPath.AS_SET:
-                // FALLTHROUGH
-            case Update.AsPath.AS_SEQUENCE:
-                // FALLTHROUGH
-            case Update.AsPath.AS_CONFED_SEQUENCE:
-                // FALLTHROUGH
-            case Update.AsPath.AS_CONFED_SET:
-                break;
-            default:
-                // ERROR: Invalid Path Segment Type
-                //
-                // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
-                // for "Invalid Path Segment Type", hence we return
-                // the error as "Malformed AS_PATH".
-                //
-                actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
-                String errorMsg =
-                    "Invalid AS Path Segment Type: " + pathSegmentType;
-                throw new BgpParseException(errorMsg);
-            }
-
-            // 4-octet AS number handling.
-            int asPathLen;
-            if (bgpSession.isAs4OctetCapable()) {
-                asPathLen = AsPath.AS_4OCTET_LENGTH;
-            } else {
-                asPathLen = AsPath.AS_LENGTH;
-            }
-
-            // Parse the AS numbers
-            if (asPathLen * pathSegmentLength > attrLen) {
-                // ERROR: Malformed AS_PATH
-                actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
-                String errorMsg = "Malformed AS Path";
-                throw new BgpParseException(errorMsg);
-            }
-            attrLen -= (asPathLen * pathSegmentLength);
-            ArrayList<Long> segmentAsNumbers = new ArrayList<>();
-            while (pathSegmentLength-- > 0) {
-                long asNumber;
-                if (asPathLen == AsPath.AS_4OCTET_LENGTH) {
-                    asNumber = message.readUnsignedInt();
-                } else {
-                    asNumber = message.readUnsignedShort();
-                }
-                segmentAsNumbers.add(asNumber);
-            }
-
-            BgpRouteEntry.PathSegment pathSegment =
-                new BgpRouteEntry.PathSegment((byte) pathSegmentType,
-                                              segmentAsNumbers);
-            pathSegments.add(pathSegment);
-        }
-
-        return new BgpRouteEntry.AsPath(pathSegments);
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type NEXT_HOP.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed NEXT_HOP value
-     * @throws BgpParseException
-     */
-    private static Ip4Address parseAttributeTypeNextHop(
-                                        BgpSession bgpSession,
-                                        ChannelHandlerContext ctx,
-                                        int attrTypeCode,
-                                        int attrLen,
-                                        int attrFlags,
-                                        ChannelBuffer message)
-        throws BgpParseException {
-
-        // Check the Attribute Length
-        if (attrLen != Update.NextHop.LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        message.markReaderIndex();
-        Ip4Address nextHopAddress =
-            Ip4Address.valueOf((int) message.readUnsignedInt());
-        //
-        // Check whether the NEXT_HOP IP address is semantically correct.
-        // As per RFC 4271, Section 6.3:
-        //
-        //  a) It MUST NOT be the IP address of the receiving speaker
-        //  b) In the case of an EBGP ....
-        //
-        // Here we check only (a), because (b) doesn't apply for us: all our
-        // peers are iBGP.
-        //
-        if (nextHopAddress.equals(bgpSession.localInfo().ip4Address())) {
-            // ERROR: Invalid NEXT_HOP Attribute
-            message.resetReaderIndex();
-            actionsBgpUpdateInvalidNextHopAttribute(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
-                nextHopAddress);
-            String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
-            throw new BgpParseException(errorMsg);
-        }
-
-        return nextHopAddress;
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed MULTI_EXIT_DISC value
-     * @throws BgpParseException
-     */
-    private static long parseAttributeTypeMultiExitDisc(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message)
-        throws BgpParseException {
-
-        // Check the Attribute Length
-        if (attrLen != Update.MultiExitDisc.LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        long multiExitDisc = message.readUnsignedInt();
-        return multiExitDisc;
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type LOCAL_PREF.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed LOCAL_PREF value
-     * @throws BgpParseException
-     */
-    private static long parseAttributeTypeLocalPref(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message)
-        throws BgpParseException {
-
-        // Check the Attribute Length
-        if (attrLen != Update.LocalPref.LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        long localPref = message.readUnsignedInt();
-        return localPref;
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @throws BgpParseException
-     */
-    private static void parseAttributeTypeAtomicAggregate(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message)
-        throws BgpParseException {
-
-        // Check the Attribute Length
-        if (attrLen != Update.AtomicAggregate.LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        // Nothing to do: this attribute is primarily informational
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type AGGREGATOR.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
-     * @throws BgpParseException
-     */
-    private static Pair<Long, Ip4Address> parseAttributeTypeAggregator(
-                                                BgpSession bgpSession,
-                                                ChannelHandlerContext ctx,
-                                                int attrTypeCode,
-                                                int attrLen,
-                                                int attrFlags,
-                                                ChannelBuffer message)
-        throws BgpParseException {
-
-        // Check the Attribute Length
-        if (attrLen != Update.Aggregator.LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        // The AGGREGATOR AS number
-        long aggregatorAsNumber = message.readUnsignedShort();
-        // The AGGREGATOR IP address
-        Ip4Address aggregatorIpAddress =
-            Ip4Address.valueOf((int) message.readUnsignedInt());
-
-        Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
-                                                    aggregatorIpAddress);
-        return aggregator;
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type MP_REACH_NLRI.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed MP_REACH_NLRI information if recognized, otherwise
-     * null
-     * @throws BgpParseException
-     */
-    private static MpNlri parseAttributeTypeMpReachNlri(
-                                                BgpSession bgpSession,
-                                                ChannelHandlerContext ctx,
-                                                int attrTypeCode,
-                                                int attrLen,
-                                                int attrFlags,
-                                                ChannelBuffer message)
-        throws BgpParseException {
-        int attributeEnd = message.readerIndex() + attrLen;
-
-        // Check the Attribute Length
-        if (attrLen < Update.MpReachNlri.MIN_LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        message.markReaderIndex();
-        int afi = message.readUnsignedShort();
-        int safi = message.readUnsignedByte();
-        int nextHopLen = message.readUnsignedByte();
-
-        //
-        // Verify the AFI/SAFI, and skip the attribute if not recognized.
-        // NOTE: Currently, we support only IPv4/IPv6 UNICAST
-        //
-        if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
-             (afi != MultiprotocolExtensions.AFI_IPV6)) ||
-            (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
-            // Skip the attribute
-            message.resetReaderIndex();
-            message.skipBytes(attrLen);
-            return null;
-        }
-
-        //
-        // Verify the next-hop length
-        //
-        int expectedNextHopLen = 0;
-        switch (afi) {
-        case MultiprotocolExtensions.AFI_IPV4:
-            expectedNextHopLen = Ip4Address.BYTE_LENGTH;
-            break;
-        case MultiprotocolExtensions.AFI_IPV6:
-            expectedNextHopLen = Ip6Address.BYTE_LENGTH;
-            break;
-        default:
-            // UNREACHABLE
-            break;
-        }
-        if (nextHopLen != expectedNextHopLen) {
-            // ERROR: Optional Attribute Error
-            message.resetReaderIndex();
-            actionsBgpUpdateOptionalAttributeError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Invalid next-hop network address length. " +
-                "Received " + nextHopLen + " expected " + expectedNextHopLen;
-            throw new BgpParseException(errorMsg);
-        }
-        // NOTE: We use "+ 1" to take into account the Reserved field (1 octet)
-        if (message.readerIndex() + nextHopLen + 1 >= attributeEnd) {
-            // ERROR: Optional Attribute Error
-            message.resetReaderIndex();
-            actionsBgpUpdateOptionalAttributeError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Malformed next-hop network address";
-            throw new BgpParseException(errorMsg);
-        }
-
-        //
-        // Get the Next-hop address, skip the Reserved field, and get the NLRI
-        //
-        byte[] nextHopBuffer = new byte[nextHopLen];
-        message.readBytes(nextHopBuffer, 0, nextHopLen);
-        int reserved = message.readUnsignedByte();
-        MpNlri mpNlri = new MpNlri(afi, safi);
-        try {
-            switch (afi) {
-            case MultiprotocolExtensions.AFI_IPV4:
-                // The next-hop address
-                mpNlri.nextHop4 = Ip4Address.valueOf(nextHopBuffer);
-                // The NLRI
-                mpNlri.nlri4 = parsePackedIp4Prefixes(
-                                        attributeEnd - message.readerIndex(),
-                                        message);
-                break;
-            case MultiprotocolExtensions.AFI_IPV6:
-                // The next-hop address
-                mpNlri.nextHop6 = Ip6Address.valueOf(nextHopBuffer);
-                // The NLRI
-                mpNlri.nlri6 = parsePackedIp6Prefixes(
-                                        attributeEnd - message.readerIndex(),
-                                        message);
-                break;
-            default:
-                // UNREACHABLE
-                break;
-            }
-        } catch (BgpParseException e) {
-            // ERROR: Optional Attribute Error
-            message.resetReaderIndex();
-            actionsBgpUpdateOptionalAttributeError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Malformed network layer reachability information";
-            throw new BgpParseException(errorMsg);
-        }
-
-        return mpNlri;
-    }
-
-    /**
-     * Parses BGP UPDATE Attribute Type MP_UNREACH_NLRI.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message to parse
-     * @return the parsed MP_UNREACH_NLRI information if recognized, otherwise
-     * null
-     * @throws BgpParseException
-     */
-    private static MpNlri parseAttributeTypeMpUnreachNlri(
-                                                BgpSession bgpSession,
-                                                ChannelHandlerContext ctx,
-                                                int attrTypeCode,
-                                                int attrLen,
-                                                int attrFlags,
-                                                ChannelBuffer message)
-        throws BgpParseException {
-        int attributeEnd = message.readerIndex() + attrLen;
-
-        // Check the Attribute Length
-        if (attrLen < Update.MpUnreachNlri.MIN_LENGTH) {
-            // ERROR: Attribute Length Error
-            actionsBgpUpdateAttributeLengthError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Attribute Length Error";
-            throw new BgpParseException(errorMsg);
-        }
-
-        message.markReaderIndex();
-        int afi = message.readUnsignedShort();
-        int safi = message.readUnsignedByte();
-
-        //
-        // Verify the AFI/SAFI, and skip the attribute if not recognized.
-        // NOTE: Currently, we support only IPv4/IPv6 UNICAST
-        //
-        if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
-             (afi != MultiprotocolExtensions.AFI_IPV6)) ||
-            (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
-            // Skip the attribute
-            message.resetReaderIndex();
-            message.skipBytes(attrLen);
-            return null;
-        }
-
-        //
-        // Get the Withdrawn Routes
-        //
-        MpNlri mpNlri = new MpNlri(afi, safi);
-        try {
-            switch (afi) {
-            case MultiprotocolExtensions.AFI_IPV4:
-                // The Withdrawn Routes
-                mpNlri.nlri4 = parsePackedIp4Prefixes(
-                                        attributeEnd - message.readerIndex(),
-                                        message);
-                break;
-            case MultiprotocolExtensions.AFI_IPV6:
-                // The Withdrawn Routes
-                mpNlri.nlri6 = parsePackedIp6Prefixes(
-                                        attributeEnd - message.readerIndex(),
-                                        message);
-                break;
-            default:
-                // UNREACHABLE
-                break;
-            }
-        } catch (BgpParseException e) {
-            // ERROR: Optional Attribute Error
-            message.resetReaderIndex();
-            actionsBgpUpdateOptionalAttributeError(
-                bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
-            String errorMsg = "Malformed withdrawn routes";
-            throw new BgpParseException(errorMsg);
-        }
-
-        return mpNlri;
-    }
-
-    /**
-     * Parses a message that contains encoded IPv4 network prefixes.
-     * <p>
-     * The IPv4 prefixes are encoded in the form:
-     * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
-     * and Prefix is the IPv4 prefix (padded with trailing bits to the end
-     * of an octet).
-     *
-     * @param totalLength the total length of the data to parse
-     * @param message the message with data to parse
-     * @return a collection of parsed IPv4 network prefixes
-     * @throws BgpParseException
-     */
-    private static Collection<Ip4Prefix> parsePackedIp4Prefixes(
-                                                int totalLength,
-                                                ChannelBuffer message)
-        throws BgpParseException {
-        Collection<Ip4Prefix> result = new ArrayList<>();
-
-        if (totalLength == 0) {
-            return result;
-        }
-
-        // Parse the data
-        byte[] buffer = new byte[Ip4Address.BYTE_LENGTH];
-        int dataEnd = message.readerIndex() + totalLength;
-        while (message.readerIndex() < dataEnd) {
-            int prefixBitlen = message.readUnsignedByte();
-            int prefixBytelen = (prefixBitlen + 7) / 8;     // Round-up
-            if (message.readerIndex() + prefixBytelen > dataEnd) {
-                String errorMsg = "Malformed Network Prefixes";
-                throw new BgpParseException(errorMsg);
-            }
-
-            message.readBytes(buffer, 0, prefixBytelen);
-            Ip4Prefix prefix = Ip4Prefix.valueOf(Ip4Address.valueOf(buffer),
-                                                 prefixBitlen);
-            result.add(prefix);
-        }
-
-        return result;
-    }
-
-    /**
-     * Parses a message that contains encoded IPv6 network prefixes.
-     * <p>
-     * The IPv6 prefixes are encoded in the form:
-     * <Length, Prefix> where Length is the length in bits of the IPv6 prefix,
-     * and Prefix is the IPv6 prefix (padded with trailing bits to the end
-     * of an octet).
-     *
-     * @param totalLength the total length of the data to parse
-     * @param message the message with data to parse
-     * @return a collection of parsed IPv6 network prefixes
-     * @throws BgpParseException
-     */
-    private static Collection<Ip6Prefix> parsePackedIp6Prefixes(
-                                                int totalLength,
-                                                ChannelBuffer message)
-        throws BgpParseException {
-        Collection<Ip6Prefix> result = new ArrayList<>();
-
-        if (totalLength == 0) {
-            return result;
-        }
-
-        // Parse the data
-        byte[] buffer = new byte[Ip6Address.BYTE_LENGTH];
-        int dataEnd = message.readerIndex() + totalLength;
-        while (message.readerIndex() < dataEnd) {
-            int prefixBitlen = message.readUnsignedByte();
-            int prefixBytelen = (prefixBitlen + 7) / 8;     // Round-up
-            if (message.readerIndex() + prefixBytelen > dataEnd) {
-                String errorMsg = "Malformed Network Prefixes";
-                throw new BgpParseException(errorMsg);
-            }
-
-            message.readBytes(buffer, 0, prefixBytelen);
-            Ip6Prefix prefix = Ip6Prefix.valueOf(Ip6Address.valueOf(buffer),
-                                                 prefixBitlen);
-            result.add(prefix);
-        }
-
-        return result;
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Invalid Network Field Error: send NOTIFICATION and close the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     */
-    private static void actionsBgpUpdateInvalidNetworkField(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx) {
-        log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
-                  bgpSession.remoteInfo().address());
-
-        //
-        // ERROR: Invalid Network Field
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   null);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Malformed Attribute List Error: send NOTIFICATION and close the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     */
-    private static void actionsBgpUpdateMalformedAttributeList(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx) {
-        log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
-                  bgpSession.remoteInfo().address());
-
-        //
-        // ERROR: Malformed Attribute List
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   null);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Missing Well-known Attribute Error: send NOTIFICATION and close the
-     * channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param missingAttrTypeCode the missing attribute type code
-     */
-    private static void actionsBgpUpdateMissingWellKnownAttribute(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int missingAttrTypeCode) {
-        log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
-                  bgpSession.remoteInfo().address(), missingAttrTypeCode);
-
-        //
-        // ERROR: Missing Well-known Attribute
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
-        ChannelBuffer data = ChannelBuffers.buffer(1);
-        data.writeByte(missingAttrTypeCode);
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   data);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message with the data
-     * @param origin the ORIGIN attribute value
-     */
-    private static void actionsBgpUpdateInvalidOriginAttribute(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message,
-                                short origin) {
-        log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
-                  bgpSession.remoteInfo().address());
-
-        //
-        // ERROR: Invalid ORIGIN Attribute
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
-        ChannelBuffer data =
-            prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
-                                                    attrFlags, message);
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   data);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Attribute Flags Error: send NOTIFICATION and close the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message with the data
-     */
-    private static void actionsBgpUpdateAttributeFlagsError(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message) {
-        log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
-                  bgpSession.remoteInfo().address());
-
-        //
-        // ERROR: Attribute Flags Error
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
-        ChannelBuffer data =
-            prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
-                                                    attrFlags, message);
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   data);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
-     * channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message with the data
-     * @param nextHop the NEXT_HOP attribute value
-     */
-    private static void actionsBgpUpdateInvalidNextHopAttribute(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message,
-                                Ip4Address nextHop) {
-        log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
-                  bgpSession.remoteInfo().address(), nextHop);
-
-        //
-        // ERROR: Invalid NEXT_HOP Attribute
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
-        ChannelBuffer data =
-            prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
-                                                    attrFlags, message);
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   data);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
-     * the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message with the data
-     */
-    private static void actionsBgpUpdateUnrecognizedWellKnownAttribute(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message) {
-        log.debug("BGP RX UPDATE Error from {}: " +
-                  "Unrecognized Well-known Attribute Error: {}",
-                  bgpSession.remoteInfo().address(), attrTypeCode);
-
-        //
-        // ERROR: Unrecognized Well-known Attribute
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode =
-            UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
-        ChannelBuffer data =
-            prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
-                                                    attrFlags, message);
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   data);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Optional Attribute Error: send NOTIFICATION and close
-     * the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message with the data
-     */
-    private static void actionsBgpUpdateOptionalAttributeError(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message) {
-        log.debug("BGP RX UPDATE Error from {}: Optional Attribute Error: {}",
-                  bgpSession.remoteInfo().address(), attrTypeCode);
-
-        //
-        // ERROR: Optional Attribute Error
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode =
-            UpdateMessageError.OPTIONAL_ATTRIBUTE_ERROR;
-        ChannelBuffer data =
-            prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
-                                                    attrFlags, message);
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   data);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Attribute Length Error: send NOTIFICATION and close the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message with the data
-     */
-    private static void actionsBgpUpdateAttributeLengthError(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx,
-                                int attrTypeCode,
-                                int attrLen,
-                                int attrFlags,
-                                ChannelBuffer message) {
-        log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
-                  bgpSession.remoteInfo().address());
-
-        //
-        // ERROR: Attribute Length Error
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
-        ChannelBuffer data =
-            prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
-                                                    attrFlags, message);
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   data);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Applies the appropriate actions after detecting BGP UPDATE
-     * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
-     *
-     * @param bgpSession the BGP Session to use
-     * @param ctx the Channel Handler Context
-     */
-    private static void actionsBgpUpdateMalformedAsPath(
-                                BgpSession bgpSession,
-                                ChannelHandlerContext ctx) {
-        log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
-                  bgpSession.remoteInfo().address());
-
-        //
-        // ERROR: Malformed AS_PATH
-        //
-        // Send NOTIFICATION and close the connection
-        int errorCode = UpdateMessageError.ERROR_CODE;
-        int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
-        ChannelBuffer txMessage =
-            BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
-                                                   null);
-        ctx.getChannel().write(txMessage);
-        bgpSession.closeSession(ctx);
-    }
-
-    /**
-     * Prepares BGP UPDATE Notification data payload.
-     *
-     * @param attrTypeCode the attribute type code
-     * @param attrLen the attribute length (in octets)
-     * @param attrFlags the attribute flags
-     * @param message the message with the data
-     * @return the buffer with the data payload for the BGP UPDATE Notification
-     */
-    private static ChannelBuffer prepareBgpUpdateNotificationDataPayload(
-                                        int attrTypeCode,
-                                        int attrLen,
-                                        int attrFlags,
-                                        ChannelBuffer message) {
-        // Compute the attribute length field octets
-        boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
-        int attrLenOctets = 1;
-        if (extendedLengthBit) {
-            attrLenOctets = 2;
-        }
-        ChannelBuffer data =
-            ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
-        data.writeByte(attrTypeCode);
-        if (extendedLengthBit) {
-            data.writeShort(attrLen);
-        } else {
-            data.writeByte(attrLen);
-        }
-        data.writeBytes(message, attrLen);
-        return data;
-    }
-
-    /**
-     * Helper class for storing Multiprotocol Network Layer Reachability
-     * information.
-     */
-    private static final class MpNlri {
-        private final int afi;
-        private final int safi;
-        private Ip4Address nextHop4;
-        private Ip6Address nextHop6;
-        private Collection<Ip4Prefix> nlri4 = new ArrayList<>();
-        private Collection<Ip6Prefix> nlri6 = new ArrayList<>();
-
-        /**
-         * Constructor.
-         *
-         * @param afi the Address Family Identifier
-         * @param safi the Subsequent Address Family Identifier
-         */
-        private MpNlri(int afi, int safi) {
-            this.afi = afi;
-            this.safi = safi;
-        }
-    }
-
-    /**
-     * Helper class for storing decoded BGP routing information.
-     */
-    private static final class DecodedBgpRoutes {
-        private final Map<Ip4Prefix, BgpRouteEntry> addedUnicastRoutes4 =
-            new HashMap<>();
-        private final Map<Ip6Prefix, BgpRouteEntry> addedUnicastRoutes6 =
-            new HashMap<>();
-        private final Map<Ip4Prefix, BgpRouteEntry> deletedUnicastRoutes4 =
-            new HashMap<>();
-        private final Map<Ip6Prefix, BgpRouteEntry> deletedUnicastRoutes6 =
-            new HashMap<>();
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/package-info.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/package-info.java
deleted file mode 100644
index 9e1b5d2..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Implementation of the BGP protocol.
- */
-package org.onosproject.sdnip.bgp;
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpNeighborsListCommand.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpNeighborsListCommand.java
deleted file mode 100644
index fe2a4a4..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpNeighborsListCommand.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.cli;
-
-import java.util.Collection;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.sdnip.SdnIpService;
-import org.onosproject.sdnip.bgp.BgpSession;
-
-/**
- * Command to show the BGP neighbors.
- */
-@Command(scope = "onos", name = "bgp-neighbors",
-         description = "Lists the BGP neighbors")
-public class BgpNeighborsListCommand extends AbstractShellCommand {
-    @Option(name = "-n", aliases = "--neighbor",
-            description = "BGP neighbor to display information about",
-            required = false, multiValued = false)
-    private String bgpNeighbor;
-
-    private static final String FORMAT_NEIGHBOR_LINE1 =
-        "BGP neighbor is %s, remote AS %d, local AS %d";
-    private static final String FORMAT_NEIGHBOR_LINE2 =
-        "  Remote router ID %s, IP %s, BGP version %d, Hold time %d";
-    private static final String FORMAT_NEIGHBOR_LINE3 =
-        "  Remote AFI/SAFI IPv4 Unicast %s Multicast %s, IPv6 Unicast %s Multicast %s";
-    private static final String FORMAT_NEIGHBOR_LINE4 =
-        "  Local  router ID %s, IP %s, BGP version %d, Hold time %d";
-    private static final String FORMAT_NEIGHBOR_LINE5 =
-        "  Local  AFI/SAFI IPv4 Unicast %s Multicast %s, IPv6 Unicast %s Multicast %s";
-    private static final String FORMAT_NEIGHBOR_LINE6 =
-        "  4 Octet AS Capability: %s %s";
-
-    @Override
-    protected void execute() {
-        SdnIpService service = get(SdnIpService.class);
-        Collection<BgpSession> bgpSessions = service.getBgpSessions();
-
-        if (bgpNeighbor != null) {
-            // Print a single neighbor (if found)
-            BgpSession foundBgpSession = null;
-            for (BgpSession bgpSession : bgpSessions) {
-                if (bgpSession.remoteInfo().bgpId().toString().equals(bgpNeighbor)) {
-                    foundBgpSession = bgpSession;
-                    break;
-                }
-            }
-            if (foundBgpSession != null) {
-                printNeighbor(foundBgpSession);
-            } else {
-                print("BGP neighbor %s not found", bgpNeighbor);
-            }
-            return;
-        }
-
-        // Print all neighbors
-        printNeighbors(bgpSessions);
-    }
-
-    /**
-     * Prints all BGP neighbors.
-     *
-     * @param bgpSessions the BGP sessions for the neighbors to print
-     */
-    private void printNeighbors(Collection<BgpSession> bgpSessions) {
-        if (outputJson()) {
-            print("%s", json(bgpSessions));
-        } else {
-            for (BgpSession bgpSession : bgpSessions) {
-                printNeighbor(bgpSession);
-            }
-        }
-    }
-
-    /**
-     * Prints a BGP neighbor.
-     *
-     * @param bgpSession the BGP session for the neighbor to print
-     */
-    private void printNeighbor(BgpSession bgpSession) {
-        print(FORMAT_NEIGHBOR_LINE1,
-              bgpSession.remoteInfo().bgpId().toString(),
-              bgpSession.remoteInfo().asNumber(),
-              bgpSession.localInfo().asNumber());
-        print(FORMAT_NEIGHBOR_LINE2,
-              bgpSession.remoteInfo().bgpId().toString(),
-              bgpSession.remoteInfo().address().toString(),
-              bgpSession.remoteInfo().bgpVersion(),
-              bgpSession.remoteInfo().holdtime());
-        print(FORMAT_NEIGHBOR_LINE3,
-              bgpSession.remoteInfo().ipv4Unicast() ? "YES" : "NO",
-              bgpSession.remoteInfo().ipv4Multicast() ? "YES" : "NO",
-              bgpSession.remoteInfo().ipv6Unicast() ? "YES" : "NO",
-              bgpSession.remoteInfo().ipv6Multicast() ? "YES" : "NO");
-        print(FORMAT_NEIGHBOR_LINE4,
-              bgpSession.localInfo().bgpId().toString(),
-              bgpSession.localInfo().address().toString(),
-              bgpSession.localInfo().bgpVersion(),
-              bgpSession.localInfo().holdtime());
-        print(FORMAT_NEIGHBOR_LINE5,
-              bgpSession.localInfo().ipv4Unicast() ? "YES" : "NO",
-              bgpSession.localInfo().ipv4Multicast() ? "YES" : "NO",
-              bgpSession.localInfo().ipv6Unicast() ? "YES" : "NO",
-              bgpSession.localInfo().ipv6Multicast() ? "YES" : "NO");
-        if (bgpSession.localInfo().as4OctetCapability() ||
-            bgpSession.remoteInfo().as4OctetCapability()) {
-            print(FORMAT_NEIGHBOR_LINE6,
-                  bgpSession.localInfo().as4OctetCapability() ? "Advertised" : "",
-                  bgpSession.remoteInfo().as4OctetCapability() ? "Received" : "");
-        }
-    }
-
-    /**
-     * Produces a JSON array of BGP neighbors.
-     *
-     * @param bgpSessions the BGP sessions with the data
-     * @return JSON array with the neighbors
-     */
-    private JsonNode json(Collection<BgpSession> bgpSessions) {
-        ObjectMapper mapper = new ObjectMapper();
-        ArrayNode result = mapper.createArrayNode();
-
-        for (BgpSession bgpSession : bgpSessions) {
-            result.add(json(mapper, bgpSession));
-        }
-        return result;
-    }
-
-    /**
-     * Produces JSON object for a BGP neighbor.
-     *
-     * @param mapper the JSON object mapper to use
-     * @param bgpSession the BGP session with the data
-     * @return JSON object for the route
-     */
-    private ObjectNode json(ObjectMapper mapper, BgpSession bgpSession) {
-        ObjectNode result = mapper.createObjectNode();
-
-        result.put("remoteAddress", bgpSession.remoteInfo().address().toString());
-        result.put("remoteBgpVersion", bgpSession.remoteInfo().bgpVersion());
-        result.put("remoteAs", bgpSession.remoteInfo().asNumber());
-        result.put("remoteAs4", bgpSession.remoteInfo().as4Number());
-        result.put("remoteHoldtime", bgpSession.remoteInfo().holdtime());
-        result.put("remoteBgpId", bgpSession.remoteInfo().bgpId().toString());
-        result.put("remoteIpv4Unicast", bgpSession.remoteInfo().ipv4Unicast());
-        result.put("remoteIpv4Multicast", bgpSession.remoteInfo().ipv4Multicast());
-        result.put("remoteIpv6Unicast", bgpSession.remoteInfo().ipv6Unicast());
-        result.put("remoteIpv6Multicast", bgpSession.remoteInfo().ipv6Multicast());
-        //
-        result.put("localAddress", bgpSession.localInfo().address().toString());
-        result.put("localBgpVersion", bgpSession.localInfo().bgpVersion());
-        result.put("localAs", bgpSession.localInfo().asNumber());
-        result.put("localAs4", bgpSession.localInfo().as4Number());
-        result.put("localHoldtime", bgpSession.localInfo().holdtime());
-        result.put("localBgpId", bgpSession.localInfo().bgpId().toString());
-        result.put("localIpv4Unicast", bgpSession.localInfo().ipv4Unicast());
-        result.put("localIpv4Multicast", bgpSession.localInfo().ipv4Multicast());
-        result.put("localIpv6Unicast", bgpSession.localInfo().ipv6Unicast());
-        result.put("localIpv6Multicast", bgpSession.localInfo().ipv6Multicast());
-
-        return result;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpRoutesListCommand.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpRoutesListCommand.java
deleted file mode 100644
index a3b19df..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpRoutesListCommand.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.cli;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.sdnip.SdnIpService;
-import org.onosproject.sdnip.bgp.BgpConstants.Update;
-import org.onosproject.sdnip.bgp.BgpRouteEntry;
-import org.onosproject.sdnip.bgp.BgpSession;
-
-/**
- * Command to show the routes learned through BGP.
- */
-@Command(scope = "onos", name = "bgp-routes",
-         description = "Lists all BGP best routes")
-public class BgpRoutesListCommand extends AbstractShellCommand {
-    @Option(name = "-s", aliases = "--summary",
-            description = "BGP routes summary",
-            required = false, multiValued = false)
-    private boolean routesSummary = false;
-
-    @Option(name = "-n", aliases = "--neighbor",
-            description = "Routes from a BGP neighbor",
-            required = false, multiValued = false)
-    private String bgpNeighbor;
-
-    private static final String FORMAT_SUMMARY_V4 =
-        "Total BGP IPv4 routes = %d";
-    private static final String FORMAT_SUMMARY_V6 =
-        "Total BGP IPv6 routes = %d";
-    private static final String FORMAT_HEADER =
-        "   Network            Next Hop        Origin LocalPref       MED BGP-ID";
-    private static final String FORMAT_ROUTE_LINE1 =
-        "   %-18s %-15s %6s %9s %9s %-15s";
-    private static final String FORMAT_ROUTE_LINE2 =
-        "                      AsPath %s";
-
-    @Override
-    protected void execute() {
-        SdnIpService service = get(SdnIpService.class);
-
-        // Print summary of the routes
-        if (routesSummary) {
-            printSummary(service.getBgpRoutes4(), service.getBgpRoutes6());
-            return;
-        }
-
-        BgpSession foundBgpSession = null;
-        if (bgpNeighbor != null) {
-            // Print the routes from a single neighbor (if found)
-            for (BgpSession bgpSession : service.getBgpSessions()) {
-                if (bgpSession.remoteInfo().bgpId().toString().equals(bgpNeighbor)) {
-                    foundBgpSession = bgpSession;
-                    break;
-                }
-            }
-            if (foundBgpSession == null) {
-                print("BGP neighbor %s not found", bgpNeighbor);
-                return;
-            }
-        }
-
-        // Print the routes
-        if (foundBgpSession != null) {
-            printRoutes(foundBgpSession.getBgpRibIn4(),
-                        foundBgpSession.getBgpRibIn6());
-        } else {
-            printRoutes(service.getBgpRoutes4(), service.getBgpRoutes6());
-        }
-    }
-
-    /**
-     * Prints summary of the routes.
-     *
-     * @param routes4 the IPv4 routes
-     * @param routes6 the IPv6 routes
-     */
-    private void printSummary(Collection<BgpRouteEntry> routes4,
-                              Collection<BgpRouteEntry> routes6) {
-        if (outputJson()) {
-            ObjectMapper mapper = new ObjectMapper();
-            ObjectNode result = mapper.createObjectNode();
-            result.put("totalRoutes4", routes4.size());
-            result.put("totalRoutes6", routes6.size());
-            print("%s", result);
-        } else {
-            print(FORMAT_SUMMARY_V4, routes4.size());
-            print(FORMAT_SUMMARY_V6, routes6.size());
-        }
-    }
-
-    /**
-     * Prints all routes.
-     *
-     * @param routes4 the IPv4 routes to print
-     * @param routes6 the IPv6 routes to print
-     */
-    private void printRoutes(Collection<BgpRouteEntry> routes4,
-                             Collection<BgpRouteEntry> routes6) {
-        if (outputJson()) {
-            ObjectMapper mapper = new ObjectMapper();
-            ObjectNode result = mapper.createObjectNode();
-            result.put("routes4", json(routes4));
-            result.put("routes6", json(routes6));
-            print("%s", result);
-        } else {
-            // The IPv4 routes
-            print(FORMAT_HEADER);
-            for (BgpRouteEntry route : routes4) {
-                printRoute(route);
-            }
-            print(FORMAT_SUMMARY_V4, routes4.size());
-            print("");                  // Empty separator line
-            // The IPv6 routes
-            print(FORMAT_HEADER);
-            for (BgpRouteEntry route : routes6) {
-                printRoute(route);
-            }
-            print(FORMAT_SUMMARY_V6, routes6.size());
-        }
-    }
-
-    /**
-     * Prints a BGP route.
-     *
-     * @param route the route to print
-     */
-    private void printRoute(BgpRouteEntry route) {
-        if (route != null) {
-            print(FORMAT_ROUTE_LINE1, route.prefix(), route.nextHop(),
-                  Update.Origin.typeToString(route.getOrigin()),
-                  route.getLocalPref(), route.getMultiExitDisc(),
-                  route.getBgpSession().remoteInfo().bgpId());
-            print(FORMAT_ROUTE_LINE2, asPath4Cli(route.getAsPath()));
-        }
-    }
-
-    /**
-     * Formats the AS Path as a string that can be shown on the CLI.
-     *
-     * @param asPath the AS Path to format
-     * @return the AS Path as a string
-     */
-    private String asPath4Cli(BgpRouteEntry.AsPath asPath) {
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments =
-            asPath.getPathSegments();
-
-        if (pathSegments.isEmpty()) {
-            return "[none]";
-        }
-
-        final StringBuilder builder = new StringBuilder();
-        for (BgpRouteEntry.PathSegment pathSegment : pathSegments) {
-            String prefix = null;
-            String suffix = null;
-            switch (pathSegment.getType()) {
-            case Update.AsPath.AS_SET:
-                prefix = "[AS-Set";
-                suffix = "]";
-                break;
-            case Update.AsPath.AS_SEQUENCE:
-                break;
-            case Update.AsPath.AS_CONFED_SEQUENCE:
-                prefix = "[AS-Confed-Seq";
-                suffix = "]";
-                break;
-            case Update.AsPath.AS_CONFED_SET:
-                prefix = "[AS-Confed-Set";
-                suffix = "]";
-                break;
-            default:
-                builder.append(String.format("(type = %s)",
-                        Update.AsPath.typeToString(pathSegment.getType())));
-                break;
-            }
-
-            if (prefix != null) {
-                if (builder.length() > 0) {
-                    builder.append(" ");        // Separator
-                }
-                builder.append(prefix);
-            }
-            // Print the AS numbers
-            for (Long asn : pathSegment.getSegmentAsNumbers()) {
-                if (builder.length() > 0) {
-                    builder.append(" ");        // Separator
-                }
-                builder.append(String.format("%d", asn));
-            }
-            if (suffix != null) {
-                // No need for separator
-                builder.append(prefix);
-            }
-        }
-        return builder.toString();
-    }
-
-    /**
-     * Produces a JSON array of routes.
-     *
-     * @param routes the routes with the data
-     * @return JSON array with the routes
-     */
-    private JsonNode json(Collection<BgpRouteEntry> routes) {
-        ObjectMapper mapper = new ObjectMapper();
-        ArrayNode result = mapper.createArrayNode();
-
-        for (BgpRouteEntry route : routes) {
-            result.add(json(mapper, route));
-        }
-        return result;
-    }
-
-    /**
-     * Produces JSON object for a route.
-     *
-     * @param mapper the JSON object mapper to use
-     * @param route the route with the data
-     * @return JSON object for the route
-     */
-    private ObjectNode json(ObjectMapper mapper, BgpRouteEntry route) {
-        ObjectNode result = mapper.createObjectNode();
-
-        result.put("prefix", route.prefix().toString());
-        result.put("nextHop", route.nextHop().toString());
-        result.put("bgpId",
-                   route.getBgpSession().remoteInfo().bgpId().toString());
-        result.put("origin", Update.Origin.typeToString(route.getOrigin()));
-        result.put("asPath", json(mapper, route.getAsPath()));
-        result.put("localPref", route.getLocalPref());
-        result.put("multiExitDisc", route.getMultiExitDisc());
-
-        return result;
-    }
-
-    /**
-     * Produces JSON object for an AS path.
-     *
-     * @param mapper the JSON object mapper to use
-     * @param asPath the AS path with the data
-     * @return JSON object for the AS path
-     */
-    private ObjectNode json(ObjectMapper mapper, BgpRouteEntry.AsPath asPath) {
-        ObjectNode result = mapper.createObjectNode();
-        ArrayNode pathSegmentsJson = mapper.createArrayNode();
-        for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) {
-            ObjectNode pathSegmentJson = mapper.createObjectNode();
-            pathSegmentJson.put("type",
-                                Update.AsPath.typeToString(pathSegment.getType()));
-            ArrayNode segmentAsNumbersJson = mapper.createArrayNode();
-            for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
-                segmentAsNumbersJson.add(asNumber);
-            }
-            pathSegmentJson.put("segmentAsNumbers", segmentAsNumbersJson);
-            pathSegmentsJson.add(pathSegmentJson);
-        }
-        result.put("pathSegments", pathSegmentsJson);
-
-        return result;
-    }
-}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RoutesListCommand.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RoutesListCommand.java
deleted file mode 100644
index cebbc43..0000000
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/RoutesListCommand.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.cli;
-
-import java.util.Collection;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.sdnip.RouteEntry;
-import org.onosproject.sdnip.SdnIpService;
-
-/**
- * Command to show the list of routes in SDN-IP's routing table.
- */
-@Command(scope = "onos", name = "routes",
-        description = "Lists all SDN-IP best routes")
-public class RoutesListCommand extends AbstractShellCommand {
-    @Option(name = "-s", aliases = "--summary",
-            description = "SDN-IP routes summary",
-            required = false, multiValued = false)
-    private boolean routesSummary = false;
-
-    private static final String FORMAT_SUMMARY_V4 =
-        "Total SDN-IP IPv4 routes = %d";
-    private static final String FORMAT_SUMMARY_V6 =
-        "Total SDN-IP IPv6 routes = %d";
-    private static final String FORMAT_HEADER =
-        "   Network            Next Hop";
-    private static final String FORMAT_ROUTE =
-        "   %-18s %-15s";
-
-    @Override
-    protected void execute() {
-        SdnIpService service = get(SdnIpService.class);
-
-        // Print summary of the routes
-        if (routesSummary) {
-            printSummary(service.getRoutes4(), service.getRoutes6());
-            return;
-        }
-
-        // Print all routes
-        printRoutes(service.getRoutes4(), service.getRoutes6());
-    }
-
-    /**
-     * Prints summary of the routes.
-     *
-     * @param routes4 the IPv4 routes
-     * @param routes6 the IPv6 routes
-     */
-    private void printSummary(Collection<RouteEntry> routes4,
-                              Collection<RouteEntry> routes6) {
-        if (outputJson()) {
-            ObjectMapper mapper = new ObjectMapper();
-            ObjectNode result = mapper.createObjectNode();
-            result.put("totalRoutes4", routes4.size());
-            result.put("totalRoutes6", routes6.size());
-            print("%s", result);
-        } else {
-            print(FORMAT_SUMMARY_V4, routes4.size());
-            print(FORMAT_SUMMARY_V6, routes6.size());
-        }
-    }
-
-    /**
-     * Prints all routes.
-     *
-     * @param routes4 the IPv4 routes to print
-     * @param routes6 the IPv6 routes to print
-     */
-    private void printRoutes(Collection<RouteEntry> routes4,
-                             Collection<RouteEntry> routes6) {
-        if (outputJson()) {
-            ObjectMapper mapper = new ObjectMapper();
-            ObjectNode result = mapper.createObjectNode();
-            result.put("routes4", json(routes4));
-            result.put("routes6", json(routes6));
-            print("%s", result);
-        } else {
-            // The IPv4 routes
-            print(FORMAT_HEADER);
-            for (RouteEntry route : routes4) {
-                printRoute(route);
-            }
-            print(FORMAT_SUMMARY_V4, routes4.size());
-            print("");                  // Empty separator line
-            // The IPv6 routes
-            print(FORMAT_HEADER);
-            for (RouteEntry route : routes6) {
-                printRoute(route);
-            }
-            print(FORMAT_SUMMARY_V6, routes6.size());
-        }
-    }
-
-    /**
-     * Prints a route.
-     *
-     * @param route the route to print
-     */
-    private void printRoute(RouteEntry route) {
-        if (route != null) {
-            print(FORMAT_ROUTE, route.prefix(), route.nextHop());
-        }
-    }
-
-    /**
-     * Produces a JSON array of routes.
-     *
-     * @param routes the routes with the data
-     * @return JSON array with the routes
-     */
-    private JsonNode json(Collection<RouteEntry> routes) {
-        ObjectMapper mapper = new ObjectMapper();
-        ArrayNode result = mapper.createArrayNode();
-
-        for (RouteEntry route : routes) {
-            result.add(json(mapper, route));
-        }
-        return result;
-    }
-
-    /**
-     * Produces JSON object for a route.
-     *
-     * @param mapper the JSON object mapper to use
-     * @param route the route with the data
-     * @return JSON object for the route
-     */
-    private ObjectNode json(ObjectMapper mapper, RouteEntry route) {
-        ObjectNode result = mapper.createObjectNode();
-
-        result.put("prefix", route.prefix().toString());
-        result.put("nextHop", route.nextHop().toString());
-
-        return result;
-    }
-}
diff --git a/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index dd33f73..3be1c79 100644
--- a/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/sdnip/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -17,15 +17,6 @@
 
   <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
     <command>
-      <action class="org.onosproject.sdnip.cli.BgpNeighborsListCommand"/>
-    </command>
-    <command>
-      <action class="org.onosproject.sdnip.cli.BgpRoutesListCommand"/>
-    </command>
-    <command>
-      <action class="org.onosproject.sdnip.cli.RoutesListCommand"/>
-    </command>
-    <command>
       <action class="org.onosproject.sdnip.cli.PrimaryChangeCommand"/>
     </command>
   </command-bundle>
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
index e4808f7..d13aa2a 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/IntentSyncTest.java
@@ -16,9 +16,8 @@
 package org.onosproject.sdnip;
 
 import com.google.common.collect.Sets;
-import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
-import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
-import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
+import org.easymock.EasyMock;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.junit.TestUtils;
@@ -32,18 +31,12 @@
 import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultHost;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
 import org.onosproject.net.host.InterfaceIpAddress;
 import org.onosproject.net.intent.AbstractIntentTest;
 import org.onosproject.net.intent.Intent;
@@ -51,10 +44,18 @@
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.net.provider.ProviderId;
+import org.onosproject.routingapi.FibEntry;
+import org.onosproject.routingapi.FibUpdate;
+import org.onosproject.routingapi.RouteEntry;
+import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
+import org.onosproject.sdnip.config.BgpPeer;
 import org.onosproject.sdnip.config.Interface;
+import org.onosproject.sdnip.config.SdnIpConfigurationService;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -71,9 +72,9 @@
  */
 public class IntentSyncTest extends AbstractIntentTest {
 
+    private SdnIpConfigurationService sdnIpConfigService;
     private InterfaceService interfaceService;
     private IntentService intentService;
-    private HostService hostService;
 
     private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
             DeviceId.deviceId("of:0000000000000001"),
@@ -87,8 +88,11 @@
             DeviceId.deviceId("of:0000000000000003"),
             PortNumber.portNumber(1));
 
+    private static final ConnectPoint SW4_ETH1 = new ConnectPoint(
+            DeviceId.deviceId("of:0000000000000004"),
+            PortNumber.portNumber(1));
+
     private IntentSynchronizer intentSynchronizer;
-    private Router router;
 
     private static final ApplicationId APPID = new ApplicationId() {
         @Override
@@ -106,12 +110,42 @@
     public void setUp() throws Exception {
         super.setUp();
         setUpInterfaceService();
-        setUpHostService();
+
+        setUpBgpPeers();
         intentService = createMock(IntentService.class);
 
         intentSynchronizer = new IntentSynchronizer(APPID, intentService,
-                                                    null, interfaceService);
-        router = new Router(intentSynchronizer, hostService);
+                                                    sdnIpConfigService, interfaceService);
+    }
+
+    /**
+     * Sets up BGP peers in external networks.
+     */
+    private void setUpBgpPeers() {
+
+        Map<IpAddress, BgpPeer> peers = new HashMap<>();
+
+        String peerSw1Eth1 = "192.168.10.1";
+        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";
+        peers.put(IpAddress.valueOf(peer1Sw2Eth1),
+                  new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
+
+        String peer2Sw2Eth1 = "192.168.20.2";
+        peers.put(IpAddress.valueOf(peer2Sw2Eth1),
+                  new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
+
+        String peer1Sw4Eth1 = "192.168.40.1";
+        peers.put(IpAddress.valueOf(peer1Sw4Eth1),
+                  new BgpPeer("00:00:00:00:00:00:00:04", 1, peer1Sw4Eth1));
+
+        sdnIpConfigService = createMock(SdnIpConfigurationService.class);
+        expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
+        EasyMock.replay(sdnIpConfigService);
+
     }
 
     /**
@@ -133,80 +167,279 @@
         interfaces.add(sw1Eth1);
 
         Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
-        interfaceIpAddresses2.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.20.101"),
-                IpPrefix.valueOf("192.168.20.0/24")));
+        interfaceIpAddresses2.add(
+                new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
+                                       IpPrefix.valueOf("192.168.20.0/24")));
         Interface sw2Eth1 = new Interface(SW2_ETH1,
                 interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"),
                 VlanId.NONE);
         interfaces.add(sw2Eth1);
 
         Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
-        interfaceIpAddresses3.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.30.101"),
-                IpPrefix.valueOf("192.168.30.0/24")));
+        interfaceIpAddresses3.add(
+                new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"),
+                                       IpPrefix.valueOf("192.168.30.0/24")));
         Interface sw3Eth1 = new Interface(SW3_ETH1,
                 interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"),
                 VlanId.NONE);
         interfaces.add(sw3Eth1);
 
+        InterfaceIpAddress interfaceIpAddress4 =
+                new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"),
+                                       IpPrefix.valueOf("192.168.40.0/24"));
+        Interface sw4Eth1 = new Interface(SW4_ETH1,
+                                          Sets.newHashSet(interfaceIpAddress4),
+                                          MacAddress.valueOf("00:00:00:00:00:04"),
+                                          VlanId.vlanId((short) 1));
+
+        expect(interfaceService.getInterface(SW4_ETH1)).andReturn(sw4Eth1).anyTimes();
+        interfaces.add(sw4Eth1);
+
         expect(interfaceService.getInterface(SW1_ETH1)).andReturn(
                 sw1Eth1).anyTimes();
         expect(interfaceService.getInterface(SW2_ETH1)).andReturn(
                 sw2Eth1).anyTimes();
         expect(interfaceService.getInterface(SW3_ETH1)).andReturn(
                 sw3Eth1).anyTimes();
-        expect(interfaceService.getInterfaces()).andReturn(
-                interfaces).anyTimes();
+        expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
         replay(interfaceService);
     }
 
     /**
-     * Sets up the host service with details of hosts.
+     * Tests adding a FIB entry to the IntentSynchronizer.
+     *
+     * We verify that the synchronizer records the correct state and that the
+     * correct intent is submitted to the IntentService.
+     *
+     * @throws TestUtilsException
      */
-    private void setUpHostService() {
-        hostService = createMock(HostService.class);
+    @Test
+    public void testFibAdd() throws TestUtilsException {
+        FibEntry fibEntry = new FibEntry(
+                Ip4Prefix.valueOf("1.1.1.0/24"),
+                Ip4Address.valueOf("192.168.10.1"),
+                MacAddress.valueOf("00:00:00:00:00:01"));
 
-        hostService.addListener(anyObject(HostListener.class));
-        expectLastCall().anyTimes();
+        // Construct a MultiPointToSinglePointIntent intent
+        TrafficSelector.Builder selectorBuilder =
+                DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
+                fibEntry.prefix());
 
-        IpAddress host1Address = IpAddress.valueOf("192.168.10.1");
-        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));
+        TrafficTreatment.Builder treatmentBuilder =
+                DefaultTrafficTreatment.builder();
+        treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
 
-        expect(hostService.getHostsByIp(host1Address))
-                .andReturn(Sets.newHashSet(host1)).anyTimes();
-        hostService.startMonitoringIp(host1Address);
-        expectLastCall().anyTimes();
+        Set<ConnectPoint> ingressPoints = new HashSet<>();
+        ingressPoints.add(SW2_ETH1);
+        ingressPoints.add(SW3_ETH1);
+        ingressPoints.add(SW4_ETH1);
+
+        MultiPointToSinglePointIntent intent =
+                new MultiPointToSinglePointIntent(APPID,
+                                                  selectorBuilder.build(), treatmentBuilder.build(),
+                                                  ingressPoints, SW1_ETH1);
+
+        // Setup the expected intents
+        IntentOperations.Builder builder = IntentOperations.builder(APPID);
+        builder.addSubmitOperation(intent);
+        intentService.execute(TestIntentServiceHelper.eqExceptId(
+                builder.build()));
+        replay(intentService);
+
+        intentSynchronizer.leaderChanged(true);
+        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
+
+        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE,
+                                            fibEntry);
+        intentSynchronizer.update(Collections.singleton(fibUpdate),
+                                  Collections.emptyList());
+
+        Assert.assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
+        Intent firstIntent =
+                intentSynchronizer.getRouteIntents().iterator().next();
+        IntentKey firstIntentKey = new IntentKey(firstIntent);
+        IntentKey intentKey = new IntentKey(intent);
+        assertTrue(firstIntentKey.equals(intentKey));
+        verify(intentService);
+    }
+
+    /**
+     * Tests adding a FIB entry with to a next hop in a VLAN.
+     *
+     * We verify that the synchronizer records the correct state and that the
+     * correct intent is submitted to the IntentService.
+     *
+     * @throws TestUtilsException
+     */
+    @Test
+    public void testFibAddWithVlan() throws TestUtilsException {
+        FibEntry fibEntry = new FibEntry(
+                Ip4Prefix.valueOf("3.3.3.0/24"),
+                Ip4Address.valueOf("192.168.40.1"),
+                MacAddress.valueOf("00:00:00:00:00:04"));
+
+        // Construct a MultiPointToSinglePointIntent intent
+        TrafficSelector.Builder selectorBuilder =
+                DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                       .matchIPDst(fibEntry.prefix())
+                       .matchVlanId(VlanId.ANY);
+
+        TrafficTreatment.Builder treatmentBuilder =
+                DefaultTrafficTreatment.builder();
+        treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:04"))
+                        .setVlanId(VlanId.vlanId((short) 1));
+
+        Set<ConnectPoint> ingressPoints = new HashSet<>();
+        ingressPoints.add(SW1_ETH1);
+        ingressPoints.add(SW2_ETH1);
+        ingressPoints.add(SW3_ETH1);
+
+        MultiPointToSinglePointIntent intent =
+                new MultiPointToSinglePointIntent(APPID,
+                        selectorBuilder.build(), treatmentBuilder.build(),
+                        ingressPoints, SW4_ETH1);
+
+        // Setup the expected intents
+        IntentOperations.Builder builder = IntentOperations.builder(APPID);
+        builder.addSubmitOperation(intent);
+        intentService.execute(
+                TestIntentServiceHelper.eqExceptId(builder.build()));
+        replay(intentService);
+
+        // Run the test
+        intentSynchronizer.leaderChanged(true);
+        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
+        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry);
+
+        intentSynchronizer.update(Collections.singleton(fibUpdate),
+                                  Collections.emptyList());
+
+        // Verify
+        Assert.assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
+        Intent firstIntent =
+            intentSynchronizer.getRouteIntents().iterator().next();
+        IntentKey firstIntentKey = new IntentKey(firstIntent);
+        IntentKey intentKey = new IntentKey(intent);
+        assertTrue(firstIntentKey.equals(intentKey));
+        verify(intentService);
+    }
+
+    /**
+     * Tests updating a FIB entry.
+     *
+     * We verify that the synchronizer records the correct state and that the
+     * correct intent is submitted to the IntentService.
+     *
+     * @throws TestUtilsException
+     */
+    @Test
+    public void testFibUpdate() throws TestUtilsException {
+        // Firstly add a route
+        testFibAdd();
+
+        Intent addedIntent =
+                intentSynchronizer.getRouteIntents().iterator().next();
+
+        // Start to construct a new route entry and new intent
+        FibEntry fibEntryUpdate = new FibEntry(
+                Ip4Prefix.valueOf("1.1.1.0/24"),
+                Ip4Address.valueOf("192.168.20.1"),
+                MacAddress.valueOf("00:00:00:00:00:02"));
+
+        // Construct a new MultiPointToSinglePointIntent intent
+        TrafficSelector.Builder selectorBuilderNew =
+                DefaultTrafficSelector.builder();
+        selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
+                fibEntryUpdate.prefix());
+
+        TrafficTreatment.Builder treatmentBuilderNew =
+                DefaultTrafficTreatment.builder();
+        treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
 
 
-        IpAddress host2Address = IpAddress.valueOf("192.168.20.1");
-        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));
+        Set<ConnectPoint> ingressPointsNew = new HashSet<>();
+        ingressPointsNew.add(SW1_ETH1);
+        ingressPointsNew.add(SW3_ETH1);
+        ingressPointsNew.add(SW4_ETH1);
 
-        expect(hostService.getHostsByIp(host2Address))
-                .andReturn(Sets.newHashSet(host2)).anyTimes();
-        hostService.startMonitoringIp(host2Address);
-        expectLastCall().anyTimes();
+        MultiPointToSinglePointIntent intentNew =
+                new MultiPointToSinglePointIntent(APPID,
+                                                  selectorBuilderNew.build(),
+                                                  treatmentBuilderNew.build(),
+                                                  ingressPointsNew, SW2_ETH1);
 
+        // Set up test expectation
+        reset(intentService);
+        // Setup the expected intents
+        IntentOperations.Builder builder = IntentOperations.builder(APPID);
+        builder.addWithdrawOperation(addedIntent.id());
+        intentService.execute(TestIntentServiceHelper.eqExceptId(
+                builder.build()));
+        builder = IntentOperations.builder(APPID);
+        builder.addSubmitOperation(intentNew);
+        intentService.execute(TestIntentServiceHelper.eqExceptId(
+                builder.build()));
+        replay(intentService);
 
-        IpAddress host3Address = IpAddress.valueOf("192.168.30.1");
-        Host host3 = new DefaultHost(ProviderId.NONE, HostId.NONE,
-                MacAddress.valueOf("00:00:00:00:00:03"), VlanId.NONE,
-                new HostLocation(SW3_ETH1, 1),
-                        Sets.newHashSet(host3Address));
+        // Call the update() method in IntentSynchronizer class
+        intentSynchronizer.leaderChanged(true);
+        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
+        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE,
+                                                  fibEntryUpdate);
+        intentSynchronizer.update(Collections.singletonList(fibUpdate),
+                                  Collections.emptyList());
 
-        expect(hostService.getHostsByIp(host3Address))
-                .andReturn(Sets.newHashSet(host3)).anyTimes();
-        hostService.startMonitoringIp(host3Address);
-        expectLastCall().anyTimes();
+        // Verify
+        Assert.assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
+        Intent firstIntent =
+                intentSynchronizer.getRouteIntents().iterator().next();
+        IntentKey firstIntentKey = new IntentKey(firstIntent);
+        IntentKey intentNewKey = new IntentKey(intentNew);
+        assertTrue(firstIntentKey.equals(intentNewKey));
+        verify(intentService);
+    }
 
+    /**
+     * Tests deleting a FIB entry.
+     *
+     * We verify that the synchronizer records the correct state and that the
+     * correct intent is withdrawn from the IntentService.
+     *
+     * @throws TestUtilsException
+     */
+    @Test
+    public void testFibDelete() throws TestUtilsException {
+        // Firstly add a route
+        testFibAdd();
 
-        replay(hostService);
+        Intent addedIntent =
+                intentSynchronizer.getRouteIntents().iterator().next();
+
+        // Construct the existing route entry
+        FibEntry fibEntry = new FibEntry(
+                Ip4Prefix.valueOf("1.1.1.0/24"), null, null);
+
+        // Set up expectation
+        reset(intentService);
+        // Setup the expected intents
+        IntentOperations.Builder builder = IntentOperations.builder(APPID);
+        builder.addWithdrawOperation(addedIntent.id());
+        intentService.execute(TestIntentServiceHelper.eqExceptId(
+                builder.build()));
+        replay(intentService);
+
+        // Call the update() method in IntentSynchronizer class
+        intentSynchronizer.leaderChanged(true);
+        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
+        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.DELETE, fibEntry);
+        intentSynchronizer.update(Collections.emptyList(),
+                                  Collections.singletonList(fibUpdate));
+
+        // Verify
+        Assert.assertEquals(intentSynchronizer.getRouteIntents().size(), 0);
+        verify(intentService);
     }
 
     /**
@@ -287,25 +520,7 @@
         MultiPointToSinglePointIntent intent6 = intentBuilder(
                 routeEntry6.prefix(), "00:00:00:00:00:01",  SW1_ETH1);
 
-        // Set up the ribTable field in Router class and routeIntents fields
-        // in IntentSynchronizer class
-        InvertedRadixTree<RouteEntry> ribTable =
-                new ConcurrentInvertedRadixTree<>(
-                new DefaultByteArrayNodeFactory());
-        ribTable.put(RouteEntry.createBinaryString(routeEntry1.prefix()),
-                     routeEntry1);
-        ribTable.put(RouteEntry.createBinaryString(routeEntry3.prefix()),
-                     routeEntry3);
-        ribTable.put(RouteEntry.createBinaryString(routeEntry4Update.prefix()),
-                     routeEntry4Update);
-        ribTable.put(RouteEntry.createBinaryString(routeEntry5.prefix()),
-                     routeEntry5);
-        ribTable.put(RouteEntry.createBinaryString(routeEntry6.prefix()),
-                     routeEntry6);
-        ribTable.put(RouteEntry.createBinaryString(routeEntry7.prefix()),
-                     routeEntry7);
-        TestUtils.setField(router, "ribTable4", ribTable);
-
+        // Set up the routeIntents field in IntentSynchronizer class
         ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent>
             routeIntents =  new ConcurrentHashMap<>();
         routeIntents.put(routeEntry1.prefix(), intent1);
@@ -353,20 +568,9 @@
 
         // Start the test
         intentSynchronizer.leaderChanged(true);
-        /*
-        TestUtils.callMethod(intentSynchronizer, "synchronizeIntents",
-                             new Class<?>[] {});
-        */
         intentSynchronizer.synchronizeIntents();
 
         // Verify
-        assertEquals(router.getRoutes4().size(), 6);
-        assertTrue(router.getRoutes4().contains(routeEntry1));
-        assertTrue(router.getRoutes4().contains(routeEntry3));
-        assertTrue(router.getRoutes4().contains(routeEntry4Update));
-        assertTrue(router.getRoutes4().contains(routeEntry5));
-        assertTrue(router.getRoutes4().contains(routeEntry6));
-
         assertEquals(intentSynchronizer.getRouteIntents().size(), 6);
         assertTrue(intentSynchronizer.getRouteIntents().contains(intent1));
         assertTrue(intentSynchronizer.getRouteIntents().contains(intent3));
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
index 5311a72..298972d 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
@@ -41,7 +41,6 @@
 import org.onosproject.net.intent.IntentOperations;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.intent.PointToPointIntent;
-import org.onosproject.sdnip.bgp.BgpConstants;
 import org.onosproject.sdnip.config.BgpPeer;
 import org.onosproject.sdnip.config.BgpSpeaker;
 import org.onosproject.sdnip.config.Interface;
@@ -302,7 +301,7 @@
      */
     private void setUpBgpIntents() {
 
-        Short bgpPort = Short.valueOf((short) BgpConstants.BGP_PORT);
+        Short bgpPort = 179;
 
         // Start to build intents between BGP speaker1 and BGP peer1
         bgpPathintentConstructor(
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouteEntryTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/RouteEntryTest.java
deleted file mode 100644
index b977917..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouteEntryTest.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Test;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-
-/**
- * Unit tests for the RouteEntry class.
- */
-public class RouteEntryTest {
-    /**
-     * Tests valid class constructor.
-     */
-    @Test
-    public void testConstructor() {
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-
-        RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
-        assertThat(routeEntry.toString(),
-                   is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
-    }
-
-    /**
-     * Tests invalid class constructor for null IPv4 prefix.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullPrefix() {
-        Ip4Prefix prefix = null;
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-
-        new RouteEntry(prefix, nextHop);
-    }
-
-    /**
-     * Tests invalid class constructor for null IPv4 next-hop.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullNextHop() {
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = null;
-
-        new RouteEntry(prefix, nextHop);
-    }
-
-    /**
-     * Tests getting the fields of a route entry.
-     */
-    @Test
-    public void testGetFields() {
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-
-        RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
-        assertThat(routeEntry.prefix(), is(prefix));
-        assertThat(routeEntry.nextHop(), is(nextHop));
-    }
-
-    /**
-     * Tests creating a binary string from IPv4 prefix.
-     */
-    @Test
-    public void testCreateBinaryString() {
-        Ip4Prefix prefix;
-
-        prefix = Ip4Prefix.valueOf("0.0.0.0/0");
-        assertThat(RouteEntry.createBinaryString(prefix), is(""));
-
-        prefix = Ip4Prefix.valueOf("192.168.166.0/22");
-        assertThat(RouteEntry.createBinaryString(prefix),
-                   is("1100000010101000101001"));
-
-        prefix = Ip4Prefix.valueOf("192.168.166.0/23");
-        assertThat(RouteEntry.createBinaryString(prefix),
-                   is("11000000101010001010011"));
-
-        prefix = Ip4Prefix.valueOf("192.168.166.0/24");
-        assertThat(RouteEntry.createBinaryString(prefix),
-                   is("110000001010100010100110"));
-
-        prefix = Ip4Prefix.valueOf("130.162.10.1/25");
-        assertThat(RouteEntry.createBinaryString(prefix),
-                   is("1000001010100010000010100"));
-
-        prefix = Ip4Prefix.valueOf("255.255.255.255/32");
-        assertThat(RouteEntry.createBinaryString(prefix),
-                   is("11111111111111111111111111111111"));
-    }
-
-    /**
-     * Tests equality of {@link RouteEntry}.
-     */
-    @Test
-    public void testEquality() {
-        Ip4Prefix prefix1 = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop1 = Ip4Address.valueOf("5.6.7.8");
-        RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1);
-
-        Ip4Prefix prefix2 = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop2 = Ip4Address.valueOf("5.6.7.8");
-        RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
-
-        assertThat(routeEntry1, is(routeEntry2));
-    }
-
-    /**
-     * Tests non-equality of {@link RouteEntry}.
-     */
-    @Test
-    public void testNonEquality() {
-        Ip4Prefix prefix1 = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop1 = Ip4Address.valueOf("5.6.7.8");
-        RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1);
-
-        Ip4Prefix prefix2 = Ip4Prefix.valueOf("1.2.3.0/25");      // Different
-        Ip4Address nextHop2 = Ip4Address.valueOf("5.6.7.8");
-        RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
-
-        Ip4Prefix prefix3 = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop3 = Ip4Address.valueOf("5.6.7.9");      // Different
-        RouteEntry routeEntry3 = new RouteEntry(prefix3, nextHop3);
-
-        assertThat(routeEntry1, is(not(routeEntry2)));
-        assertThat(routeEntry1, is(not(routeEntry3)));
-    }
-
-    /**
-     * Tests object string representation.
-     */
-    @Test
-    public void testToString() {
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
-
-        assertThat(routeEntry.toString(),
-                   is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterAsyncArpTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterAsyncArpTest.java
deleted file mode 100644
index 4d14228..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterAsyncArpTest.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import com.google.common.collect.Sets;
-import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
-import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
-import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.junit.TestUtils;
-import org.onlab.junit.TestUtils.TestUtilsException;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultHost;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intent.AbstractIntentTest;
-import org.onosproject.net.intent.Intent;
-import org.onosproject.net.intent.IntentOperations;
-import org.onosproject.net.intent.IntentService;
-import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
-import org.onosproject.sdnip.Router.InternalHostListener;
-import org.onosproject.sdnip.config.BgpPeer;
-import org.onosproject.sdnip.config.Interface;
-import org.onosproject.sdnip.config.SdnIpConfigurationService;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * This class tests adding a route, updating a route, deleting a route, and
- * the ARP module answers the MAC address asynchronously.
- */
-public class RouterAsyncArpTest extends AbstractIntentTest {
-
-    private SdnIpConfigurationService sdnIpConfigService;
-    private InterfaceService interfaceService;
-    private IntentService intentService;
-    private HostService hostService;
-
-    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 IntentSynchronizer intentSynchronizer;
-    private Router router;
-    private InternalHostListener internalHostListener;
-
-    private static final ApplicationId APPID = new ApplicationId() {
-        @Override
-        public short id() {
-            return 1;
-        }
-
-        @Override
-        public String name() {
-            return "SDNIP";
-        }
-    };
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        setUpSdnIpConfigService();
-        setUpInterfaceService();
-        hostService = createMock(HostService.class);
-        intentService = createMock(IntentService.class);
-
-        intentSynchronizer = new IntentSynchronizer(APPID, intentService,
-                                                    sdnIpConfigService,
-                                                    interfaceService);
-        router = new Router(intentSynchronizer, hostService);
-        internalHostListener = router.new InternalHostListener();
-    }
-
-    /**
-     * Sets up SdnIpConfigService.
-     */
-    private void setUpSdnIpConfigService() {
-
-        sdnIpConfigService = createMock(SdnIpConfigurationService.class);
-
-        Map<IpAddress, BgpPeer> peers = new HashMap<>();
-
-        String peerSw1Eth1 = "192.168.10.1";
-        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";
-        peers.put(IpAddress.valueOf(peer1Sw2Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
-
-        String peer2Sw2Eth1 = "192.168.20.2";
-        peers.put(IpAddress.valueOf(peer2Sw2Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
-
-        expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
-        replay(sdnIpConfigService);
-    }
-
-    /**
-     * Sets up InterfaceService.
-     */
-    private void setUpInterfaceService() {
-
-        interfaceService = createMock(InterfaceService.class);
-
-        Set<Interface> interfaces = Sets.newHashSet();
-
-        Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
-        interfaceIpAddresses1.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.10.101"),
-                IpPrefix.valueOf("192.168.10.0/24")));
-        Interface sw1Eth1 = new Interface(SW1_ETH1,
-                interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"),
-                VlanId.NONE);
-        interfaces.add(sw1Eth1);
-
-        Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
-        interfaceIpAddresses2.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.20.101"),
-                IpPrefix.valueOf("192.168.20.0/24")));
-        Interface sw2Eth1 = new Interface(SW2_ETH1,
-                interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"),
-                VlanId.NONE);
-        interfaces.add(sw2Eth1);
-
-        Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
-        interfaceIpAddresses3.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.30.101"),
-                IpPrefix.valueOf("192.168.30.0/24")));
-        Interface sw3Eth1 = new Interface(SW3_ETH1,
-                interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"),
-                VlanId.NONE);
-        interfaces.add(sw3Eth1);
-
-        expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
-        expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
-        expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
-        expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
-        replay(interfaceService);
-    }
-
-    /**
-     * This method tests adding a route entry.
-     */
-    @Test
-    public void testRouteAdd() throws TestUtilsException {
-
-        // Construct a route entry
-        RouteEntry routeEntry = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("192.168.10.1"));
-
-        // Construct a route intent
-        MultiPointToSinglePointIntent intent = staticIntentBuilder();
-
-        // Set up test expectation
-        reset(hostService);
-        expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
-                new HashSet<Host>()).anyTimes();
-        hostService.startMonitoringIp(IpAddress.valueOf("192.168.10.1"));
-        replay(hostService);
-
-        reset(intentService);
-        IntentOperations.Builder builder = IntentOperations.builder(APPID);
-        builder.addSubmitOperation(intent);
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                                  routeEntry);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
-                MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
-                new HostLocation(
-                        SW1_ETH1.deviceId(),
-                        SW1_ETH1.port(), 1),
-                        Sets.newHashSet(IpAddress.valueOf("192.168.10.1")));
-        internalHostListener.event(
-                new HostEvent(HostEvent.Type.HOST_ADDED, host));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 1);
-        assertTrue(router.getRoutes4().contains(routeEntry));
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
-        Intent firstIntent =
-            intentSynchronizer.getRouteIntents().iterator().next();
-        IntentKey firstIntentKey = new IntentKey(firstIntent);
-        IntentKey intentKey = new IntentKey(intent);
-        assertTrue(firstIntentKey.equals(intentKey));
-        verify(intentService);
-        verify(hostService);
-
-    }
-
-    /**
-     * This method tests updating a route entry.
-     *
-     * @throws TestUtilsException
-     */
-    @Test
-    public void testRouteUpdate() throws TestUtilsException {
-
-        // Construct the existing route entry
-        RouteEntry routeEntry = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("192.168.10.1"));
-
-        // Construct the existing MultiPointToSinglePointIntent intent
-        MultiPointToSinglePointIntent intent = staticIntentBuilder();
-
-        // Set up the ribTable field of Router class with existing route, and
-        // routeIntents field with the corresponding existing intent
-        setRibTableField(routeEntry);
-        setRouteIntentsField(routeEntry, intent);
-
-        // Start to construct a new route entry and new intent
-        RouteEntry routeEntryUpdate = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("192.168.20.1"));
-
-        // Construct a new MultiPointToSinglePointIntent intent
-        TrafficSelector.Builder selectorBuilderNew =
-                DefaultTrafficSelector.builder();
-        selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
-                routeEntryUpdate.prefix());
-
-        TrafficTreatment.Builder treatmentBuilderNew =
-                DefaultTrafficTreatment.builder();
-        treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
-
-        Set<ConnectPoint> ingressPointsNew = new HashSet<ConnectPoint>();
-        ingressPointsNew.add(SW1_ETH1);
-        ingressPointsNew.add(SW3_ETH1);
-
-        MultiPointToSinglePointIntent intentNew =
-                new MultiPointToSinglePointIntent(APPID,
-                        selectorBuilderNew.build(),
-                        treatmentBuilderNew.build(),
-                        ingressPointsNew, SW2_ETH1);
-
-        // Set up test expectation
-        reset(hostService);
-        expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
-                new HashSet<Host>()).anyTimes();
-        hostService.startMonitoringIp(IpAddress.valueOf("192.168.20.1"));
-        replay(hostService);
-
-        reset(intentService);
-        IntentOperations.Builder builder = IntentOperations.builder(APPID);
-        builder.addWithdrawOperation(intent.id());
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        builder = IntentOperations.builder(APPID);
-        builder.addSubmitOperation(intentNew);
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                                  routeEntryUpdate);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
-                MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
-                new HostLocation(
-                        SW2_ETH1.deviceId(),
-                        SW2_ETH1.port(), 1),
-                        Sets.newHashSet(IpAddress.valueOf("192.168.20.1")));
-        internalHostListener.event(
-                new HostEvent(HostEvent.Type.HOST_ADDED, host));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 1);
-        assertTrue(router.getRoutes4().contains(routeEntryUpdate));
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
-        Intent firstIntent =
-            intentSynchronizer.getRouteIntents().iterator().next();
-        IntentKey firstIntentKey = new IntentKey(firstIntent);
-        IntentKey intentNewKey = new IntentKey(intentNew);
-        assertTrue(firstIntentKey.equals(intentNewKey));
-        verify(intentService);
-        verify(hostService);
-    }
-
-    /**
-     * This method tests deleting a route entry.
-     */
-    @Test
-    public void testRouteDelete() throws TestUtilsException {
-
-        // Construct the existing route entry
-        RouteEntry routeEntry = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("192.168.10.1"));
-
-        // Construct the existing MultiPointToSinglePointIntent intent
-        MultiPointToSinglePointIntent intent = staticIntentBuilder();
-
-        // Set up the ribTable field of Router class with existing route, and
-        // routeIntents field with the corresponding existing intent
-        setRibTableField(routeEntry);
-        setRouteIntentsField(routeEntry, intent);
-
-        // Set up expectation
-        reset(intentService);
-        IntentOperations.Builder builder = IntentOperations.builder(APPID);
-        builder.addWithdrawOperation(intent.id());
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE,
-                                                  routeEntry);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 0);
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 0);
-        verify(intentService);
-    }
-
-    /**
-     * Constructs a static MultiPointToSinglePointIntent.
-     */
-    private MultiPointToSinglePointIntent staticIntentBuilder() {
-
-        TrafficSelector.Builder selectorBuilder =
-                DefaultTrafficSelector.builder();
-        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
-                IpPrefix.valueOf("1.1.1.0/24"));
-
-        TrafficTreatment.Builder treatmentBuilder =
-                DefaultTrafficTreatment.builder();
-        treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
-
-        Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
-        ingressPoints.add(SW2_ETH1);
-        ingressPoints.add(SW3_ETH1);
-
-        MultiPointToSinglePointIntent intent =
-                new MultiPointToSinglePointIntent(APPID,
-                        selectorBuilder.build(), treatmentBuilder.build(),
-                        ingressPoints, SW1_ETH1);
-
-        return intent;
-    }
-
-    /**
-     * Sets ribTable Field in Router class.
-     *
-     * @throws TestUtilsException
-     */
-    private void setRibTableField(RouteEntry routeEntry)
-            throws TestUtilsException {
-
-        InvertedRadixTree<RouteEntry> ribTable =
-                new ConcurrentInvertedRadixTree<>(
-                new DefaultByteArrayNodeFactory());
-        ribTable.put(RouteEntry.createBinaryString(routeEntry.prefix()),
-                     routeEntry);
-        TestUtils.setField(router, "ribTable4", ribTable);
-    }
-
-    /**
-     * Sets routeIntentsField in IntentSynchronizer class.
-     *
-     * @throws TestUtilsException
-     */
-    private void setRouteIntentsField(RouteEntry routeEntry,
-            MultiPointToSinglePointIntent intent)
-            throws TestUtilsException {
-
-        ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent>
-            routeIntents =  new ConcurrentHashMap<>();
-        routeIntents.put(routeEntry.prefix(), intent);
-        TestUtils.setField(intentSynchronizer, "routeIntents", routeIntents);
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterTest.java
deleted file mode 100644
index a7b4cce..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/RouterTest.java
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import com.google.common.collect.Sets;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.junit.TestUtils;
-import org.onlab.junit.TestUtils.TestUtilsException;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultHost;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intent.AbstractIntentTest;
-import org.onosproject.net.intent.Intent;
-import org.onosproject.net.intent.IntentOperations;
-import org.onosproject.net.intent.IntentService;
-import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
-import org.onosproject.sdnip.config.BgpPeer;
-import org.onosproject.sdnip.config.Interface;
-import org.onosproject.sdnip.config.SdnIpConfigurationService;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * This class tests adding a route, updating a route, deleting a route,
- * and adding a route whose next hop is the local BGP speaker.
- * <p/>
- * ARP module answers the MAC address synchronously.
- */
-public class RouterTest extends AbstractIntentTest {
-
-    private SdnIpConfigurationService sdnIpConfigService;
-    private InterfaceService interfaceService;
-    private IntentService intentService;
-    private HostService hostService;
-
-    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 ConnectPoint SW4_ETH1 = new ConnectPoint(
-            DeviceId.deviceId("of:0000000000000004"),
-            PortNumber.portNumber(1));
-
-    private static final ApplicationId APPID = new ApplicationId() {
-        @Override
-        public short id() {
-            return 1;
-        }
-
-        @Override
-        public String name() {
-            return "SDNIP";
-        }
-    };
-
-    private IntentSynchronizer intentSynchronizer;
-    private Router router;
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        setUpBgpPeers();
-
-        setUpInterfaceService();
-        setUpHostService();
-
-        intentService = createMock(IntentService.class);
-
-        intentSynchronizer = new IntentSynchronizer(APPID, intentService,
-                                                    sdnIpConfigService,
-                                                    interfaceService);
-        router = new Router(intentSynchronizer, hostService);
-    }
-
-    /**
-     * Sets up BGP peers in external networks.
-     */
-    private void setUpBgpPeers() {
-
-        Map<IpAddress, BgpPeer> peers = new HashMap<>();
-
-        String peerSw1Eth1 = "192.168.10.1";
-        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";
-        peers.put(IpAddress.valueOf(peer1Sw2Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
-
-        String peer2Sw2Eth1 = "192.168.20.2";
-        peers.put(IpAddress.valueOf(peer2Sw2Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
-
-        String peer1Sw4Eth1 = "192.168.40.1";
-        peers.put(IpAddress.valueOf(peer1Sw4Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:04", 1, peer1Sw4Eth1));
-
-        sdnIpConfigService = createMock(SdnIpConfigurationService.class);
-        expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
-        replay(sdnIpConfigService);
-
-    }
-
-    /**
-     * Sets up logical interfaces, which emulate the configured interfaces
-     * in SDN-IP application.
-     */
-    private void setUpInterfaceService() {
-        interfaceService = createMock(InterfaceService.class);
-
-        Set<Interface> interfaces = Sets.newHashSet();
-
-        InterfaceIpAddress ia1 =
-            new InterfaceIpAddress(IpAddress.valueOf("192.168.10.101"),
-                                   IpPrefix.valueOf("192.168.10.0/24"));
-        Interface sw1Eth1 = new Interface(SW1_ETH1,
-                Sets.newHashSet(ia1),
-                MacAddress.valueOf("00:00:00:00:00:01"),
-                VlanId.NONE);
-
-        expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
-        interfaces.add(sw1Eth1);
-
-        InterfaceIpAddress ia2 =
-            new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
-                                   IpPrefix.valueOf("192.168.20.0/24"));
-        Interface sw2Eth1 = new Interface(SW2_ETH1,
-                Sets.newHashSet(ia2),
-                MacAddress.valueOf("00:00:00:00:00:02"),
-                VlanId.NONE);
-
-        expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
-        interfaces.add(sw2Eth1);
-
-        InterfaceIpAddress ia3 =
-            new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"),
-                                   IpPrefix.valueOf("192.168.30.0/24"));
-        Interface sw3Eth1 = new Interface(SW3_ETH1,
-                Sets.newHashSet(ia3),
-                MacAddress.valueOf("00:00:00:00:00:03"),
-                VlanId.NONE);
-
-        expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
-        interfaces.add(sw3Eth1);
-
-        InterfaceIpAddress ia4 =
-                new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"),
-                                       IpPrefix.valueOf("192.168.40.0/24"));
-            Interface sw4Eth1 = new Interface(SW4_ETH1,
-                    Sets.newHashSet(ia4),
-                    MacAddress.valueOf("00:00:00:00:00:04"),
-                    VlanId.vlanId((short) 1));
-
-            expect(interfaceService.getInterface(SW4_ETH1)).andReturn(sw4Eth1).anyTimes();
-            interfaces.add(sw4Eth1);
-
-        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();
-
-        IpAddress host1Address = IpAddress.valueOf("192.168.10.1");
-        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);
-        expectLastCall().anyTimes();
-
-
-        IpAddress host2Address = IpAddress.valueOf("192.168.20.1");
-        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);
-        expectLastCall().anyTimes();
-
-        // Next hop on a VLAN
-        IpAddress host3Address = IpAddress.valueOf("192.168.40.1");
-        Host host3 = new DefaultHost(ProviderId.NONE, HostId.NONE,
-                MacAddress.valueOf("00:00:00:00:00:03"), VlanId.vlanId((short) 1),
-                new HostLocation(SW4_ETH1, 1),
-                Sets.newHashSet(host3Address));
-
-        expect(hostService.getHostsByIp(host3Address))
-                .andReturn(Sets.newHashSet(host3)).anyTimes();
-        hostService.startMonitoringIp(host3Address);
-        expectLastCall().anyTimes();
-
-
-        replay(hostService);
-    }
-
-    /**
-     * This method tests adding a route entry.
-     */
-    @Test
-    public void testRouteAdd() throws TestUtilsException {
-        // Construct a route entry
-        RouteEntry routeEntry = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("192.168.10.1"));
-
-        // Construct a MultiPointToSinglePointIntent intent
-        TrafficSelector.Builder selectorBuilder =
-                DefaultTrafficSelector.builder();
-        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
-                routeEntry.prefix());
-
-        TrafficTreatment.Builder treatmentBuilder =
-                DefaultTrafficTreatment.builder();
-        treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
-
-        Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
-        ingressPoints.add(SW2_ETH1);
-        ingressPoints.add(SW3_ETH1);
-        ingressPoints.add(SW4_ETH1);
-
-        MultiPointToSinglePointIntent intent =
-                new MultiPointToSinglePointIntent(APPID,
-                        selectorBuilder.build(), treatmentBuilder.build(),
-                        ingressPoints, SW1_ETH1);
-
-        // Set up test expectation
-        reset(intentService);
-        // Setup the expected intents
-        IntentOperations.Builder builder = IntentOperations.builder(APPID);
-        builder.addSubmitOperation(intent);
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                                  routeEntry);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 1);
-        assertTrue(router.getRoutes4().contains(routeEntry));
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
-        Intent firstIntent =
-            intentSynchronizer.getRouteIntents().iterator().next();
-        IntentKey firstIntentKey = new IntentKey(firstIntent);
-        IntentKey intentKey = new IntentKey(intent);
-        assertTrue(firstIntentKey.equals(intentKey));
-        verify(intentService);
-    }
-
-    /**
-     * This method tests adding a route entry.
-     */
-    @Test
-    public void testRouteAddWithVlan() throws TestUtilsException {
-        // Construct a route entry
-        RouteEntry routeEntry = new RouteEntry(
-                Ip4Prefix.valueOf("3.3.3.0/24"),
-                Ip4Address.valueOf("192.168.40.1"));
-
-        // Construct a MultiPointToSinglePointIntent intent
-        TrafficSelector.Builder selectorBuilder =
-                DefaultTrafficSelector.builder();
-        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                       .matchIPDst(routeEntry.prefix())
-                       .matchVlanId(VlanId.ANY);
-
-        TrafficTreatment.Builder treatmentBuilder =
-                DefaultTrafficTreatment.builder();
-        treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:03"))
-                        .setVlanId(VlanId.vlanId((short) 1));
-
-        Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
-        ingressPoints.add(SW1_ETH1);
-        ingressPoints.add(SW2_ETH1);
-        ingressPoints.add(SW3_ETH1);
-
-        MultiPointToSinglePointIntent intent =
-                new MultiPointToSinglePointIntent(APPID,
-                        selectorBuilder.build(), treatmentBuilder.build(),
-                        ingressPoints, SW4_ETH1);
-
-        // Set up test expectation
-        reset(intentService);
-        // Setup the expected intents
-        IntentOperations.Builder builder = IntentOperations.builder(APPID);
-        builder.addSubmitOperation(intent);
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                                  routeEntry);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 1);
-        assertTrue(router.getRoutes4().contains(routeEntry));
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
-        Intent firstIntent =
-            intentSynchronizer.getRouteIntents().iterator().next();
-        IntentKey firstIntentKey = new IntentKey(firstIntent);
-        IntentKey intentKey = new IntentKey(intent);
-        assertTrue(firstIntentKey.equals(intentKey));
-        verify(intentService);
-    }
-
-    /**
-     * This method tests updating a route entry.
-     *
-     * @throws TestUtilsException
-     */
-    @Test
-    public void testRouteUpdate() throws TestUtilsException {
-        // Firstly add a route
-        testRouteAdd();
-
-        Intent addedIntent =
-            intentSynchronizer.getRouteIntents().iterator().next();
-
-        // Start to construct a new route entry and new intent
-        RouteEntry routeEntryUpdate = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("192.168.20.1"));
-
-        // Construct a new MultiPointToSinglePointIntent intent
-        TrafficSelector.Builder selectorBuilderNew =
-                DefaultTrafficSelector.builder();
-        selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
-                routeEntryUpdate.prefix());
-
-        TrafficTreatment.Builder treatmentBuilderNew =
-                DefaultTrafficTreatment.builder();
-        treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
-
-
-        Set<ConnectPoint> ingressPointsNew = new HashSet<ConnectPoint>();
-        ingressPointsNew.add(SW1_ETH1);
-        ingressPointsNew.add(SW3_ETH1);
-        ingressPointsNew.add(SW4_ETH1);
-
-        MultiPointToSinglePointIntent intentNew =
-                new MultiPointToSinglePointIntent(APPID,
-                        selectorBuilderNew.build(),
-                        treatmentBuilderNew.build(),
-                        ingressPointsNew, SW2_ETH1);
-
-        // Set up test expectation
-        reset(intentService);
-        // Setup the expected intents
-        IntentOperations.Builder builder = IntentOperations.builder(APPID);
-        builder.addWithdrawOperation(addedIntent.id());
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        builder = IntentOperations.builder(APPID);
-        builder.addSubmitOperation(intentNew);
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                                  routeEntryUpdate);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 1);
-        assertTrue(router.getRoutes4().contains(routeEntryUpdate));
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
-        Intent firstIntent =
-            intentSynchronizer.getRouteIntents().iterator().next();
-        IntentKey firstIntentKey = new IntentKey(firstIntent);
-        IntentKey intentNewKey = new IntentKey(intentNew);
-        assertTrue(firstIntentKey.equals(intentNewKey));
-        verify(intentService);
-    }
-
-    /**
-     * This method tests deleting a route entry.
-     */
-    @Test
-    public void testRouteDelete() throws TestUtilsException {
-        // Firstly add a route
-        testRouteAdd();
-
-        Intent addedIntent =
-            intentSynchronizer.getRouteIntents().iterator().next();
-
-        // Construct the existing route entry
-        RouteEntry routeEntry = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("192.168.10.1"));
-
-        // Set up expectation
-        reset(intentService);
-        // Setup the expected intents
-        IntentOperations.Builder builder = IntentOperations.builder(APPID);
-        builder.addWithdrawOperation(addedIntent.id());
-        intentService.execute(TestIntentServiceHelper.eqExceptId(
-                                builder.build()));
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE,
-                                                  routeEntry);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 0);
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 0);
-        verify(intentService);
-    }
-
-    /**
-     * This method tests when the next hop of a route is the local BGP speaker.
-     *
-     * @throws TestUtilsException
-     */
-    @Test
-    public void testLocalRouteAdd() throws TestUtilsException {
-        // Construct a route entry, the next hop is the local BGP speaker
-        RouteEntry routeEntry = new RouteEntry(
-                Ip4Prefix.valueOf("1.1.1.0/24"),
-                Ip4Address.valueOf("0.0.0.0"));
-
-        // Reset intentService to check whether the submit method is called
-        reset(intentService);
-        replay(intentService);
-
-        // Call the processRouteUpdates() method in Router class
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
-                                                  routeEntry);
-        router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
-
-        // Verify
-        assertEquals(router.getRoutes4().size(), 1);
-        assertTrue(router.getRoutes4().contains(routeEntry));
-        assertEquals(intentSynchronizer.getRouteIntents().size(), 0);
-        verify(intentService);
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpTest.java
deleted file mode 100644
index 157c73f..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/SdnIpTest.java
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import com.google.common.collect.Sets;
-import org.easymock.IAnswer;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.onlab.junit.IntegrationTest;
-import org.onlab.junit.TestUtils;
-import org.onlab.junit.TestUtils.TestUtilsException;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intent.AbstractIntentTest;
-import org.onosproject.net.intent.IntentService;
-import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.sdnip.config.BgpPeer;
-import org.onosproject.sdnip.config.Interface;
-import org.onosproject.sdnip.config.SdnIpConfigurationService;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Integration tests for the SDN-IP application.
- * <p/>
- * The tests are very coarse-grained. They feed route updates in to
- * {@link Router} (simulating routes learnt from iBGP module inside SDN-IP
- * application), then they check that the correct intents are created and
- * submitted to the intent service. The entire route processing logic of
- * Router class is tested.
- */
-@Category(IntegrationTest.class)
-public class SdnIpTest extends AbstractIntentTest {
-    private static final int MAC_ADDRESS_LENGTH = 6;
-    private static final int MIN_PREFIX_LENGTH = 1;
-    private static final int MAX_PREFIX_LENGTH = 32;
-
-    private IntentSynchronizer intentSynchronizer;
-    static Router router;
-
-    private SdnIpConfigurationService sdnIpConfigService;
-    private InterfaceService interfaceService;
-    private HostService hostService;
-    private IntentService intentService;
-
-    private Map<IpAddress, BgpPeer> bgpPeers;
-
-    private Random random;
-
-    static final ConnectPoint SW1_ETH1 = new ConnectPoint(
-            DeviceId.deviceId("of:0000000000000001"),
-            PortNumber.portNumber(1));
-
-    static final ConnectPoint SW2_ETH1 = new ConnectPoint(
-            DeviceId.deviceId("of:0000000000000002"),
-            PortNumber.portNumber(1));
-
-    static final ConnectPoint SW3_ETH1 = new ConnectPoint(
-            DeviceId.deviceId("of:0000000000000003"),
-            PortNumber.portNumber(1));
-
-    private static final ApplicationId APPID = new ApplicationId() {
-        @Override
-        public short id() {
-            return 1;
-        }
-
-        @Override
-        public String name() {
-            return "SDNIP";
-        }
-    };
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        setUpInterfaceService();
-        setUpSdnIpConfigService();
-
-        hostService = new TestHostService();
-        intentService = createMock(IntentService.class);
-        random = new Random();
-
-        intentSynchronizer = new IntentSynchronizer(APPID, intentService,
-                                                    sdnIpConfigService,
-                                                    interfaceService);
-        router = new Router(intentSynchronizer, hostService);
-    }
-
-    /**
-     * Sets up InterfaceService and virtual {@link Interface}s.
-     */
-    private void setUpInterfaceService() {
-
-        interfaceService = createMock(InterfaceService.class);
-
-        Set<Interface> interfaces = Sets.newHashSet();
-
-        Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
-        interfaceIpAddresses1.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.10.101"),
-                IpPrefix.valueOf("192.168.10.0/24")));
-        Interface sw1Eth1 = new Interface(SW1_ETH1,
-                interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"),
-                VlanId.NONE);
-        interfaces.add(sw1Eth1);
-
-        Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
-        interfaceIpAddresses2.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.20.101"),
-                IpPrefix.valueOf("192.168.20.0/24")));
-        Interface sw2Eth1 = new Interface(SW2_ETH1,
-                interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"),
-                VlanId.NONE);
-        interfaces.add(sw2Eth1);
-
-        Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
-        interfaceIpAddresses3.add(new InterfaceIpAddress(
-                IpAddress.valueOf("192.168.30.101"),
-                IpPrefix.valueOf("192.168.30.0/24")));
-        Interface sw3Eth1 = new Interface(SW3_ETH1,
-                interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"),
-                VlanId.NONE);
-        interfaces.add(sw3Eth1);
-
-        expect(interfaceService.getInterface(SW1_ETH1)).andReturn(
-                sw1Eth1).anyTimes();
-        expect(interfaceService.getInterface(SW2_ETH1)).andReturn(
-                sw2Eth1).anyTimes();
-        expect(interfaceService.getInterface(SW3_ETH1)).andReturn(
-                sw3Eth1).anyTimes();
-
-        expect(interfaceService.getInterfaces()).andReturn(
-                interfaces).anyTimes();
-        replay(interfaceService);
-    }
-
-    /**
-     * Sets up SdnIpConfigService and BGP peers in external networks.
-     */
-    private void setUpSdnIpConfigService() {
-
-        sdnIpConfigService = createMock(SdnIpConfigurationService.class);
-
-        bgpPeers = new HashMap<>();
-
-        String peerSw1Eth1 = "192.168.10.1";
-        bgpPeers.put(IpAddress.valueOf(peerSw1Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1));
-
-        String peer1Sw2Eth1 = "192.168.20.1";
-        bgpPeers.put(IpAddress.valueOf(peer1Sw2Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
-
-        String peer2Sw2Eth1 = "192.168.30.1";
-        bgpPeers.put(IpAddress.valueOf(peer2Sw2Eth1),
-                new BgpPeer("00:00:00:00:00:00:00:03", 1, peer2Sw2Eth1));
-
-        expect(sdnIpConfigService.getBgpPeers()).andReturn(bgpPeers).anyTimes();
-        replay(sdnIpConfigService);
-    }
-
-    /**
-     * Tests adding a set of routes into {@link Router}.
-     * <p/>
-     * Random routes are generated and fed in to the route processing
-     * logic (via processRouteAdd in Router class). We check that the correct
-     * intents are generated and submitted to our mock intent service.
-     *
-     * @throws InterruptedException if interrupted while waiting on a latch
-     * @throws TestUtilsException if exceptions when using TestUtils
-     */
-    @Test
-    public void testAddRoutes() throws InterruptedException, TestUtilsException {
-        int numRoutes = 100;
-
-        final CountDownLatch latch = new CountDownLatch(numRoutes);
-
-        List<RouteUpdate> routeUpdates = generateRouteUpdates(numRoutes);
-
-        // Set up expectation
-        reset(intentService);
-
-        for (RouteUpdate update : routeUpdates) {
-            IpAddress nextHopAddress = update.routeEntry().nextHop();
-
-            // Find out the egress ConnectPoint
-            ConnectPoint egressConnectPoint = getConnectPoint(nextHopAddress);
-
-            MultiPointToSinglePointIntent intent = getIntentForUpdate(update,
-                    generateMacAddress(nextHopAddress),
-                    egressConnectPoint);
-            intentService.submit(TestIntentServiceHelper.eqExceptId(intent));
-
-            expectLastCall().andAnswer(new IAnswer<Object>() {
-                @Override
-                public Object answer() throws Throwable {
-                    latch.countDown();
-                    return null;
-                }
-            }).once();
-        }
-
-        replay(intentService);
-
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-
-        // Add route updates
-        router.processRouteUpdates(routeUpdates);
-
-        latch.await(5000, TimeUnit.MILLISECONDS);
-
-        assertEquals(router.getRoutes4().size(), numRoutes);
-        assertEquals(intentSynchronizer.getRouteIntents().size(),
-                     numRoutes);
-
-        verify(intentService);
-    }
-
-    /**
-     * Tests adding then deleting a set of routes from {@link Router}.
-     * <p/>
-     * Random routes are generated and fed in to the route processing
-     * logic (via processRouteAdd in Router class), and we check that the
-     * correct intents are generated. We then delete the entire set of routes
-     * (by feeding updates to processRouteDelete), and check that the correct
-     * intents are withdrawn from the intent service.
-     *
-     * @throws InterruptedException if interrupted while waiting on a latch
-     * @throws TestUtilsException exceptions when using TestUtils
-     */
-    @Test
-    public void testDeleteRoutes() throws InterruptedException, TestUtilsException {
-        int numRoutes = 100;
-        List<RouteUpdate> routeUpdates = generateRouteUpdates(numRoutes);
-
-        final CountDownLatch installCount = new CountDownLatch(numRoutes);
-        final CountDownLatch deleteCount = new CountDownLatch(numRoutes);
-
-        // Set up expectation
-        reset(intentService);
-
-        for (RouteUpdate update : routeUpdates) {
-            IpAddress nextHopAddress = update.routeEntry().nextHop();
-
-            // Find out the egress ConnectPoint
-            ConnectPoint egressConnectPoint = getConnectPoint(nextHopAddress);
-            MultiPointToSinglePointIntent intent = getIntentForUpdate(update,
-                    generateMacAddress(nextHopAddress),
-                    egressConnectPoint);
-            intentService.submit(TestIntentServiceHelper.eqExceptId(intent));
-            expectLastCall().andAnswer(new IAnswer<Object>() {
-                @Override
-                public Object answer() throws Throwable {
-                    installCount.countDown();
-                    return null;
-                }
-            }).once();
-            intentService.withdraw(TestIntentServiceHelper.eqExceptId(intent));
-            expectLastCall().andAnswer(new IAnswer<Object>() {
-                @Override
-                public Object answer() throws Throwable {
-                    deleteCount.countDown();
-                    return null;
-                }
-            }).once();
-        }
-
-        replay(intentService);
-
-        intentSynchronizer.leaderChanged(true);
-        TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
-
-        // Send the add updates first
-        router.processRouteUpdates(routeUpdates);
-
-        // Give some time to let the intents be submitted
-        installCount.await(5000, TimeUnit.MILLISECONDS);
-
-        // Send the DELETE updates
-        List<RouteUpdate> deleteRouteUpdates = new ArrayList<>();
-        for (RouteUpdate update : routeUpdates) {
-            RouteUpdate deleteUpdate = new RouteUpdate(RouteUpdate.Type.DELETE,
-                                                       update.routeEntry());
-            deleteRouteUpdates.add(deleteUpdate);
-        }
-        router.processRouteUpdates(deleteRouteUpdates);
-
-        deleteCount.await(5000, TimeUnit.MILLISECONDS);
-
-        assertEquals(0, router.getRoutes4().size());
-        assertEquals(0, intentSynchronizer.getRouteIntents().size());
-        verify(intentService);
-    }
-
-    /**
-     * This methods generates random route updates.
-     *
-     * @param numRoutes the number of route updates to generate
-     * @return a list of route update
-     */
-    private List<RouteUpdate> generateRouteUpdates(int numRoutes) {
-        List<RouteUpdate> routeUpdates = new ArrayList<>(numRoutes);
-
-        Set<Ip4Prefix> prefixes = new HashSet<>();
-
-        for (int i = 0; i < numRoutes; i++) {
-            Ip4Prefix prefix;
-            do {
-                // Generate a random prefix length between MIN_PREFIX_LENGTH
-                // and MAX_PREFIX_LENGTH
-                int prefixLength = random.nextInt(
-                        (MAX_PREFIX_LENGTH - MIN_PREFIX_LENGTH) + 1)
-                        + MIN_PREFIX_LENGTH;
-                prefix =
-                    Ip4Prefix.valueOf(Ip4Address.valueOf(random.nextInt()),
-                                      prefixLength);
-                // We have to ensure we don't generate the same prefix twice
-                // (this is quite easy to happen with small prefix lengths).
-            } while (prefixes.contains(prefix));
-
-            prefixes.add(prefix);
-
-            // Randomly select a peer to use as the next hop
-            BgpPeer nextHop = null;
-            int peerNumber = random.nextInt(sdnIpConfigService.getBgpPeers()
-                    .size());
-            int j = 0;
-            for (BgpPeer peer : sdnIpConfigService.getBgpPeers().values()) {
-                if (j++ == peerNumber) {
-                    nextHop = peer;
-                    break;
-                }
-            }
-
-            assertNotNull(nextHop);
-
-            RouteUpdate update =
-                new RouteUpdate(RouteUpdate.Type.UPDATE,
-                        new RouteEntry(prefix,
-                                       nextHop.ipAddress().getIp4Address()));
-
-            routeUpdates.add(update);
-        }
-
-        return routeUpdates;
-    }
-
-    /**
-     * Generates the MultiPointToSinglePointIntent that should be
-     * submitted/withdrawn for a particular RouteUpdate.
-     *
-     * @param update the RouteUpdate to generate an intent for
-     * @param nextHopMac a MAC address to use as the dst-mac for the intent
-     * @param egressConnectPoint the outgoing ConnectPoint for the intent
-     * @return the generated intent
-     */
-    private MultiPointToSinglePointIntent getIntentForUpdate(RouteUpdate update,
-            MacAddress nextHopMac, ConnectPoint egressConnectPoint) {
-        IpPrefix ip4Prefix = update.routeEntry().prefix();
-
-        TrafficSelector.Builder selectorBuilder =
-                DefaultTrafficSelector.builder();
-
-        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ip4Prefix);
-
-        TrafficTreatment.Builder treatmentBuilder =
-                DefaultTrafficTreatment.builder();
-        treatmentBuilder.setEthDst(nextHopMac);
-
-        Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
-        for (Interface intf : interfaceService.getInterfaces()) {
-            if (!intf.connectPoint().equals(egressConnectPoint)) {
-                ConnectPoint srcPort = intf.connectPoint();
-                ingressPoints.add(srcPort);
-            }
-        }
-
-        MultiPointToSinglePointIntent intent =
-                new MultiPointToSinglePointIntent(APPID,
-                selectorBuilder.build(), treatmentBuilder.build(),
-                ingressPoints, egressConnectPoint);
-
-        return intent;
-    }
-
-    /**
-     * Generates a MAC address based on an IP address.
-     * For the test we need MAC addresses but the actual values don't have any
-     * meaning, so we'll just generate them based on the IP address. This means
-     * we have a deterministic mapping from IP address to MAC address.
-     *
-     * @param ipAddress IP address used to generate a MAC address
-     * @return generated MAC address
-     */
-    static MacAddress generateMacAddress(IpAddress ipAddress) {
-        byte[] macAddress = new byte[MAC_ADDRESS_LENGTH];
-        ByteBuffer bb = ByteBuffer.wrap(macAddress);
-
-        // Put the IP address bytes into the lower four bytes of the MAC
-        // address. Leave the first two bytes set to 0.
-        bb.position(2);
-        bb.put(ipAddress.toOctets());
-
-        return MacAddress.valueOf(bb.array());
-    }
-
-    /**
-     * Finds out the ConnectPoint for a BGP peer address.
-     *
-     * @param bgpPeerAddress the BGP peer address.
-     */
-    private ConnectPoint getConnectPoint(IpAddress bgpPeerAddress) {
-        ConnectPoint connectPoint = null;
-
-        for (BgpPeer bgpPeer: bgpPeers.values()) {
-            if (bgpPeer.ipAddress().equals(bgpPeerAddress)) {
-                connectPoint = bgpPeer.connectPoint();
-                break;
-            }
-        }
-        return connectPoint;
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/TestHostService.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/TestHostService.java
deleted file mode 100644
index 7e84f8e..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/TestHostService.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip;
-
-import java.util.HashSet;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultHost;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.PortAddresses;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.sdnip.Router.InternalHostListener;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-
-import com.google.common.collect.Sets;
-
-/**
- * Test version of the HostService which is used to simulate delays in
- * receiving ARP replies, as you would see in a real system due to the time
- * it takes to proxy ARP packets to/from the host. Requests are asynchronous,
- * and replies may come back to the requestor in a different order than the
- * requests were sent, which again you would expect to see in a real system.
- */
-public class TestHostService implements HostService {
-
-    /**
-     * The maximum possible delay before an ARP reply is received.
-     */
-    private static final int MAX_ARP_REPLY_DELAY = 30; // milliseconds
-
-    /**
-     * The probability that we already have the MAC address cached when the
-     * caller calls {@link #getHostsByIp(IpAddress ipAddress)}.
-     */
-    private static final float MAC_ALREADY_KNOWN_PROBABILITY = 0.3f;
-
-    private final ScheduledExecutorService replyTaskExecutor;
-    private final Random random;
-
-    /**
-     * Class constructor.
-     */
-    public TestHostService() {
-        replyTaskExecutor = Executors.newSingleThreadScheduledExecutor();
-        random = new Random();
-    }
-
-    /**
-     * Task used to reply to ARP requests from a different thread. Replies
-     * usually come on a different thread in the real system, so we need to
-     * ensure we test this behavior.
-     */
-    private class ReplyTask implements Runnable {
-        private HostListener listener;
-        private IpAddress ipAddress;
-
-        /**
-         * Class constructor.
-         *
-         * @param listener the client who requests and waits the MAC address
-         * @param ipAddress the target IP address of the request
-         */
-        public ReplyTask(InternalHostListener listener,
-                IpAddress ipAddress) {
-            this.listener = listener;
-            this.ipAddress = ipAddress;
-        }
-
-        @Override
-        public void run() {
-            Host host = getHostsByIp(ipAddress).iterator().next();
-            HostEvent hostevent =
-                    new HostEvent(HostEvent.Type.HOST_ADDED, host);
-            listener.event(hostevent);
-        }
-    }
-
-    @Override
-    public Set<Host> getHostsByIp(IpAddress ipAddress) {
-        float replyChance = random.nextFloat();
-
-        // We don't care what the attachment point is in the test,
-        // so for all the hosts, we use a same ConnectPoint.
-        Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
-                SdnIpTest.generateMacAddress(ipAddress), VlanId.NONE,
-                new HostLocation(SdnIpTest.SW1_ETH1, 1),
-                Sets.newHashSet(ipAddress));
-
-        if (replyChance < MAC_ALREADY_KNOWN_PROBABILITY) {
-            // Some percentage of the time we already know the MAC address, so
-            // we reply directly when the requestor asks for the MAC address
-            return Sets.newHashSet(host);
-        }
-        return new HashSet<Host>();
-    }
-
-    @Override
-    public void startMonitoringIp(IpAddress ipAddress) {
-
-        // Randomly select an amount of time to delay the reply coming back to
-        int delay = random.nextInt(MAX_ARP_REPLY_DELAY);
-        ReplyTask replyTask = new ReplyTask(
-                (SdnIpTest.router.new InternalHostListener()), ipAddress);
-        replyTaskExecutor.schedule(replyTask, delay, TimeUnit.MILLISECONDS);
-    }
-
-    @Override
-    public int getHostCount() {
-        return 0;
-    }
-
-    @Override
-    public Iterable<Host> getHosts() {
-        return null;
-    }
-
-    @Override
-    public Host getHost(HostId hostId) {
-        return null;
-    }
-
-    @Override
-    public Set<Host> getHostsByVlan(VlanId vlanId) {
-        return null;
-    }
-
-    @Override
-    public Set<Host> getHostsByMac(MacAddress mac) {
-        return null;
-    }
-
-    @Override
-    public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
-        return null;
-    }
-
-    @Override
-    public Set<Host> getConnectedHosts(DeviceId deviceId) {
-        return null;
-    }
-
-    @Override
-    public void stopMonitoringIp(IpAddress ip) {
-
-    }
-
-    @Override
-    public void requestMac(IpAddress ip) {
-
-    }
-
-    @Override
-    public Set<PortAddresses> getAddressBindings() {
-        return null;
-    }
-
-    @Override
-    public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
-        return null;
-    }
-
-    @Override
-    public void addListener(HostListener listener) {
-
-    }
-
-    @Override
-    public void removeListener(HostListener listener) {
-
-    }
-
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/AsPathTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/AsPathTest.java
deleted file mode 100644
index 481ca43..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/AsPathTest.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-
-import java.util.ArrayList;
-
-import org.junit.Test;
-
-/**
- * Unit tests for the BgpRouteEntry.AsPath class.
- */
-public class AsPathTest {
-    /**
-     * Generates Path Segments.
-     *
-     * @return the generated Path Segments
-     */
-    private ArrayList<BgpRouteEntry.PathSegment> generatePathSegments() {
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType;
-        ArrayList<Long> segmentAsNumbers;
-        BgpRouteEntry.PathSegment pathSegment;
-
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 1);
-        segmentAsNumbers.add((long) 2);
-        segmentAsNumbers.add((long) 3);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-        //
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SET;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 4);
-        segmentAsNumbers.add((long) 5);
-        segmentAsNumbers.add((long) 6);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-        //
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 7);
-        segmentAsNumbers.add((long) 8);
-        segmentAsNumbers.add((long) 9);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-        //
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SET;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 10);
-        segmentAsNumbers.add((long) 11);
-        segmentAsNumbers.add((long) 12);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-
-        return pathSegments;
-    }
-
-    /**
-     * Generates an AS Path.
-     *
-     * @return a generated AS Path
-     */
-    private BgpRouteEntry.AsPath generateAsPath() {
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments =
-            generatePathSegments();
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-
-        return asPath;
-    }
-
-    /**
-     * Tests valid class constructor.
-     */
-    @Test
-    public void testConstructor() {
-        BgpRouteEntry.AsPath asPath = generateAsPath();
-
-        String expectedString =
-            "AsPath{pathSegments=[" +
-            "PathSegment{type=AS_CONFED_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
-            "PathSegment{type=AS_CONFED_SET, segmentAsNumbers=[4, 5, 6]}, " +
-            "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[7, 8, 9]}, " +
-            "PathSegment{type=AS_SET, segmentAsNumbers=[10, 11, 12]}]}";
-        assertThat(asPath.toString(), is(expectedString));
-    }
-
-    /**
-     * Tests invalid class constructor for null Path Segments.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullPathSegments() {
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = null;
-        new BgpRouteEntry.AsPath(pathSegments);
-    }
-
-    /**
-     * Tests getting the fields of an AS Path.
-     */
-    @Test
-    public void testGetFields() {
-        // Create the fields to compare against
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments =
-            generatePathSegments();
-
-        // Generate the entry to test
-        BgpRouteEntry.AsPath asPath = generateAsPath();
-
-        assertThat(asPath.getPathSegments(), is(pathSegments));
-    }
-
-    /**
-     * Tests getting the AS Path Length.
-     */
-    @Test
-    public void testGetAsPathLength() {
-        //
-        // NOTE:
-        //  - AS_CONFED_SEQUENCE and AS_CONFED_SET are excluded
-        //  - AS_SET counts as a single hop
-        //
-        BgpRouteEntry.AsPath asPath = generateAsPath();
-        assertThat(asPath.getAsPathLength(), is(4));
-
-        // Create an empty AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        asPath = new BgpRouteEntry.AsPath(pathSegments);
-        assertThat(asPath.getAsPathLength(), is(0));
-    }
-
-    /**
-     * Tests equality of {@link BgpRouteEntry.AsPath}.
-     */
-    @Test
-    public void testEquality() {
-        BgpRouteEntry.AsPath asPath1 = generateAsPath();
-        BgpRouteEntry.AsPath asPath2 = generateAsPath();
-
-        assertThat(asPath1, is(asPath2));
-    }
-
-    /**
-     * Tests non-equality of {@link BgpRouteEntry.AsPath}.
-     */
-    @Test
-    public void testNonEquality() {
-        BgpRouteEntry.AsPath asPath1 = generateAsPath();
-
-        // Setup AS Path 2
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType;
-        ArrayList<Long> segmentAsNumbers;
-        BgpRouteEntry.PathSegment pathSegment;
-
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 1);
-        segmentAsNumbers.add((long) 2);
-        segmentAsNumbers.add((long) 3);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-        //
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SET;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 4);
-        segmentAsNumbers.add((long) 5);
-        segmentAsNumbers.add((long) 6);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-        //
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 7);
-        segmentAsNumbers.add((long) 8);
-        segmentAsNumbers.add((long) 9);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-        //
-        pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SET;
-        segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 10);
-        segmentAsNumbers.add((long) 111);                       // Different
-        segmentAsNumbers.add((long) 12);
-        pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-        pathSegments.add(pathSegment);
-        //
-        BgpRouteEntry.AsPath asPath2 = new BgpRouteEntry.AsPath(pathSegments);
-
-        assertThat(asPath1, is(not(asPath2)));
-    }
-
-    /**
-     * Tests object string representation.
-     */
-    @Test
-    public void testToString() {
-        BgpRouteEntry.AsPath asPath = generateAsPath();
-
-        String expectedString =
-            "AsPath{pathSegments=[" +
-            "PathSegment{type=AS_CONFED_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
-            "PathSegment{type=AS_CONFED_SET, segmentAsNumbers=[4, 5, 6]}, " +
-            "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[7, 8, 9]}, " +
-            "PathSegment{type=AS_SET, segmentAsNumbers=[10, 11, 12]}]}";
-        assertThat(asPath.toString(), is(expectedString));
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpRouteEntryTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpRouteEntryTest.java
deleted file mode 100644
index d53eb59..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpRouteEntryTest.java
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-
-import java.util.ArrayList;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-
-/**
- * Unit tests for the BgpRouteEntry class.
- */
-public class BgpRouteEntryTest {
-    private BgpSession bgpSession;
-    private static final Ip4Address BGP_SESSION_BGP_ID =
-        Ip4Address.valueOf("10.0.0.1");
-    private static final Ip4Address BGP_SESSION_IP_ADDRESS =
-        Ip4Address.valueOf("20.0.0.1");
-
-    private BgpSession bgpSession2;
-    private static final Ip4Address BGP_SESSION_BGP_ID2 =
-        Ip4Address.valueOf("10.0.0.2");
-    private static final Ip4Address BGP_SESSION_IP_ADDRESS2 =
-        Ip4Address.valueOf("20.0.0.1");
-
-    private BgpSession bgpSession3;
-    private static final Ip4Address BGP_SESSION_BGP_ID3 =
-        Ip4Address.valueOf("10.0.0.1");
-    private static final Ip4Address BGP_SESSION_IP_ADDRESS3 =
-        Ip4Address.valueOf("20.0.0.2");
-
-    private final BgpSessionInfo localInfo = new BgpSessionInfo();
-    private final BgpSessionInfo remoteInfo = new BgpSessionInfo();
-
-    private final BgpSessionInfo localInfo2 = new BgpSessionInfo();
-    private final BgpSessionInfo remoteInfo2 = new BgpSessionInfo();
-
-    private final BgpSessionInfo localInfo3 = new BgpSessionInfo();
-    private final BgpSessionInfo remoteInfo3 = new BgpSessionInfo();
-
-    @Before
-    public void setUp() throws Exception {
-        // Mock objects for testing
-        bgpSession = createMock(BgpSession.class);
-        bgpSession2 = createMock(BgpSession.class);
-        bgpSession3 = createMock(BgpSession.class);
-
-        // Setup the BGP Sessions
-        remoteInfo.setIp4Address(BGP_SESSION_IP_ADDRESS);
-        remoteInfo2.setIp4Address(BGP_SESSION_IP_ADDRESS2);
-        remoteInfo3.setIp4Address(BGP_SESSION_IP_ADDRESS3);
-        remoteInfo.setBgpId(BGP_SESSION_BGP_ID);
-        remoteInfo2.setBgpId(BGP_SESSION_BGP_ID2);
-        remoteInfo3.setBgpId(BGP_SESSION_BGP_ID3);
-
-        expect(bgpSession.localInfo()).andReturn(localInfo).anyTimes();
-        expect(bgpSession.remoteInfo()).andReturn(remoteInfo).anyTimes();
-        expect(bgpSession2.localInfo()).andReturn(localInfo2).anyTimes();
-        expect(bgpSession2.remoteInfo()).andReturn(remoteInfo2).anyTimes();
-        expect(bgpSession3.localInfo()).andReturn(localInfo3).anyTimes();
-        expect(bgpSession3.remoteInfo()).andReturn(remoteInfo3).anyTimes();
-
-        replay(bgpSession);
-        replay(bgpSession2);
-        replay(bgpSession3);
-    }
-
-    /**
-     * Generates a BGP Route Entry.
-     *
-     * @return a generated BGP Route Entry
-     */
-    private BgpRouteEntry generateBgpRouteEntry() {
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        // Setup the AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
-        segmentAsNumbers1.add((long) 1);
-        segmentAsNumbers1.add((long) 2);
-        segmentAsNumbers1.add((long) 3);
-        BgpRouteEntry.PathSegment pathSegment1 =
-            new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
-        pathSegments.add(pathSegment1);
-        //
-        byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
-        ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
-        segmentAsNumbers2.add((long) 4);
-        segmentAsNumbers2.add((long) 5);
-        segmentAsNumbers2.add((long) 6);
-        BgpRouteEntry.PathSegment pathSegment2 =
-            new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
-        pathSegments.add(pathSegment2);
-        //
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-        //
-        long localPref = 100;
-        long multiExitDisc = 20;
-
-        BgpRouteEntry bgpRouteEntry =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry.setMultiExitDisc(multiExitDisc);
-
-        return bgpRouteEntry;
-    }
-
-    /**
-     * Tests valid class constructor.
-     */
-    @Test
-    public void testConstructor() {
-        BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
-
-        String expectedString =
-            "BgpRouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8, " +
-            "bgpId=10.0.0.1, origin=IGP, asPath=AsPath{pathSegments=" +
-            "[PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
-            "PathSegment{type=AS_SET, segmentAsNumbers=[4, 5, 6]}]}, " +
-            "localPref=100, multiExitDisc=20}";
-        assertThat(bgpRouteEntry.toString(), is(expectedString));
-    }
-
-    /**
-     * Tests invalid class constructor for null BGP Session.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullBgpSession() {
-        BgpSession bgpSessionNull = null;
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        // Setup the AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-        //
-        long localPref = 100;
-
-        new BgpRouteEntry(bgpSessionNull, prefix, nextHop, origin, asPath,
-                    localPref);
-    }
-
-    /**
-     * Tests invalid class constructor for null AS Path.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullAsPath() {
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        BgpRouteEntry.AsPath asPath = null;
-        long localPref = 100;
-
-        new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                    localPref);
-    }
-
-    /**
-     * Tests getting the fields of a BGP route entry.
-     */
-    @Test
-    public void testGetFields() {
-        // Create the fields to compare against
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        // Setup the AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
-        segmentAsNumbers1.add((long) 1);
-        segmentAsNumbers1.add((long) 2);
-        segmentAsNumbers1.add((long) 3);
-        BgpRouteEntry.PathSegment pathSegment1 =
-            new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
-        pathSegments.add(pathSegment1);
-        //
-        byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
-        ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
-        segmentAsNumbers2.add((long) 4);
-        segmentAsNumbers2.add((long) 5);
-        segmentAsNumbers2.add((long) 6);
-        BgpRouteEntry.PathSegment pathSegment2 =
-            new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
-        pathSegments.add(pathSegment2);
-        //
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-        //
-        long localPref = 100;
-        long multiExitDisc = 20;
-
-        // Generate the entry to test
-        BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
-
-        assertThat(bgpRouteEntry.prefix(), is(prefix));
-        assertThat(bgpRouteEntry.nextHop(), is(nextHop));
-        assertThat(bgpRouteEntry.getBgpSession(), is(bgpSession));
-        assertThat(bgpRouteEntry.getOrigin(), is(origin));
-        assertThat(bgpRouteEntry.getAsPath(), is(asPath));
-        assertThat(bgpRouteEntry.getLocalPref(), is(localPref));
-        assertThat(bgpRouteEntry.getMultiExitDisc(), is(multiExitDisc));
-    }
-
-    /**
-     * Tests whether a BGP route entry is a local route.
-     */
-    @Test
-    public void testIsLocalRoute() {
-        //
-        // Test non-local route
-        //
-        BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
-        assertThat(bgpRouteEntry.isLocalRoute(), is(false));
-
-        //
-        // Test local route with AS Path that begins with AS_SET
-        //
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        // Setup the AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SET;
-        ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
-        segmentAsNumbers1.add((long) 1);
-        segmentAsNumbers1.add((long) 2);
-        segmentAsNumbers1.add((long) 3);
-        BgpRouteEntry.PathSegment pathSegment1 =
-            new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
-        pathSegments.add(pathSegment1);
-        //
-        byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
-        segmentAsNumbers2.add((long) 4);
-        segmentAsNumbers2.add((long) 5);
-        segmentAsNumbers2.add((long) 6);
-        BgpRouteEntry.PathSegment pathSegment2 =
-            new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
-        pathSegments.add(pathSegment2);
-        //
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-        //
-        long localPref = 100;
-        long multiExitDisc = 20;
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry.setMultiExitDisc(multiExitDisc);
-        assertThat(bgpRouteEntry.isLocalRoute(), is(true));
-
-        //
-        // Test local route with empty AS Path
-        //
-        pathSegments = new ArrayList<>();
-        asPath = new BgpRouteEntry.AsPath(pathSegments);
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry.setMultiExitDisc(multiExitDisc);
-        assertThat(bgpRouteEntry.isLocalRoute(), is(true));
-    }
-
-    /**
-     * Tests getting the BGP Neighbor AS number for a route.
-     */
-    @Test
-    public void testGetNeighborAs() {
-        //
-        // Get neighbor AS for non-local route
-        //
-        BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
-        assertThat(bgpRouteEntry.getNeighborAs(), is((long) 1));
-
-        //
-        // Get neighbor AS for a local route
-        //
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        // Setup the AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-        //
-        long localPref = 100;
-        long multiExitDisc = 20;
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry.setMultiExitDisc(multiExitDisc);
-        assertThat(bgpRouteEntry.getNeighborAs(), is(BgpConstants.BGP_AS_0));
-    }
-
-    /**
-     * Tests whether a BGP route entry has AS Path loop.
-     */
-    @Test
-    public void testHasAsPathLoop() {
-        BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
-
-        // Test for loops: test each AS number in the interval [1, 6]
-        for (int i = 1; i <= 6; i++) {
-            assertThat(bgpRouteEntry.hasAsPathLoop(i), is(true));
-        }
-
-        // Test for non-loops
-        assertThat(bgpRouteEntry.hasAsPathLoop(500), is(false));
-    }
-
-    /**
-     * Tests the BGP Decision Process comparison of BGP routes.
-     */
-    @Test
-    public void testBgpDecisionProcessComparison() {
-        BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
-        BgpRouteEntry bgpRouteEntry2 = generateBgpRouteEntry();
-
-        //
-        // Compare two routes that are same
-        //
-        assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
-        assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(true));
-
-        //
-        // Compare two routes with different LOCAL_PREF
-        //
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        // Setup the AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
-        segmentAsNumbers1.add((long) 1);
-        segmentAsNumbers1.add((long) 2);
-        segmentAsNumbers1.add((long) 3);
-        BgpRouteEntry.PathSegment pathSegment1 =
-            new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
-        pathSegments.add(pathSegment1);
-        //
-        byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
-        ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
-        segmentAsNumbers2.add((long) 4);
-        segmentAsNumbers2.add((long) 5);
-        segmentAsNumbers2.add((long) 6);
-        BgpRouteEntry.PathSegment pathSegment2 =
-            new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
-        pathSegments.add(pathSegment2);
-        //
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-        //
-        long localPref = 50;                                    // Different
-        long multiExitDisc = 20;
-        bgpRouteEntry2 =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
-        //
-        assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
-        assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
-        localPref = bgpRouteEntry1.getLocalPref();              // Restore
-
-        //
-        // Compare two routes with different AS_PATH length
-        //
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments2 = new ArrayList<>();
-        pathSegments2.add(pathSegment1);
-        // Different AS Path
-        BgpRouteEntry.AsPath asPath2 = new BgpRouteEntry.AsPath(pathSegments2);
-        bgpRouteEntry2 =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath2,
-                              localPref);
-        bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
-        //
-        assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(false));
-        assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(true));
-
-        //
-        // Compare two routes with different ORIGIN
-        //
-        origin = BgpConstants.Update.Origin.EGP;                // Different
-        bgpRouteEntry2 =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
-        //
-        assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
-        assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
-        origin = bgpRouteEntry1.getOrigin();                    // Restore
-
-        //
-        // Compare two routes with different MULTI_EXIT_DISC
-        //
-        multiExitDisc = 10;                                     // Different
-        bgpRouteEntry2 =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
-        //
-        assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
-        assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
-        multiExitDisc = bgpRouteEntry1.getMultiExitDisc();      // Restore
-
-        //
-        // Compare two routes with different BGP ID
-        //
-        bgpRouteEntry2 =
-            new BgpRouteEntry(bgpSession2, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
-        //
-        assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
-        assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
-
-        //
-        // Compare two routes with different BGP address
-        //
-        bgpRouteEntry2 =
-            new BgpRouteEntry(bgpSession3, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
-        //
-        assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
-        assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
-    }
-
-    /**
-     * Tests equality of {@link BgpRouteEntry}.
-     */
-    @Test
-    public void testEquality() {
-        BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
-        BgpRouteEntry bgpRouteEntry2 = generateBgpRouteEntry();
-
-        assertThat(bgpRouteEntry1, is(bgpRouteEntry2));
-    }
-
-    /**
-     * Tests non-equality of {@link BgpRouteEntry}.
-     */
-    @Test
-    public void testNonEquality() {
-        BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
-
-        // Setup BGP Route 2
-        Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
-        Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-        byte origin = BgpConstants.Update.Origin.IGP;
-        // Setup the AS Path
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
-        segmentAsNumbers1.add((long) 1);
-        segmentAsNumbers1.add((long) 2);
-        segmentAsNumbers1.add((long) 3);
-        BgpRouteEntry.PathSegment pathSegment1 =
-            new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
-        pathSegments.add(pathSegment1);
-        //
-        byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
-        ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
-        segmentAsNumbers2.add((long) 4);
-        segmentAsNumbers2.add((long) 5);
-        segmentAsNumbers2.add((long) 6);
-        BgpRouteEntry.PathSegment pathSegment2 =
-            new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
-        pathSegments.add(pathSegment2);
-        //
-        BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
-        //
-        long localPref = 500;                                   // Different
-        long multiExitDisc = 20;
-        BgpRouteEntry bgpRouteEntry2 =
-            new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
-                              localPref);
-        bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
-
-        assertThat(bgpRouteEntry1, is(not(bgpRouteEntry2)));
-    }
-
-    /**
-     * Tests object string representation.
-     */
-    @Test
-    public void testToString() {
-        BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
-
-        String expectedString =
-            "BgpRouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8, " +
-            "bgpId=10.0.0.1, origin=IGP, asPath=AsPath{pathSegments=" +
-            "[PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
-            "PathSegment{type=AS_SET, segmentAsNumbers=[4, 5, 6]}]}, " +
-            "localPref=100, multiExitDisc=20}";
-        assertThat(bgpRouteEntry.toString(), is(expectedString));
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
deleted file mode 100644
index 7ae8658..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
-import org.jboss.netty.bootstrap.ClientBootstrap;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelFactory;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.junit.TestUtils;
-import org.onlab.junit.TestUtils.TestUtilsException;
-import org.onosproject.sdnip.RouteListener;
-import org.onosproject.sdnip.RouteUpdate;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-
-import com.google.common.net.InetAddresses;
-
-/**
- * Unit tests for the BgpSessionManager class.
- */
-public class BgpSessionManagerTest {
-    private static final Ip4Address IP_LOOPBACK_ID =
-        Ip4Address.valueOf("127.0.0.1");
-    private static final Ip4Address BGP_PEER1_ID =
-        Ip4Address.valueOf("10.0.0.1");
-    private static final Ip4Address BGP_PEER2_ID =
-        Ip4Address.valueOf("10.0.0.2");
-    private static final Ip4Address BGP_PEER3_ID =
-        Ip4Address.valueOf("10.0.0.3");
-    private static final Ip4Address NEXT_HOP1_ROUTER =
-        Ip4Address.valueOf("10.20.30.41");
-    private static final Ip4Address NEXT_HOP2_ROUTER =
-        Ip4Address.valueOf("10.20.30.42");
-    private static final Ip4Address NEXT_HOP3_ROUTER =
-        Ip4Address.valueOf("10.20.30.43");
-
-    private static final long DEFAULT_LOCAL_PREF = 10;
-    private static final long BETTER_LOCAL_PREF = 20;
-    private static final long DEFAULT_MULTI_EXIT_DISC = 20;
-    private static final long BETTER_MULTI_EXIT_DISC = 30;
-
-    BgpRouteEntry.AsPath asPathShort;
-    BgpRouteEntry.AsPath asPathLong;
-
-    // Timeout waiting for a message to be received
-    private static final int MESSAGE_TIMEOUT_MS = 5000; // 5s
-
-    // The BGP Session Manager to test
-    private BgpSessionManager bgpSessionManager;
-
-    // Remote Peer state
-    private final Collection<TestBgpPeer> peers = new LinkedList<>();
-    TestBgpPeer peer1;
-    TestBgpPeer peer2;
-    TestBgpPeer peer3;
-
-    // Local BGP per-peer session state
-    BgpSession bgpSession1;
-    BgpSession bgpSession2;
-    BgpSession bgpSession3;
-
-    // The socket that the remote peers should connect to
-    private InetSocketAddress connectToSocket;
-
-    private final DummyRouteListener dummyRouteListener =
-        new DummyRouteListener();
-
-    /**
-     * Dummy implementation for the RouteListener interface.
-     */
-    private class DummyRouteListener implements RouteListener {
-        @Override
-        public void update(Collection<RouteUpdate> routeUpdate) {
-            // Nothing to do
-        }
-    }
-
-    /**
-     * A class to capture the state for a BGP peer.
-     */
-    private final class TestBgpPeer {
-        private final Ip4Address peerId;
-        private ClientBootstrap peerBootstrap;
-        private TestBgpPeerChannelHandler peerChannelHandler;
-        private TestBgpPeerFrameDecoder peerFrameDecoder =
-            new TestBgpPeerFrameDecoder();
-
-        /**
-         * Constructor.
-         *
-         * @param peerId the peer ID
-         */
-        private TestBgpPeer(Ip4Address peerId) {
-            this.peerId = peerId;
-            peerChannelHandler = new TestBgpPeerChannelHandler(peerId);
-        }
-
-        /**
-         * Starts up the BGP peer and connects it to the tested SDN-IP
-         * instance.
-         *
-         * @param connectToSocket the socket to connect to
-         */
-        private void connect(InetSocketAddress connectToSocket)
-            throws InterruptedException {
-            //
-            // Setup the BGP Peer, i.e., the "remote" BGP router that will
-            // initiate the BGP connection, send BGP UPDATE messages, etc.
-            //
-            ChannelFactory channelFactory =
-                new NioClientSocketChannelFactory(
-                        Executors.newCachedThreadPool(),
-                        Executors.newCachedThreadPool());
-            ChannelPipelineFactory pipelineFactory =
-                new ChannelPipelineFactory() {
-                    @Override
-                    public ChannelPipeline getPipeline() throws Exception {
-                        // Setup the transmitting pipeline
-                        ChannelPipeline pipeline = Channels.pipeline();
-                        pipeline.addLast("TestBgpPeerFrameDecoder",
-                                         peerFrameDecoder);
-                        pipeline.addLast("TestBgpPeerChannelHandler",
-                                         peerChannelHandler);
-                        return pipeline;
-                    }
-                };
-
-            peerBootstrap = new ClientBootstrap(channelFactory);
-            peerBootstrap.setOption("child.keepAlive", true);
-            peerBootstrap.setOption("child.tcpNoDelay", true);
-            peerBootstrap.setPipelineFactory(pipelineFactory);
-            peerBootstrap.connect(connectToSocket);
-
-            boolean result;
-            // Wait until the OPEN message is received
-            result = peerFrameDecoder.receivedOpenMessageLatch.await(
-                MESSAGE_TIMEOUT_MS,
-                TimeUnit.MILLISECONDS);
-            assertThat(result, is(true));
-            // Wait until the KEEPALIVE message is received
-            result = peerFrameDecoder.receivedKeepaliveMessageLatch.await(
-                MESSAGE_TIMEOUT_MS,
-                TimeUnit.MILLISECONDS);
-            assertThat(result, is(true));
-
-            for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
-                if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER1_ID)) {
-                    bgpSession1 = bgpSession;
-                }
-                if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER2_ID)) {
-                    bgpSession2 = bgpSession;
-                }
-                if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER3_ID)) {
-                    bgpSession3 = bgpSession;
-                }
-            }
-        }
-    }
-
-    /**
-     * Class that implements a matcher for BgpRouteEntry by considering
-     * the BGP peer the entry was received from.
-     */
-    private static final class BgpRouteEntryAndPeerMatcher
-        extends TypeSafeMatcher<Collection<BgpRouteEntry>> {
-        private final BgpRouteEntry bgpRouteEntry;
-
-        private BgpRouteEntryAndPeerMatcher(BgpRouteEntry bgpRouteEntry) {
-            this.bgpRouteEntry = bgpRouteEntry;
-        }
-
-        @Override
-        public boolean matchesSafely(Collection<BgpRouteEntry> entries) {
-            for (BgpRouteEntry entry : entries) {
-                if (bgpRouteEntry.equals(entry) &&
-                    bgpRouteEntry.getBgpSession() == entry.getBgpSession()) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("BGP route entry lookup for entry \"").
-                appendText(bgpRouteEntry.toString()).
-                appendText("\"");
-        }
-    }
-
-    /**
-     * A helper method used for testing whether a collection of
-     * BGP route entries contains an entry from a specific BGP peer.
-     *
-     * @param bgpRouteEntry the BGP route entry to test
-     * @return an instance of BgpRouteEntryAndPeerMatcher that implements
-     * the matching logic
-     */
-    private static BgpRouteEntryAndPeerMatcher hasBgpRouteEntry(
-        BgpRouteEntry bgpRouteEntry) {
-        return new BgpRouteEntryAndPeerMatcher(bgpRouteEntry);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        peer1 = new TestBgpPeer(BGP_PEER1_ID);
-        peer2 = new TestBgpPeer(BGP_PEER2_ID);
-        peer3 = new TestBgpPeer(BGP_PEER3_ID);
-        peers.clear();
-        peers.add(peer1);
-        peers.add(peer2);
-        peers.add(peer3);
-
-        //
-        // Setup the BGP Session Manager to test, and start listening for BGP
-        // connections.
-        //
-        bgpSessionManager = new BgpSessionManager(dummyRouteListener);
-        // NOTE: We use port 0 to bind on any available port
-        bgpSessionManager.start(0);
-
-        // Get the port number the BGP Session Manager is listening on
-        Channel serverChannel = TestUtils.getField(bgpSessionManager,
-                                                   "serverChannel");
-        SocketAddress socketAddress = serverChannel.getLocalAddress();
-        InetSocketAddress inetSocketAddress =
-            (InetSocketAddress) socketAddress;
-        InetAddress connectToAddress = InetAddresses.forString("127.0.0.1");
-        connectToSocket = new InetSocketAddress(connectToAddress,
-                                                inetSocketAddress.getPort());
-
-        //
-        // Setup the AS Paths
-        //
-        ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-        byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
-        segmentAsNumbers1.add((long) 65010);
-        segmentAsNumbers1.add((long) 65020);
-        segmentAsNumbers1.add((long) 65030);
-        BgpRouteEntry.PathSegment pathSegment1 =
-            new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
-        pathSegments.add(pathSegment1);
-        asPathShort = new BgpRouteEntry.AsPath(new ArrayList(pathSegments));
-        //
-        byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
-        ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
-        segmentAsNumbers2.add((long) 65041);
-        segmentAsNumbers2.add((long) 65042);
-        segmentAsNumbers2.add((long) 65043);
-        BgpRouteEntry.PathSegment pathSegment2 =
-            new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
-        pathSegments.add(pathSegment2);
-        //
-        asPathLong = new BgpRouteEntry.AsPath(pathSegments);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        bgpSessionManager.stop();
-        bgpSessionManager = null;
-    }
-
-    /**
-     * Gets BGP RIB-IN routes by waiting until they are received.
-     * <p>
-     * NOTE: We keep checking once every 10ms the number of received routes,
-     * up to 5 seconds.
-     * </p>
-     *
-     * @param bgpSession the BGP session that is expected to receive the
-     * routes
-     * @param expectedRoutes the expected number of routes
-     * @return the BGP RIB-IN routes as received within the expected
-     * time interval
-     */
-    private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
-                                                      long expectedRoutes)
-        throws InterruptedException {
-        Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn4();
-
-        final int maxChecks = 500;              // Max wait of 5 seconds
-        for (int i = 0; i < maxChecks; i++) {
-            if (bgpRibIn.size() == expectedRoutes) {
-                break;
-            }
-            Thread.sleep(10);
-            bgpRibIn = bgpSession.getBgpRibIn4();
-        }
-
-        return bgpRibIn;
-    }
-
-    /**
-     * Gets BGP merged routes by waiting until they are received.
-     * <p>
-     * NOTE: We keep checking once every 10ms the number of received routes,
-     * up to 5 seconds.
-     * </p>
-     *
-     * @param expectedRoutes the expected number of routes
-     * @return the BGP Session Manager routes as received within the expected
-     * time interval
-     */
-    private Collection<BgpRouteEntry> waitForBgpRoutes(long expectedRoutes)
-        throws InterruptedException {
-        Collection<BgpRouteEntry> bgpRoutes =
-            bgpSessionManager.getBgpRoutes4();
-
-        final int maxChecks = 500;              // Max wait of 5 seconds
-        for (int i = 0; i < maxChecks; i++) {
-            if (bgpRoutes.size() == expectedRoutes) {
-                break;
-            }
-            Thread.sleep(10);
-            bgpRoutes = bgpSessionManager.getBgpRoutes4();
-        }
-
-        return bgpRoutes;
-    }
-
-    /**
-     * Gets a merged BGP route by waiting until it is received.
-     * <p>
-     * NOTE: We keep checking once every 10ms whether the route is received,
-     * up to 5 seconds.
-     * </p>
-     *
-     * @param expectedRoute the expected route
-     * @return the merged BGP route if received within the expected time
-     * interval, otherwise null
-     */
-    private BgpRouteEntry waitForBgpRoute(BgpRouteEntry expectedRoute)
-        throws InterruptedException {
-        Collection<BgpRouteEntry> bgpRoutes =
-            bgpSessionManager.getBgpRoutes4();
-
-        final int maxChecks = 500;              // Max wait of 5 seconds
-        for (int i = 0; i < maxChecks; i++) {
-            for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
-                if (bgpRouteEntry.equals(expectedRoute) &&
-                    bgpRouteEntry.getBgpSession() ==
-                    expectedRoute.getBgpSession()) {
-                    return bgpRouteEntry;
-                }
-            }
-            Thread.sleep(10);
-            bgpRoutes = bgpSessionManager.getBgpRoutes4();
-        }
-
-        return null;
-    }
-
-    /**
-     * Tests that the BGP OPEN messages have been exchanged, followed by
-     * KEEPALIVE.
-     * <p>
-     * The BGP Peer opens the sessions and transmits OPEN Message, eventually
-     * followed by KEEPALIVE. The tested BGP listener should respond by
-     * OPEN Message, followed by KEEPALIVE.
-     * </p>
-     *
-     * @throws TestUtilsException TestUtils error
-     */
-    @Test
-    public void testExchangedBgpOpenMessages()
-            throws InterruptedException, TestUtilsException {
-        // Initiate the connections
-        peer1.connect(connectToSocket);
-        peer2.connect(connectToSocket);
-        peer3.connect(connectToSocket);
-
-        //
-        // Test the fields from the BGP OPEN message:
-        // BGP version, AS number, BGP ID
-        //
-        for (TestBgpPeer peer : peers) {
-            assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
-                       is(BgpConstants.BGP_VERSION));
-            assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
-                       is(IP_LOOPBACK_ID));
-            assertThat(peer.peerFrameDecoder.remoteInfo.asNumber(),
-                       is(TestBgpPeerChannelHandler.PEER_AS));
-        }
-
-        //
-        // Test that the BgpSession instances have been created
-        //
-        assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
-        assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
-        assertThat(bgpSession1, notNullValue());
-        assertThat(bgpSession2, notNullValue());
-        assertThat(bgpSession3, notNullValue());
-        for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
-            long sessionAs = bgpSession.localInfo().asNumber();
-            assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
-        }
-    }
-
-
-    /**
-     * Tests that the BGP OPEN with Capability messages have been exchanged,
-     * followed by KEEPALIVE.
-     * <p>
-     * The BGP Peer opens the sessions and transmits OPEN Message, eventually
-     * followed by KEEPALIVE. The tested BGP listener should respond by
-     * OPEN Message, followed by KEEPALIVE.
-     * </p>
-     *
-     * @throws TestUtilsException TestUtils error
-     */
-    @Test
-    public void testExchangedBgpOpenCapabilityMessages()
-            throws InterruptedException, TestUtilsException {
-        //
-        // Setup the BGP Capabilities for all peers
-        //
-        for (TestBgpPeer peer : peers) {
-            peer.peerChannelHandler.localInfo.setIpv4Unicast();
-            peer.peerChannelHandler.localInfo.setIpv4Multicast();
-            peer.peerChannelHandler.localInfo.setIpv6Unicast();
-            peer.peerChannelHandler.localInfo.setIpv6Multicast();
-            peer.peerChannelHandler.localInfo.setAs4OctetCapability();
-            peer.peerChannelHandler.localInfo.setAs4Number(
-                TestBgpPeerChannelHandler.PEER_AS4);
-        }
-
-        // Initiate the connections
-        peer1.connect(connectToSocket);
-        peer2.connect(connectToSocket);
-        peer3.connect(connectToSocket);
-
-        //
-        // Test the fields from the BGP OPEN message:
-        // BGP version, BGP ID
-        //
-        for (TestBgpPeer peer : peers) {
-            assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
-                       is(BgpConstants.BGP_VERSION));
-            assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
-                       is(IP_LOOPBACK_ID));
-        }
-
-        //
-        // Test that the BgpSession instances have been created,
-        // and contain the appropriate BGP session information.
-        //
-        assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
-        assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
-        assertThat(bgpSession1, notNullValue());
-        assertThat(bgpSession2, notNullValue());
-        assertThat(bgpSession3, notNullValue());
-        for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
-            BgpSessionInfo localInfo = bgpSession.localInfo();
-            assertThat(localInfo.ipv4Unicast(), is(true));
-            assertThat(localInfo.ipv4Multicast(), is(true));
-            assertThat(localInfo.ipv6Unicast(), is(true));
-            assertThat(localInfo.ipv6Multicast(), is(true));
-            assertThat(localInfo.as4OctetCapability(), is(true));
-            assertThat(localInfo.asNumber(),
-                       is(TestBgpPeerChannelHandler.PEER_AS4));
-            assertThat(localInfo.as4Number(),
-                       is(TestBgpPeerChannelHandler.PEER_AS4));
-        }
-    }
-
-    /**
-     * Tests that the BGP UPDATE messages have been received and processed.
-     */
-    @Test
-    public void testProcessedBgpUpdateMessages() throws InterruptedException {
-        ChannelBuffer message;
-        BgpRouteEntry bgpRouteEntry;
-        Collection<BgpRouteEntry> bgpRibIn1;
-        Collection<BgpRouteEntry> bgpRibIn2;
-        Collection<BgpRouteEntry> bgpRibIn3;
-        Collection<BgpRouteEntry> bgpRoutes;
-
-        // Initiate the connections
-        peer1.connect(connectToSocket);
-        peer2.connect(connectToSocket);
-        peer3.connect(connectToSocket);
-
-        // Prepare routes to add/delete
-        Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
-        Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
-
-        //
-        // Add and delete some routes
-        //
-        addedRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
-        addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
-        addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
-        addedRoutes.add(Ip4Prefix.valueOf("40.0.0.0/24"));
-        addedRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
-        withdrawnRoutes.add(Ip4Prefix.valueOf("60.0.0.0/8"));
-        withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
-        withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
-        withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
-        // Write the routes
-        message = peer1.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP1_ROUTER,
-                        DEFAULT_LOCAL_PREF,
-                        DEFAULT_MULTI_EXIT_DISC,
-                        asPathLong,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer1.peerChannelHandler.savedCtx.getChannel().write(message);
-        //
-        // Check that the routes have been received, processed and stored
-        //
-        bgpRibIn1 = waitForBgpRibIn(bgpSession1, 5);
-        assertThat(bgpRibIn1, hasSize(5));
-        bgpRoutes = waitForBgpRoutes(5);
-        assertThat(bgpRoutes, hasSize(5));
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("0.0.0.0/0"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("20.0.0.0/8"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("30.0.0.0/16"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("40.0.0.0/24"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("50.0.0.0/32"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-
-        //
-        // Delete some routes
-        //
-        addedRoutes = new LinkedList<>();
-        withdrawnRoutes = new LinkedList<>();
-        withdrawnRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
-        withdrawnRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
-        // Write the routes
-        message = peer1.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP1_ROUTER,
-                        DEFAULT_LOCAL_PREF,
-                        DEFAULT_MULTI_EXIT_DISC,
-                        asPathLong,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer1.peerChannelHandler.savedCtx.getChannel().write(message);
-        //
-        // Check that the routes have been received, processed and stored
-        //
-        bgpRibIn1 = waitForBgpRibIn(bgpSession1, 3);
-        assertThat(bgpRibIn1, hasSize(3));
-        bgpRoutes = waitForBgpRoutes(3);
-        assertThat(bgpRoutes, hasSize(3));
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("20.0.0.0/8"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("30.0.0.0/16"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("40.0.0.0/24"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              DEFAULT_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-
-
-        // Close the channels and test there are no routes
-        peer1.peerChannelHandler.closeChannel();
-        peer2.peerChannelHandler.closeChannel();
-        peer3.peerChannelHandler.closeChannel();
-        bgpRoutes = waitForBgpRoutes(0);
-        assertThat(bgpRoutes, hasSize(0));
-    }
-
-    /**
-     * Tests the BGP route preference.
-     */
-    @Test
-    public void testBgpRoutePreference() throws InterruptedException {
-        ChannelBuffer message;
-        BgpRouteEntry bgpRouteEntry;
-        Collection<BgpRouteEntry> bgpRibIn1;
-        Collection<BgpRouteEntry> bgpRibIn2;
-        Collection<BgpRouteEntry> bgpRibIn3;
-        Collection<BgpRouteEntry> bgpRoutes;
-        Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
-        Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
-
-        // Initiate the connections
-        peer1.connect(connectToSocket);
-        peer2.connect(connectToSocket);
-        peer3.connect(connectToSocket);
-
-        //
-        // Setup the initial set of routes to Peer1
-        //
-        addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
-        addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
-        // Write the routes
-        message = peer1.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP1_ROUTER,
-                        DEFAULT_LOCAL_PREF,
-                        DEFAULT_MULTI_EXIT_DISC,
-                        asPathLong,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer1.peerChannelHandler.savedCtx.getChannel().write(message);
-        bgpRoutes = waitForBgpRoutes(2);
-        assertThat(bgpRoutes, hasSize(2));
-
-        //
-        // Add a route entry to Peer2 with a better LOCAL_PREF
-        //
-        addedRoutes = new LinkedList<>();
-        withdrawnRoutes = new LinkedList<>();
-        addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
-        // Write the routes
-        message = peer2.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP2_ROUTER,
-                        BETTER_LOCAL_PREF,
-                        DEFAULT_MULTI_EXIT_DISC,
-                        asPathLong,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer2.peerChannelHandler.savedCtx.getChannel().write(message);
-        //
-        // Check that the routes have been received, processed and stored
-        //
-        bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
-        assertThat(bgpRibIn2, hasSize(1));
-        bgpRoutes = waitForBgpRoutes(2);
-        assertThat(bgpRoutes, hasSize(2));
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession2,
-                              Ip4Prefix.valueOf("20.0.0.0/8"),
-                              NEXT_HOP2_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathLong,
-                              BETTER_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-
-        //
-        // Add a route entry to Peer3 with a shorter AS path
-        //
-        addedRoutes = new LinkedList<>();
-        withdrawnRoutes = new LinkedList<>();
-        addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
-        // Write the routes
-        message = peer3.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP3_ROUTER,
-                        BETTER_LOCAL_PREF,
-                        DEFAULT_MULTI_EXIT_DISC,
-                        asPathShort,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer3.peerChannelHandler.savedCtx.getChannel().write(message);
-        //
-        // Check that the routes have been received, processed and stored
-        //
-        bgpRibIn3 = waitForBgpRibIn(bgpSession3, 1);
-        assertThat(bgpRibIn3, hasSize(1));
-        bgpRoutes = waitForBgpRoutes(2);
-        assertThat(bgpRoutes, hasSize(2));
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession3,
-                              Ip4Prefix.valueOf("20.0.0.0/8"),
-                              NEXT_HOP3_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathShort,
-                              BETTER_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn3, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-
-        //
-        // Cleanup in preparation for next test: delete old route entry from
-        // Peer2
-        //
-        addedRoutes = new LinkedList<>();
-        withdrawnRoutes = new LinkedList<>();
-        withdrawnRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
-        // Write the routes
-        message = peer2.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP2_ROUTER,
-                        BETTER_LOCAL_PREF,
-                        BETTER_MULTI_EXIT_DISC,
-                        asPathShort,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer2.peerChannelHandler.savedCtx.getChannel().write(message);
-        //
-        // Check that the routes have been received, processed and stored
-        //
-        bgpRibIn2 = waitForBgpRibIn(bgpSession2, 0);
-        assertThat(bgpRibIn2, hasSize(0));
-
-        //
-        // Add a route entry to Peer2 with a better MED
-        //
-        addedRoutes = new LinkedList<>();
-        withdrawnRoutes = new LinkedList<>();
-        addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
-        // Write the routes
-        message = peer2.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP2_ROUTER,
-                        BETTER_LOCAL_PREF,
-                        BETTER_MULTI_EXIT_DISC,
-                        asPathShort,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer2.peerChannelHandler.savedCtx.getChannel().write(message);
-        //
-        // Check that the routes have been received, processed and stored
-        //
-        bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
-        assertThat(bgpRibIn2, hasSize(1));
-        bgpRoutes = waitForBgpRoutes(2);
-        assertThat(bgpRoutes, hasSize(2));
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession2,
-                              Ip4Prefix.valueOf("20.0.0.0/8"),
-                              NEXT_HOP2_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathShort,
-                              BETTER_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-
-        //
-        // Add a route entry to Peer1 with a better (lower) BGP ID
-        //
-        addedRoutes = new LinkedList<>();
-        withdrawnRoutes = new LinkedList<>();
-        addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
-        withdrawnRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
-        // Write the routes
-        message = peer1.peerChannelHandler.prepareBgpUpdate(
-                        NEXT_HOP1_ROUTER,
-                        BETTER_LOCAL_PREF,
-                        BETTER_MULTI_EXIT_DISC,
-                        asPathShort,
-                        addedRoutes,
-                        withdrawnRoutes);
-        peer1.peerChannelHandler.savedCtx.getChannel().write(message);
-        //
-        // Check that the routes have been received, processed and stored
-        //
-        bgpRibIn1 = waitForBgpRibIn(bgpSession1, 1);
-        assertThat(bgpRibIn1, hasSize(1));
-        bgpRoutes = waitForBgpRoutes(1);
-        assertThat(bgpRoutes, hasSize(1));
-        //
-        bgpRouteEntry =
-            new BgpRouteEntry(bgpSession1,
-                              Ip4Prefix.valueOf("20.0.0.0/8"),
-                              NEXT_HOP1_ROUTER,
-                              (byte) BgpConstants.Update.Origin.IGP,
-                              asPathShort,
-                              BETTER_LOCAL_PREF);
-        bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
-        assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
-        assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
-
-
-        // Close the channels and test there are no routes
-        peer1.peerChannelHandler.closeChannel();
-        peer2.peerChannelHandler.closeChannel();
-        peer3.peerChannelHandler.closeChannel();
-        bgpRoutes = waitForBgpRoutes(0);
-        assertThat(bgpRoutes, hasSize(0));
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/PathSegmentTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/PathSegmentTest.java
deleted file mode 100644
index e8f2ddc..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/PathSegmentTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-
-import java.util.ArrayList;
-
-import org.junit.Test;
-
-/**
- * Unit tests for the BgpRouteEntry.PathSegment class.
- */
-public class PathSegmentTest {
-    /**
-     * Generates a Path Segment.
-     *
-     * @return a generated PathSegment
-     */
-    private BgpRouteEntry.PathSegment generatePathSegment() {
-        byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 1);
-        segmentAsNumbers.add((long) 2);
-        segmentAsNumbers.add((long) 3);
-        BgpRouteEntry.PathSegment pathSegment =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-
-        return pathSegment;
-    }
-
-    /**
-     * Tests valid class constructor.
-     */
-    @Test
-    public void testConstructor() {
-        BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
-
-        String expectedString =
-            "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}";
-        assertThat(pathSegment.toString(), is(expectedString));
-    }
-
-    /**
-     * Tests invalid class constructor for null Segment AS Numbers.
-     */
-    @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullSegmentAsNumbers() {
-        byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers = null;
-        new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-    }
-
-    /**
-     * Tests getting the fields of a Path Segment.
-     */
-    @Test
-    public void testGetFields() {
-        // Create the fields to compare against
-        byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 1);
-        segmentAsNumbers.add((long) 2);
-        segmentAsNumbers.add((long) 3);
-
-        // Generate the entry to test
-        BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
-
-        assertThat(pathSegment.getType(), is(pathSegmentType));
-        assertThat(pathSegment.getSegmentAsNumbers(), is(segmentAsNumbers));
-    }
-
-    /**
-     * Tests equality of {@link BgpRouteEntry.PathSegment}.
-     */
-    @Test
-    public void testEquality() {
-        BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment();
-        BgpRouteEntry.PathSegment pathSegment2 = generatePathSegment();
-
-        assertThat(pathSegment1, is(pathSegment2));
-    }
-
-    /**
-     * Tests non-equality of {@link BgpRouteEntry.PathSegment}.
-     */
-    @Test
-    public void testNonEquality() {
-        BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment();
-
-        // Setup Path Segment 2
-        byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
-        ArrayList<Long> segmentAsNumbers = new ArrayList<>();
-        segmentAsNumbers.add((long) 1);
-        segmentAsNumbers.add((long) 22);                        // Different
-        segmentAsNumbers.add((long) 3);
-        //
-        BgpRouteEntry.PathSegment pathSegment2 =
-            new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
-
-        assertThat(pathSegment1, is(not(pathSegment2)));
-    }
-
-    /**
-     * Tests object string representation.
-     */
-    @Test
-    public void testToString() {
-        BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
-
-        String expectedString =
-            "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}";
-        assertThat(pathSegment.toString(), is(expectedString));
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerChannelHandler.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerChannelHandler.java
deleted file mode 100644
index 979a1ed..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerChannelHandler.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import java.util.Collection;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.SimpleChannelHandler;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-
-/**
- * Class for handling the remote BGP Peer session.
- */
-class TestBgpPeerChannelHandler extends SimpleChannelHandler {
-    static final long PEER_AS = 65001;
-    static final long PEER_AS4 = 0x12345678;
-    static final int PEER_HOLDTIME = 120;       // 120 seconds
-
-    final BgpSessionInfo localInfo = new BgpSessionInfo();
-    ChannelHandlerContext savedCtx;
-
-    /**
-     * Constructor for given BGP ID.
-     *
-     * @param bgpId the BGP ID to use
-     */
-    TestBgpPeerChannelHandler(Ip4Address bgpId) {
-        this.localInfo.setBgpVersion(BgpConstants.BGP_VERSION);
-        this.localInfo.setBgpId(bgpId);
-        this.localInfo.setAsNumber(PEER_AS);
-        this.localInfo.setHoldtime(PEER_HOLDTIME);
-    }
-
-    /**
-     * Closes the channel.
-     */
-    void closeChannel() {
-        savedCtx.getChannel().close();
-    }
-
-    @Override
-    public void channelConnected(ChannelHandlerContext ctx,
-                                 ChannelStateEvent channelEvent) {
-        this.savedCtx = ctx;
-        // Prepare and transmit BGP OPEN message
-        ChannelBuffer message = BgpOpen.prepareBgpOpen(localInfo);
-        ctx.getChannel().write(message);
-
-        // Prepare and transmit BGP KEEPALIVE message
-        message = BgpKeepalive.prepareBgpKeepalive();
-        ctx.getChannel().write(message);
-    }
-
-    @Override
-    public void channelDisconnected(ChannelHandlerContext ctx,
-                                    ChannelStateEvent channelEvent) {
-        // Nothing to do
-    }
-
-    /**
-     * Prepares BGP UPDATE message.
-     *
-     * @param nextHopRouter the next-hop router address for the routes to add
-     * @param localPref the local preference for the routes to use
-     * @param multiExitDisc the MED value
-     * @param asPath the AS path for the routes to add
-     * @param addedRoutes the routes to add
-     * @param withdrawnRoutes the routes to withdraw
-     * @return the message to transmit (BGP header included)
-     */
-    ChannelBuffer prepareBgpUpdate(Ip4Address nextHopRouter,
-                                   long localPref,
-                                   long multiExitDisc,
-                                   BgpRouteEntry.AsPath asPath,
-                                   Collection<Ip4Prefix> addedRoutes,
-                                   Collection<Ip4Prefix> withdrawnRoutes) {
-        int attrFlags;
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-        ChannelBuffer pathAttributes =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
-        // Encode the Withdrawn Routes
-        ChannelBuffer encodedPrefixes = encodePackedPrefixes(withdrawnRoutes);
-        message.writeShort(encodedPrefixes.readableBytes());
-        message.writeBytes(encodedPrefixes);
-
-        // Encode the Path Attributes
-        // ORIGIN: IGP
-        attrFlags = 0x40;                               // Transitive flag
-        pathAttributes.writeByte(attrFlags);
-        pathAttributes.writeByte(BgpConstants.Update.Origin.TYPE);
-        pathAttributes.writeByte(1);                    // Data length
-        pathAttributes.writeByte(BgpConstants.Update.Origin.IGP);
-
-        // AS_PATH: asPath
-        attrFlags = 0x40;                               // Transitive flag
-        pathAttributes.writeByte(attrFlags);
-        pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE);
-        ChannelBuffer encodedAsPath = encodeAsPath(asPath);
-        pathAttributes.writeByte(encodedAsPath.readableBytes()); // Data length
-        pathAttributes.writeBytes(encodedAsPath);
-        // NEXT_HOP: nextHopRouter
-        attrFlags = 0x40;                               // Transitive flag
-        pathAttributes.writeByte(attrFlags);
-        pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE);
-        pathAttributes.writeByte(4);                    // Data length
-        pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router
-        // LOCAL_PREF: localPref
-        attrFlags = 0x40;                               // Transitive flag
-        pathAttributes.writeByte(attrFlags);
-        pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE);
-        pathAttributes.writeByte(4);                    // Data length
-        pathAttributes.writeInt((int) localPref);       // Preference value
-        // MULTI_EXIT_DISC: multiExitDisc
-        attrFlags = 0x80;                               // Optional
-                                                        // Non-Transitive flag
-        pathAttributes.writeByte(attrFlags);
-        pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE);
-        pathAttributes.writeByte(4);                    // Data length
-        pathAttributes.writeInt((int) multiExitDisc);   // Preference value
-        // The NLRI prefixes
-        encodedPrefixes = encodePackedPrefixes(addedRoutes);
-
-        // Write the Path Attributes, beginning with its length
-        message.writeShort(pathAttributes.readableBytes());
-        message.writeBytes(pathAttributes);
-        message.writeBytes(encodedPrefixes);
-
-        return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE,
-                                            message);
-    }
-
-    /**
-     * Encodes a collection of IPv4 network prefixes in a packed format.
-     * <p>
-     * The IPv4 prefixes are encoded in the form:
-     * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
-     * and Prefix is the IPv4 prefix (padded with trailing bits to the end
-     * of an octet).
-     *
-     * @param prefixes the prefixes to encode
-     * @return the buffer with the encoded prefixes
-     */
-    private ChannelBuffer encodePackedPrefixes(Collection<Ip4Prefix> prefixes) {
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
-        // Write each of the prefixes
-        for (Ip4Prefix prefix : prefixes) {
-            int prefixBitlen = prefix.prefixLength();
-            int prefixBytelen = (prefixBitlen + 7) / 8;         // Round-up
-            message.writeByte(prefixBitlen);
-
-            Ip4Address address = prefix.address();
-            long value = address.toInt() & 0xffffffffL;
-            for (int i = 0; i < Ip4Address.BYTE_LENGTH; i++) {
-                if (prefixBytelen-- == 0) {
-                    break;
-                }
-                long nextByte =
-                    (value >> ((Ip4Address.BYTE_LENGTH - i - 1) * 8)) & 0xff;
-                message.writeByte((int) nextByte);
-            }
-        }
-
-        return message;
-    }
-
-    /**
-     * Encodes an AS path.
-     *
-     * @param asPath the AS path to encode
-     * @return the buffer with the encoded AS path
-     */
-    private ChannelBuffer encodeAsPath(BgpRouteEntry.AsPath asPath) {
-        ChannelBuffer message =
-            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
-        for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) {
-            message.writeByte(pathSegment.getType());
-            message.writeByte(pathSegment.getSegmentAsNumbers().size());
-            for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
-                message.writeShort(asNumber.intValue());
-            }
-        }
-
-        return message;
-    }
-}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerFrameDecoder.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerFrameDecoder.java
deleted file mode 100644
index 4f39547..0000000
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerFrameDecoder.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.sdnip.bgp;
-
-import java.util.concurrent.CountDownLatch;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.frame.FrameDecoder;
-import org.onlab.packet.Ip4Address;
-
-/**
- * Class for handling the decoding of the BGP messages at the remote
- * BGP peer session.
- */
-class TestBgpPeerFrameDecoder extends FrameDecoder {
-    final BgpSessionInfo remoteInfo = new BgpSessionInfo();
-
-    final CountDownLatch receivedOpenMessageLatch = new CountDownLatch(1);
-    final CountDownLatch receivedKeepaliveMessageLatch = new CountDownLatch(1);
-
-    @Override
-    protected Object decode(ChannelHandlerContext ctx,
-                            Channel channel,
-                            ChannelBuffer buf) throws Exception {
-        // Test for minimum length of the BGP message
-        if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) {
-            // No enough data received
-            return null;
-        }
-
-        //
-        // Mark the current buffer position in case we haven't received
-        // the whole message.
-        //
-        buf.markReaderIndex();
-
-        //
-        // Read and check the BGP message Marker field: it must be all ones
-        //
-        byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH];
-        buf.readBytes(marker);
-        for (int i = 0; i < marker.length; i++) {
-            if (marker[i] != (byte) 0xff) {
-                // ERROR: Connection Not Synchronized. Close the channel.
-                ctx.getChannel().close();
-                return null;
-            }
-        }
-
-        //
-        // Read and check the BGP message Length field
-        //
-        int length = buf.readUnsignedShort();
-        if ((length < BgpConstants.BGP_HEADER_LENGTH) ||
-            (length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) {
-            // ERROR: Bad Message Length. Close the channel.
-            ctx.getChannel().close();
-            return null;
-        }
-
-        //
-        // Test whether the rest of the message is received:
-        // So far we have read the Marker (16 octets) and the
-        // Length (2 octets) fields.
-        //
-        int remainingMessageLen =
-            length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2;
-        if (buf.readableBytes() < remainingMessageLen) {
-            // No enough data received
-            buf.resetReaderIndex();
-            return null;
-        }
-
-        //
-        // Read the BGP message Type field, and process based on that type
-        //
-        int type = buf.readUnsignedByte();
-        remainingMessageLen--;      // Adjust after reading the type
-        ChannelBuffer message = buf.readBytes(remainingMessageLen);
-
-        //
-        // Process the remaining of the message based on the message type
-        //
-        switch (type) {
-        case BgpConstants.BGP_TYPE_OPEN:
-            processBgpOpen(ctx, message);
-            break;
-        case BgpConstants.BGP_TYPE_UPDATE:
-            // NOTE: Not used as part of the test, because ONOS does not
-            // originate UPDATE messages.
-            break;
-        case BgpConstants.BGP_TYPE_NOTIFICATION:
-            // NOTE: Not used as part of the testing (yet)
-            break;
-        case BgpConstants.BGP_TYPE_KEEPALIVE:
-            processBgpKeepalive(ctx, message);
-            break;
-        default:
-            // ERROR: Bad Message Type. Close the channel.
-            ctx.getChannel().close();
-            return null;
-        }
-
-        return null;
-    }
-
-    /**
-     * Processes BGP OPEN message.
-     *
-     * @param ctx the Channel Handler Context.
-     * @param message the message to process.
-     */
-    private void processBgpOpen(ChannelHandlerContext ctx,
-                                ChannelBuffer message) {
-        int minLength =
-            BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
-        if (message.readableBytes() < minLength) {
-            // ERROR: Bad Message Length. Close the channel.
-            ctx.getChannel().close();
-            return;
-        }
-
-        //
-        // Parse the OPEN message
-        //
-        remoteInfo.setBgpVersion(message.readUnsignedByte());
-        remoteInfo.setAsNumber(message.readUnsignedShort());
-        remoteInfo.setHoldtime(message.readUnsignedShort());
-        remoteInfo.setBgpId(Ip4Address.valueOf((int) message.readUnsignedInt()));
-        // Optional Parameters
-        int optParamLen = message.readUnsignedByte();
-        if (message.readableBytes() < optParamLen) {
-            // ERROR: Bad Message Length. Close the channel.
-            ctx.getChannel().close();
-            return;
-        }
-        message.readBytes(optParamLen);             // NOTE: data ignored
-
-        // BGP OPEN message successfully received
-        receivedOpenMessageLatch.countDown();
-    }
-
-    /**
-     * Processes BGP KEEPALIVE message.
-     *
-     * @param ctx the Channel Handler Context.
-     * @param message the message to process.
-     */
-    private void processBgpKeepalive(ChannelHandlerContext ctx,
-                                     ChannelBuffer message) {
-        if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
-            BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
-            // ERROR: Bad Message Length. Close the channel.
-            ctx.getChannel().close();
-            return;
-        }
-        // BGP KEEPALIVE message successfully received
-        receivedKeepaliveMessageLatch.countDown();
-    }
-}