[GEANT] Add/remove peer details. Config using port to peer.

Change-Id: I9b9933de67cefd84f5474ad759c94a610b2ef141
diff --git a/pom.xml b/pom.xml
index db081c0..531ef73 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,7 @@
         <module>ifwd</module>
         <module>ipfix</module>
         <module>oneping</module>
+        <module>sdx-l3</module>
         <module>tvue</module>
         <module>uiref</module>
         <module>ecord/co</module>
diff --git a/sdx-l3/pom.xml b/sdx-l3/pom.xml
index 7a51fef..2d33fd2 100644
--- a/sdx-l3/pom.xml
+++ b/sdx-l3/pom.xml
@@ -22,7 +22,7 @@
 
     <parent>
         <groupId>org.onosproject</groupId>
-        <artifactId>onos-apps</artifactId>
+        <artifactId>onos-app-samples</artifactId>
         <version>1.5.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3.java
index f01cd80..8211b68 100644
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3.java
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3.java
@@ -85,7 +85,7 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostService hostService;
 
-    protected ArpHandler arpHandler = null;
+    protected SdxL3ArpHandler arpHandler = null;
 
     private InternalPacketProcessor processor = null;
 
@@ -95,7 +95,7 @@
     static {
         components.add("org.onosproject.routing.bgp.BgpSessionManager");
         components.add("org.onosproject.routing.impl.Router");
-        components.add(org.onosproject.sdxl3.impl.PeerConnectivityManager.class.getName());
+        components.add(org.onosproject.sdxl3.impl.SdxL3PeerManager.class.getName());
         components.add(org.onosproject.sdxl3.SdxL3Fib.class.getName());
     }
 
@@ -109,7 +109,7 @@
         BgpConfig bgpConfig =
                 networkConfigService.getConfig(routerAppId, RoutingService.CONFIG_CLASS);
 
-        arpHandler = new ArpHandler(bgpConfig,
+        arpHandler = new SdxL3ArpHandler(bgpConfig,
                 edgeService,
                 hostService,
                 packetService,
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3ArpHandler.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3ArpHandler.java
index 795d301..a1643c3 100644
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3ArpHandler.java
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3ArpHandler.java
@@ -154,7 +154,7 @@
 
         // If the source address matches one of our external addresses
         // it could be a request from an internal host to an external
-        // address. Forward it over to the correct port.
+        // address. Forward it over to the correct connectPoint.
         boolean matched = false;
         Set<Interface> interfaces = interfaceService.getInterfacesByIp(context.sender());
         for (Interface intf : interfaces) {
@@ -185,7 +185,7 @@
         }
 
         // The request couldn't be resolved.
-        // Flood the request on all ports except the incoming port.
+        // Flood the request on all ports except the incoming connectPoint.
         flood(context.packet(), context.inPort());
     }
 
@@ -242,25 +242,25 @@
     }
 
     /**
-     * Outputs a packet out a specific port.
+     * Outputs a packet out a specific connectPoint.
      *
      * @param packet  the packet to send
-     * @param outPort the port to send it out
+     * @param outPort the connectPoint to send it out
      */
     private void sendTo(Ethernet packet, ConnectPoint outPort) {
         sendTo(outPort, ByteBuffer.wrap(packet.serialize()));
     }
 
     /**
-     * Outputs a packet out a specific port.
+     * Outputs a packet out a specific connectPoint.
      *
-     * @param outPort port to send it out
+     * @param outPort connectPoint to send it out
      * @param packet packet to send
      */
     private void sendTo(ConnectPoint outPort, ByteBuffer packet) {
         if (!edgeService.isEdgePoint(outPort)) {
             // Sanity check to make sure we don't send the packet out an
-            // internal port and create a loop (could happen due to
+            // internal connectPoint and create a loop (could happen due to
             // misconfiguration).
             return;
         }
@@ -272,10 +272,10 @@
     }
 
     /**
-     * Returns whether the given port has any IP addresses configured or not.
+     * Returns whether the given connectPoint has any IP addresses configured or not.
      *
-     * @param connectPoint the port to check
-     * @return true if the port has at least one IP address configured,
+     * @param connectPoint the connectPoint to check
+     * @return true if the connectPoint has at least one IP address configured,
      * false otherwise
      */
     private boolean hasIpAddress(ConnectPoint connectPoint) {
@@ -287,10 +287,10 @@
     }
 
     /**
-     * Returns whether the given port has any VLAN configured or not.
+     * Returns whether the given connectPoint has any VLAN configured or not.
      *
-     * @param connectPoint the port to check
-     * @return true if the port has at least one VLAN configured,
+     * @param connectPoint the connectPoint to check
+     * @return true if the connectPoint has at least one VLAN configured,
      * false otherwise
      */
     private boolean hasVlan(ConnectPoint connectPoint) {
@@ -394,7 +394,7 @@
      * created.
      *
      * @param eth input Ethernet frame
-     * @param inPort in port
+     * @param inPort in connectPoint
      * @return MessageContext if the packet was ARP or NDP, otherwise null
      */
     private MessageContext createContext(Ethernet eth, ConnectPoint inPort) {
@@ -411,7 +411,7 @@
      * Extracts context information from ARP packets.
      *
      * @param eth input Ethernet frame that is thought to be ARP
-     * @param inPort in port
+     * @param inPort in connectPoint
      * @return MessageContext object if the packet was a valid ARP packet,
      * otherwise null
      */
@@ -441,7 +441,7 @@
      * Extracts context information from NDP packets.
      *
      * @param eth input Ethernet frame that is thought to be NDP
-     * @param inPort in port
+     * @param inPort in connectPoint
      * @return MessageContext object if the packet was a valid NDP packet,
      * otherwise null
      */
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java
index 68829e1..9cd228d 100644
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java
@@ -75,7 +75,7 @@
     protected RoutingService routingService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected PeerConnectivityService peerConnectivity;
+    protected SdxL3PeerService peerService;
 
     private final InternalFibListener fibListener = new InternalFibListener();
 
@@ -177,7 +177,7 @@
             MacAddress nextHopMacAddress) {
 
         // Find the attachment point (egress interface) of the next hop
-        Interface egressInterface = peerConnectivity.getInterfaceForPeer(nextHopIpAddress);
+        Interface egressInterface = peerService.getInterfaceForPeer(nextHopIpAddress);
 
         if (egressInterface == null) {
             log.warn("No outgoing interface found for {}",
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3PeerService.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3PeerService.java
index 6a2542c..c0a7a77 100644
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3PeerService.java
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3PeerService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-2016 Open Networking Laboratory
+ * Copyright 2016 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.
@@ -18,19 +18,52 @@
 
 import org.onlab.packet.IpAddress;
 import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.routing.config.BgpConfig;
+import org.onosproject.sdxl3.config.SdxProvidersConfig;
+
+import java.util.List;
 
 /*
  * Service for managing peers connections
  */
 public interface SdxL3PeerService {
 
-    String CONFIG_KEY = "bgpPeers";
+    Class<SdxProvidersConfig> CONFIG_CLASS = SdxProvidersConfig.class;
+    String CONFIG_KEY = "providers";
+
+    /**
+     * Returns the list of IP addresses of BGP peers.
+     *
+     * @param bgpConfig BGP configuration
+     * @return list of IP addresses of peers
+     */
+    List<IpAddress> getPeerAddresses(BgpConfig bgpConfig);
 
     /**
      * Returns the interface used as connection point to peer.
      *
-     * @param peeringAddress IP address of peer
+     * @param peerAddress IP address of peer
      * @return interface to the peer
      */
-    Interface getInterfaceForPeer(IpAddress peeringAddress);
+    Interface getInterfaceForPeer(IpAddress peerAddress);
+
+    /**
+     * Adds details for a BGP peer to the configuration.
+     *
+     * @param peerName Peer name
+     * @param peerAddress Peer IP address
+     * @param port Connection point with peer
+     * @param interfaceName Name of the interface configured on port
+     */
+    void addPeerDetails(String peerName, IpAddress peerAddress,
+                        ConnectPoint port, String  interfaceName);
+
+    /**
+     * Removes details for a BGP peer to the configuration.
+     *
+     * @param peerAddress Peer IP address
+     */
+    void removePeerDetails(IpAddress peerAddress);
+
 }
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/AddPeerDetailsCommand.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/AddPeerDetailsCommand.java
new file mode 100644
index 0000000..acc4579
--- /dev/null
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/AddPeerDetailsCommand.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 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.sdxl3.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.sdxl3.SdxL3PeerService;
+
+/**
+ * Command to set details for an existing BGP peer.
+ */
+@Command(scope = "onos", name = "peer-add-details",
+        description = "Adds the details of an external BGP peer")
+public class AddPeerDetailsCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "ip", description = "BGP peer IP",
+            required = true, multiValued = false)
+    private String ip = null;
+
+    @Argument(index = 1, name = "port",
+            description = "Connect point of the BGP peer",
+            required = true, multiValued = false)
+    private String connectPoint = null;
+
+    @Argument(index = 2, name = "intfName",
+            description = "Name of configured interface for the BGP peer",
+            required = true, multiValued = false)
+    private String interfaceName = null;
+
+    @Option(name = "-n", aliases = "--name", description = "BGP peer name",
+            required = false, multiValued = false)
+    private String peerName = null;
+
+    private static final String DETAILS_ADD_SUCCESS =
+            "Details successfully added to peer.";
+    private static final String DETAILS_ADD_FAIL =
+            "Details could not be added to peer: ";
+
+    private IpAddress peerAddress = null;
+    private ConnectPoint port = null;
+
+    @Override
+    protected void execute() {
+        peerAddress = IpAddress.valueOf(ip);
+        port = ConnectPoint.deviceConnectPoint(connectPoint);
+
+        SdxL3PeerService peerService = get(SdxL3PeerService.class);
+        try {
+            peerService.addPeerDetails(peerName, peerAddress, port, interfaceName);
+            print(DETAILS_ADD_SUCCESS);
+        } catch (Exception e) {
+            print(DETAILS_ADD_FAIL + e.getMessage());
+        }
+    }
+}
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/BgpPeersListCommand.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/BgpPeersListCommand.java
index 09f237b..2e22bed 100644
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/BgpPeersListCommand.java
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/BgpPeersListCommand.java
@@ -26,7 +26,8 @@
 import org.onosproject.routing.RoutingService;
 import org.onosproject.routing.config.BgpConfig;
 import org.onosproject.sdxl3.SdxL3;
-import org.onosproject.sdxl3.config.BgpPeersConfig;
+import org.onosproject.sdxl3.SdxL3PeerService;
+import org.onosproject.sdxl3.config.SdxProvidersConfig;
 
 import java.util.Comparator;
 import java.util.List;
@@ -39,12 +40,13 @@
         description = "Lists all BGP peers")
 public class BgpPeersListCommand extends AbstractShellCommand {
 
-    private static final String FORMAT = "ip=%s, interface=%s";
-    private static final String NAME_FORMAT = "%s: " + FORMAT;
-    private static final String AUTO_SELECTION = "auto";
+    private static final String BASIC_FORMAT =  "ip=%s";
+    private static final String DETAILS_FORMAT =
+            BASIC_FORMAT + ", port=%s/%s, intfName=%s";
+    private static final String NAME_FORMAT = "%s: " + DETAILS_FORMAT;
     public static final String NO_PEERS = "No peers configured";
 
-    private static final Comparator<BgpPeersConfig.PeerConfig> PEER_COMPARATOR =
+    private static final Comparator<SdxProvidersConfig.PeerConfig> PEER_COMPARATOR =
             Comparator.comparing(p -> p.ip());
     public static final String EMPTY = "";
 
@@ -52,13 +54,14 @@
     protected void execute() {
         NetworkConfigService configService = get(NetworkConfigService.class);
         CoreService coreService = get(CoreService.class);
+        SdxL3PeerService peerService = get(SdxL3PeerService.class);
 
         ApplicationId routerAppId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
         BgpConfig bgpConfig = configService.getConfig(routerAppId, RoutingService.CONFIG_CLASS);
 
         ApplicationId sdxL3AppId = coreService.getAppId(SdxL3.SDX_L3_APP);
-        BgpPeersConfig peersConfig = configService.
-                getConfig(sdxL3AppId, BgpPeersConfig.class);
+        SdxProvidersConfig peersConfig = configService.
+                getConfig(sdxL3AppId, SdxProvidersConfig.class);
 
         if (bgpConfig == null && peersConfig == null) {
             print(NO_PEERS);
@@ -67,12 +70,14 @@
 
         List<IpAddress> peeringAddresses = Lists.newArrayList();
         if (bgpConfig != null) {
-            peeringAddresses = getPeeringAddresses(bgpConfig);
+            // Get all peering addresses from BGP configuration
+            peeringAddresses = peerService.getPeerAddresses(bgpConfig);
         }
 
-        List<BgpPeersConfig.PeerConfig> bgpPeers =
+        List<SdxProvidersConfig.PeerConfig> bgpPeers =
                 Lists.newArrayList();
         if (peersConfig != null) {
+            // Get all peers having details specified
             bgpPeers.addAll(peersConfig.bgpPeers());
         }
 
@@ -86,43 +91,30 @@
         bgpPeers.sort(PEER_COMPARATOR);
         bgpPeers.forEach(p -> {
             if (p.name().isPresent()) {
-                if (p.interfaceName() != EMPTY) {
-                    print(NAME_FORMAT, p.name().get(), p.ip(), p.interfaceName());
-                } else {
-                    print(NAME_FORMAT, p.name().get(), p.ip(), AUTO_SELECTION);
-                }
-            } else if (p.interfaceName() != EMPTY) {
-                print(FORMAT, p.ip(), p.interfaceName());
+                print(NAME_FORMAT, p.name().get(), p.ip(),
+                      p.connectPoint().deviceId(), p.connectPoint().port(),
+                      p.interfaceName());
+            } else if (p.connectPoint() != null) {
+                print(DETAILS_FORMAT, p.ip(), p.connectPoint().deviceId(),
+                      p.connectPoint().port(), p.interfaceName());
             } else {
-                print(FORMAT, p.ip(), AUTO_SELECTION);
+                print(BASIC_FORMAT, p.ip());
             }
         });
     }
 
-    private List<IpAddress> getPeeringAddresses(BgpConfig bgpConfig) {
-        List<IpAddress> peeringAddresses = Lists.newArrayList();
-
-        List<BgpConfig.BgpSpeakerConfig> bgpSpeakers =
-                Lists.newArrayList(bgpConfig.bgpSpeakers());
-        bgpSpeakers.forEach(
-                s -> peeringAddresses.addAll(s.peers()));
-
-        return peeringAddresses;
-    }
-
-    private List<BgpPeersConfig.PeerConfig> mergePeers(
-            List<IpAddress> peeringAddresses,
-            List<BgpPeersConfig.PeerConfig> bgpPeers) {
+    private List<SdxProvidersConfig.PeerConfig> mergePeers(
+                List<IpAddress> peeringAddresses,
+                List<SdxProvidersConfig.PeerConfig> bgpPeers) {
         peeringAddresses.forEach(a -> {
             boolean exists = bgpPeers.stream()
                     .filter(p -> p.ip().equals(a))
                     .findAny().isPresent();
             if (!exists) {
-                bgpPeers.add(new BgpPeersConfig
-                        .PeerConfig(Optional.<String>empty(), a, EMPTY));
+                bgpPeers.add(new SdxProvidersConfig
+                        .PeerConfig(Optional.<String>empty(), a, null, EMPTY));
             }
         });
-
         return bgpPeers;
     }
 }
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/RemovePeerDetailsCommand.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/RemovePeerDetailsCommand.java
new file mode 100644
index 0000000..8eee2ba
--- /dev/null
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/cli/RemovePeerDetailsCommand.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 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.sdxl3.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.sdxl3.SdxL3PeerService;
+
+/**
+ * Command to remove details for a peer from configuration.
+ */
+@Command(scope = "onos", name = "peer-remove-details",
+        description = "Removes the details of an external BGP peer")
+public class RemovePeerDetailsCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "ip",
+            description = "BGP peer IP",
+            required = true, multiValued = false)
+    private String ip = null;
+
+    private static final String DETAILS_REMOVE_SUCCESS =
+            "Details successfully removed from peer.";
+    private static final String DETAILS_REMOVE_FAIL =
+            "Details could not be added to peer: ";
+
+    private IpAddress peerAddress = null;
+
+    @Override
+    protected void execute() {
+        peerAddress = IpAddress.valueOf(ip);
+
+        SdxL3PeerService peerService = get(SdxL3PeerService.class);
+        try {
+            peerService.removePeerDetails(peerAddress);
+            print(DETAILS_REMOVE_SUCCESS);
+        } catch (Exception e) {
+            print(DETAILS_REMOVE_FAIL + e.getMessage());
+        }
+    }
+}
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/config/BgpPeersConfig.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/config/BgpPeersConfig.java
deleted file mode 100644
index dd89aed..0000000
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/config/BgpPeersConfig.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2014-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.sdxl3.config;
-
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.Config;
-
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-public class BgpPeersConfig extends Config<ApplicationId> {
-    public static final String NAME = "name";
-    public static final String IP = "ip";
-    public static final String INTERFACE = "interface";
-
-    /**
-     * Gets the set of configured BGP peers.
-     *
-     * @return BGP peers
-     */
-    public Set<PeerConfig> bgpPeers() {
-        Set<PeerConfig> peers = Sets.newHashSet();
-
-        ArrayNode peersNode = array;
-        peersNode.forEach(jsonNode -> {
-            Optional<String> name;
-            if (jsonNode.get(NAME) == null) {
-                name = Optional.empty();
-            } else {
-                name = Optional.of(jsonNode.get(NAME).asText());
-            }
-
-            peers.add(new PeerConfig(name,
-                    IpAddress.valueOf(jsonNode.path(IP).asText()),
-                    jsonNode.path(INTERFACE).asText()));
-        });
-
-        return peers;
-    }
-
-    /**
-     * Gets the interface name configured for a given BGP peer.
-     *
-     * @param peerAddress IP address of the peer
-     * @return interface name
-     */
-
-    public String getInterfaceNameForPeer(IpAddress peerAddress) {
-        Optional<PeerConfig> match = bgpPeers()
-                .stream()
-                .filter(p -> p.ip().equals(peerAddress))
-                .findAny();
-
-        if (match.isPresent()) {
-            return match.get().interfaceName();
-        } else {
-            return null;
-        }
-    }
-
-
-    /**
-     * Configuration for a BGP peer.
-     */
-    public static class PeerConfig {
-
-        private Optional<String> name;
-        private IpAddress ip;
-        private String interfaceName;
-
-        public PeerConfig(Optional<String> name, IpAddress ip, String interfaceName) {
-            this.name = checkNotNull(name);
-            this.ip = checkNotNull(ip);
-            this.interfaceName = checkNotNull(interfaceName);
-        }
-
-        public Optional<String> name() {
-            return name;
-        }
-
-        public IpAddress ip() {
-            return ip;
-        }
-
-        public String interfaceName() {
-            return interfaceName;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj instanceof PeerConfig) {
-                final PeerConfig that = (PeerConfig) obj;
-                return Objects.equals(this.name, that.name) &&
-                        Objects.equals(this.ip, that.ip) &&
-                        Objects.equals(this.interfaceName, that.interfaceName);
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(name, ip, interfaceName);
-        }
-    }
-}
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/config/SdxProvidersConfig.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/config/SdxProvidersConfig.java
new file mode 100644
index 0000000..8206fda
--- /dev/null
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/config/SdxProvidersConfig.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2014-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.sdxl3.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Sets;
+import org.onlab.packet.IpAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.Config;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Configuration for the Service Providers being connected to the
+ * software defined internet exchange point.
+ */
+public class SdxProvidersConfig extends Config<ApplicationId> {
+
+    public static final String PEERS = "bgpPeers";
+    public static final String NAME = "name";
+    public static final String IP = "ip";
+    public static final String CONN_POINT = "connectPoint";
+    public static final String INTF_NAME = "intfName";
+
+    /**
+     * Gets the set of configured BGP peers.
+     *
+     * @return BGP peers
+     */
+    public Set<PeerConfig> bgpPeers() {
+        Set<PeerConfig> peers = Sets.newHashSet();
+
+        JsonNode peersNode = object.get(PEERS);
+
+        if (peersNode == null) {
+            return peers;
+        }
+        peersNode.forEach(jsonNode -> {
+            Optional<String> name;
+            if (jsonNode.get(NAME) == null) {
+                name = Optional.empty();
+            } else {
+                name = Optional.of(jsonNode.get(NAME).asText());
+            }
+
+            peers.add(new PeerConfig(name,
+                    IpAddress.valueOf(jsonNode.path(IP).asText()),
+                    ConnectPoint.deviceConnectPoint(jsonNode.path(CONN_POINT).asText()),
+                    jsonNode.path(INTF_NAME).asText()));
+        });
+
+        return peers;
+    }
+
+    /**
+     * Gets the connectPoint configured for a given BGP peer.
+     *
+     * @param peerAddress IP address of the peer
+     * @return connectPoint connection point
+     */
+
+    public ConnectPoint getPortForPeer(IpAddress peerAddress) {
+        Optional<PeerConfig> match = bgpPeers()
+                .stream()
+                .filter(p -> p.ip().equals(peerAddress))
+                .findAny();
+
+        if (match.isPresent()) {
+            return match.get().connectPoint();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the interface name configured for a given BGP peer.
+     *
+     * @param peerAddress IP address of the peer
+     * @return interface name
+     */
+
+    public String getInterfaceNameForPeer(IpAddress peerAddress) {
+        Optional<PeerConfig> match = bgpPeers()
+                .stream()
+                .filter(p -> p.ip().equals(peerAddress))
+                .findAny();
+
+        if (match.isPresent()) {
+            return match.get().interfaceName();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the BGP peer configured for a given peer name.
+     *
+     * @param peerName Name of the BGP peer
+     * @return Peer configuration or null
+     */
+
+    public PeerConfig getPeerForName(Optional<String> peerName) {
+        Optional<PeerConfig> match = bgpPeers()
+                .stream()
+                .filter(p -> p.name().equals(peerName))
+                .findAny();
+
+        if (match.isPresent()) {
+            return match.get();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Adds new BGP peer details to the configuration.
+     *
+     * @param peer BGP peer configuration entry
+     */
+
+    public void addPeer(PeerConfig peer) {
+        ObjectNode peerNode = JsonNodeFactory.instance.objectNode();
+
+        if (peer.name().isPresent()) {
+            peerNode.put(NAME, peer.name().get());
+        }
+        peerNode.put(IP, peer.ip().toString());
+        peerNode.put(CONN_POINT, peer.connectPoint().elementId().toString()
+                + "/" + peer.connectPoint().port().toString());
+        peerNode.put(INTF_NAME, peer.interfaceName());
+
+        ArrayNode peersArray = bgpPeers().isEmpty() ?
+                initPeersConfiguration() : (ArrayNode) object.get(PEERS);
+        peersArray.add(peerNode);
+    }
+
+    /**
+     * Gets the BGP peer configured for a given peer IP.
+     *
+     * @param ip Name of the BGP peer
+     * @return Peer configuration or null
+     */
+
+    public PeerConfig getPeerForIp(IpAddress ip) {
+        Optional<PeerConfig> match = bgpPeers()
+                .stream()
+                .filter(p -> p.ip().equals(ip))
+                .findAny();
+
+        if (match.isPresent()) {
+            return match.get();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Removes BGP peer details from configuration.
+     *
+     * @param peerIp BGP peer IP address
+     */
+    public void removePeer(IpAddress peerIp) {
+        ArrayNode peersArray = (ArrayNode) object.get(PEERS);
+
+        for (int i = 0; i < peersArray.size(); i++) {
+            if (peersArray.get(i).get(IP).asText().equals(peerIp.toString())) {
+                peersArray.remove(i);
+                return;
+            }
+        }
+    }
+
+    /**
+     * Creates empty configuration for BGP peers details.
+     *
+     * @return empty array of BGP peers
+     */
+    private ArrayNode initPeersConfiguration() {
+        return object.putArray(PEERS);
+    }
+
+    /**
+     * Configuration for a BGP peer.
+     */
+    public static class PeerConfig {
+
+        private Optional<String> name;
+        private IpAddress ip;
+        private ConnectPoint connectPoint;
+        private String interfaceName;
+
+        public PeerConfig(Optional<String> name,
+                          IpAddress ip,
+                          ConnectPoint connectPoint,
+                          String interfaceName) {
+            this.name = checkNotNull(name);
+            this.ip = checkNotNull(ip);
+            // It can be null only for printout entries
+            this.connectPoint = connectPoint;
+            this.interfaceName = checkNotNull(interfaceName);
+        }
+
+        public Optional<String> name() {
+            return name;
+        }
+
+        public IpAddress ip() {
+            return ip;
+        }
+
+        public ConnectPoint connectPoint() {
+            return connectPoint;
+        }
+
+        public String interfaceName() {
+            return interfaceName;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof PeerConfig) {
+                final PeerConfig that = (PeerConfig) obj;
+                return Objects.equals(this.name, that.name) &&
+                        Objects.equals(this.ip, that.ip) &&
+                        Objects.equals(this.connectPoint, that.connectPoint) &&
+                        Objects.equals(this.interfaceName, that.interfaceName);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(name, ip, connectPoint, interfaceName);
+        }
+    }
+}
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/impl/SdxL3PeerManager.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/impl/SdxL3PeerManager.java
index b881ca2..8f9d5e5 100644
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/impl/SdxL3PeerManager.java
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/impl/SdxL3PeerManager.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.sdxl3.impl;
 
+import com.google.common.collect.Lists;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -28,6 +29,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.TpPort;
+import org.onlab.util.ItemNotFoundException;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.incubator.net.intf.Interface;
@@ -50,9 +52,9 @@
 import org.onosproject.routing.IntentSynchronizationService;
 import org.onosproject.routing.RoutingService;
 import org.onosproject.routing.config.BgpConfig;
-import org.onosproject.sdxl3.PeerConnectivityService;
 import org.onosproject.sdxl3.SdxL3;
-import org.onosproject.sdxl3.config.BgpPeersConfig;
+import org.onosproject.sdxl3.SdxL3PeerService;
+import org.onosproject.sdxl3.config.SdxProvidersConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,6 +63,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -70,9 +73,6 @@
 @Service
 @Component(immediate = true, enabled = false)
 public class SdxL3PeerManager implements SdxL3PeerService {
-
-    private static final String CONFIG_KEY = "bgpPeers";
-
     private static final int PRIORITY_OFFSET = 1000;
 
     private static final String SUFFIX_DST = "dst";
@@ -80,7 +80,7 @@
     private static final String SUFFIX_ICMP = "icmp";
 
     private static final Logger log = LoggerFactory.getLogger(
-            PeerConnectivityManager.class);
+            SdxL3PeerManager.class);
 
     private static final short BGP_PORT = 179;
 
@@ -101,10 +101,10 @@
 
     private ConfigFactory configFactory =
             new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY,
-                    BgpPeersConfig.class, CONFIG_KEY) {
+                              CONFIG_CLASS, CONFIG_KEY) {
                 @Override
-                public BgpPeersConfig createConfig() {
-                    return new BgpPeersConfig();
+                public SdxProvidersConfig createConfig() {
+                    return new SdxProvidersConfig();
                 }
             };
 
@@ -138,14 +138,234 @@
     }
 
     /**
+     * Adds details for a BGP peer to the SDX-L3 configuration.
+     *
+     * @param peerName      Peer name
+     * @param peerAddress   Peer IP address
+     * @param port          Connection point with peer
+     * @param interfaceName Name of the interface configured on port
+     */
+    @Override
+    public void addPeerDetails(String peerName, IpAddress peerAddress, ConnectPoint port, String interfaceName) {
+
+        BgpConfig bgpConfig = getBgpConfig();
+        if (bgpConfig == null) {
+            throw new ItemNotFoundException("BGP configuration not found");
+        }
+
+        if (!peerAddressExists(bgpConfig, peerAddress)) {
+            throw new ItemNotFoundException("Peer IP not found");
+        }
+
+        Interface peerInterface = getInterface(port, interfaceName);
+        if (peerInterface == null) {
+            throw new ItemNotFoundException("Interface not found");
+        }
+
+        if (!interfaceSubnetIncludesIp(peerInterface, peerAddress)) {
+            throw new IllegalArgumentException("Interface not configured for IP "
+                                                       + peerAddress);
+        }
+
+        Interface confInterface = getConfiguredInterfaceForPeer(peerAddress);
+        if (confInterface != null) {
+            if (confInterface.equals(peerInterface)) {
+                // Do nothing since the association exists.
+                return;
+            } else {
+                // The peer is associated with another interface.
+                throw new IllegalArgumentException("Peer details already exist");
+            }
+        }
+
+        SdxProvidersConfig peersConfig =
+                configService.addConfig(sdxAppId, SdxProvidersConfig.class);
+        if (peerName != null && peerNameExists(peersConfig, peerName)) {
+            throw new IllegalArgumentException("Peer name in use");
+        }
+
+        addPeerToConf(peersConfig, peerName, peerAddress, port, interfaceName);
+        configService.
+                applyConfig(sdxAppId, SdxProvidersConfig.class, peersConfig.node());
+    }
+
+    /**
+     * Removes details for a BGP peer to the SDX-L3 configuration.
+     *
+     * @param peerAddress Peer IP address
+     */
+    @Override
+    public void removePeerDetails(IpAddress peerAddress) {
+        BgpConfig bgpConfig = getBgpConfig();
+        if (bgpConfig == null) {
+            throw new ItemNotFoundException("BGP configuration not found");
+        }
+
+        SdxProvidersConfig peersConfig =
+                configService.addConfig(sdxAppId, SdxProvidersConfig.class);
+
+        if (peersConfig.getPeerForIp(peerAddress) == null) {
+            throw new ItemNotFoundException("Peer details not found");
+        }
+
+        removePeerFromConf(peersConfig, peerAddress);
+        configService.applyConfig(sdxAppId,
+                                  SdxProvidersConfig.class,
+                                  peersConfig.node());
+    }
+
+    /**
+     * Returns BGP configuration has been specified and any BGP speaker
+     * exists in this configuration, else null is returned.
+     *
+     * @return BGP configuration or null
+     */
+    private BgpConfig getBgpConfig() {
+        BgpConfig bgpConfig = configService.
+                getConfig(routerAppId, BgpConfig.class);
+
+        if (bgpConfig == null || bgpConfig.bgpSpeakers().isEmpty()) {
+            return null;
+        }
+        return bgpConfig;
+    }
+
+    private Interface getInterface(ConnectPoint port, String interfaceName) {
+        Optional<Interface> interfaceMatch = interfaceService
+                .getInterfacesByPort(port)
+                .stream()
+                .filter(intf -> intf.name().equals(interfaceName))
+                .findFirst();
+        if (!interfaceMatch.isPresent()) {
+            // No such interface name configured for given connectPoint
+            return null;
+        }
+        return interfaceMatch.get();
+    }
+
+    boolean interfaceSubnetIncludesIp(Interface peerInterface, IpAddress peerAddress) {
+        if (peerInterface.ipAddresses().stream()
+                .anyMatch(intfIp -> intfIp.subnetAddress().
+                        contains(peerAddress))) {
+            // Interface configured subnet not including peer address
+            return true;
+        }
+        return false;
+    }
+
+    private boolean peerNameExists(SdxProvidersConfig config, String peerName) {
+        if (config.getPeerForName(Optional.of(peerName)) == null) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Adds the peer to the SdxProvidersConfig .
+     *
+     * @param peersConfig the BGP peers configuration
+     */
+    private void addPeerToConf(SdxProvidersConfig peersConfig, String peerName,
+                               IpAddress peerAddress, ConnectPoint port,
+                               String interfaceName) {
+        log.debug("Adding peer with IP to configuration: {}", peerAddress);
+        SdxProvidersConfig.PeerConfig peer = new SdxProvidersConfig.
+                PeerConfig(Optional.ofNullable(peerName), peerAddress,
+                           port, interfaceName);
+
+        peersConfig.addPeer(peer);
+    }
+
+    /**
+     * Removes the speaker from the BgpConfig service.
+     *
+     * @param peersConfig the BGP peeers configuration
+     */
+    private void removePeerFromConf(SdxProvidersConfig peersConfig,
+                                    IpAddress peerAddress) {
+        log.debug("Removing peer details from configuration: {}",
+                  peerAddress.toString());
+        peersConfig.removePeer(peerAddress);
+    }
+
+    /**
+     * Returns true if a given IP address has been specified as a BGP peer
+     * address in the network configuration.
+     *
+     * @param BgpConfig BGP configuration
+     * @param peerAddress IP address of peer
+     * @return whether address has been specified for a peer or not
+     */
+    private Boolean peerAddressExists(BgpConfig bgpConfig,
+                                      IpAddress peerAddress) {
+        List<IpAddress> peeringAddresses =
+                getPeerAddresses(bgpConfig);
+        if (!peeringAddresses.contains(peerAddress)) {
+            return false;
+        }
+        return true;
+    }
+
+    private Interface getConfiguredInterfaceForPeer(IpAddress peerAddress) {
+        if (sdxAppId == null) {
+            return null;
+        }
+
+        SdxProvidersConfig config = configService.getConfig(sdxAppId, SdxProvidersConfig.class);
+        if (config == null) {
+            return null;
+        }
+
+        ConnectPoint port = config.getPortForPeer(peerAddress);
+        String intfName = config.getInterfaceNameForPeer(peerAddress);
+        if (port != null && intfName != null) {
+            Optional<Interface> interfaceMatch = interfaceService
+                    .getInterfacesByPort(port)
+                    .stream()
+                    .filter(intf -> intf.name().equals(intfName))
+                    .findFirst();
+            if (interfaceMatch.isPresent()) {
+                return interfaceMatch.get();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the interface used as connection point to peer.
+     *
+     * @param peerAddress IP address of peer
+     * @return interface to the peer
+     */
+    @Override
+    public Interface getInterfaceForPeer(IpAddress peerAddress) {
+        Interface peeringInterface = getConfiguredInterfaceForPeer(peerAddress);
+        if (peeringInterface == null) {
+            peeringInterface = interfaceService.getMatchingInterface(peerAddress);
+        }
+        return peeringInterface;
+    }
+
+    @Override
+    public List<IpAddress> getPeerAddresses(BgpConfig bgpConfig) {
+        List<IpAddress> peeringAddresses = Lists.newArrayList();
+
+        List<BgpConfig.BgpSpeakerConfig> bgpSpeakers =
+                Lists.newArrayList(bgpConfig.bgpSpeakers());
+        bgpSpeakers.forEach(
+                s -> peeringAddresses.addAll(s.peers()));
+
+        return peeringAddresses;
+    }
+
+    /**
      * Sets up paths to establish connectivity between all internal
      * BGP speakers and external BGP peers.
      */
     private void setUpConnectivity() {
-        BgpConfig config = configService.getConfig(routerAppId, RoutingService.CONFIG_CLASS);
-
+        BgpConfig config = getBgpConfig();
         if (config == null) {
-            log.warn("No BgpConfig found");
+            log.warn("No BGP configuration found");
             return;
         }
 
@@ -201,23 +421,6 @@
         return intents;
     }
 
-    private Interface getConfiguredInterfaceForPeer(IpAddress peerAddress) {
-        if (sdxAppId == null) {
-            return null;
-        }
-
-        BgpPeersConfig config = configService.getConfig(sdxAppId, BgpPeersConfig.class);
-        if (config == null) {
-            return null;
-        }
-
-        String intfName = config.getInterfaceNameForPeer(peerAddress);
-        if (intfName != null) {
-            return interfaceService.getInterfaceByName(intfName);
-        }
-        return null;
-    }
-
     /**
      * Builds the required intents between the two pairs of connect points and
      * IP addresses.
@@ -250,7 +453,7 @@
             icmpProtocol = IPv6.PROTOCOL_ICMP6;
         }
 
-        // Path from BGP speaker to BGP peer matching destination TCP port 179
+        // Path from BGP speaker to BGP peer matching destination TCP connectPoint 179
         selector = buildSelector(tcpProtocol,
                 ipOne,
                 ipTwo,
@@ -269,7 +472,7 @@
                 .priority(PRIORITY_OFFSET)
                 .build());
 
-        // Path from BGP speaker to BGP peer matching source TCP port 179
+        // Path from BGP speaker to BGP peer matching source TCP connectPoint 179
         selector = buildSelector(tcpProtocol,
                 ipOne,
                 ipTwo,
@@ -288,7 +491,7 @@
                 .priority(PRIORITY_OFFSET)
                 .build());
 
-        // Path from BGP peer to BGP speaker matching destination TCP port 179
+        // Path from BGP peer to BGP speaker matching destination TCP connectPoint 179
         selector = buildSelector(tcpProtocol,
                 ipTwo,
                 ipOne,
@@ -307,7 +510,7 @@
                 .priority(PRIORITY_OFFSET)
                 .build());
 
-        // Path from BGP peer to BGP speaker matching source TCP port 179
+        // Path from BGP peer to BGP speaker matching source TCP connectPoint 179
         selector = buildSelector(tcpProtocol,
                 ipTwo,
                 ipOne,
@@ -373,8 +576,8 @@
      * @param ipProto IP protocol
      * @param srcIp source IP address
      * @param dstIp destination IP address
-     * @param srcTcpPort source TCP port, or null if shouldn't be set
-     * @param dstTcpPort destination TCP port, or null if shouldn't be set
+     * @param srcTcpPort source TCP connectPoint, or null if shouldn't be set
+     * @param dstTcpPort destination TCP connectPoint, or null if shouldn't be set
      * @return the new traffic selector
      */
     private TrafficSelector buildSelector(byte ipProto, IpAddress srcIp,
@@ -426,15 +629,6 @@
         return Key.of(keyString, sdxAppId);
     }
 
-    @Override
-    public Interface getInterfaceForPeer(IpAddress peeringAddress) {
-        Interface peeringInterface = getConfiguredInterfaceForPeer(peeringAddress);
-        if (peeringInterface == null) {
-            peeringInterface = interfaceService.getMatchingInterface(peeringAddress);
-        }
-        return peeringInterface;
-    }
-
     private class InternalNetworkConfigListener implements NetworkConfigListener {
 
         @Override
@@ -447,7 +641,8 @@
             case CONFIG_ADDED:
             case CONFIG_UPDATED:
             case CONFIG_REMOVED:
-                if (event.configClass() == RoutingService.CONFIG_CLASS) {
+                if (event.configClass() == RoutingService.CONFIG_CLASS ||
+                        event.configClass() == CONFIG_CLASS) {
                     setUpConnectivity();
                 }
                 break;
diff --git a/sdx-l3/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/sdx-l3/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 4757f78..237a9dc 100644
--- a/sdx-l3/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/sdx-l3/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -19,5 +19,11 @@
       <command>
           <action class="org.onosproject.sdxl3.cli.BgpPeersListCommand"/>
       </command>
+      <command>
+          <action class="org.onosproject.sdxl3.cli.AddPeerDetailsCommand"/>
+      </command>
+      <command>
+          <action class="org.onosproject.sdxl3.cli.RemovePeerDetailsCommand"/>
+      </command>
   </command-bundle>
 </blueprint>
diff --git a/sdx-l3/src/main/resources/config-examples/network-cfg.json b/sdx-l3/src/main/resources/config-examples/network-cfg.json
index a51ef92..7100e7a 100644
--- a/sdx-l3/src/main/resources/config-examples/network-cfg.json
+++ b/sdx-l3/src/main/resources/config-examples/network-cfg.json
@@ -6,14 +6,25 @@
           "name" : "AS1-conn1",
           "ips"  : [ "10.0.1.101/24" ],
           "mac"  : "00:00:00:00:00:01"
-        }
-      ]
-    },
-    "of:00000000000000a2/1" : {
-      "interfaces" : [
+        },
         {
           "name" : "AS1-conn2",
           "ips"  : [ "10.0.1.101/24" ],
+          "mac"  : "00:00:00:00:00:01",
+          "vlan" : "100"
+        }
+      ]
+    },
+    "of:00000000000000a3/1" : {
+      "interfaces" : [
+        {
+          "name" : "AS1-conn3",
+          "ips"  : [ "10.0.1.101/24" ],
+          "mac"  : "00:00:00:00:00:01"
+        },
+        {
+          "name" : "AS2-conn1",
+          "ips"  : [ "10.0.2.101/24" ],
           "mac"  : "00:00:00:00:00:01"
         }
       ]
@@ -38,19 +49,34 @@
     }
   },
   "apps" : {
-    "org.onosproject.sdxl3" : {
-      "bgpPeers" : [
-        {
-          "name" : "AS1-Router1",
-          "ip" : "10.0.1.1",
-          "interface" : "AS1-conn1"
-        },
-        {
-          "name" : "AS1-Router2",
-          "ip" : "10.0.1.129",
-          "interface" : "AS1-conn2"
-        }
-      ]
+    "org.onosproject.sdxl3": {
+      "providers": {
+        "bgpPeers": [
+          {
+            "name": "AS1-Router1",
+            "ip": "10.0.1.1",
+            "connectPoint": "of:00000000000000a1/1",
+            "intfName": "AS1-conn1"
+          },
+          {
+            "name": "AS1-Router2",
+            "ip": "10.0.1.2",
+            "connectPoint": "of:00000000000000a1/1",
+            "intfName": "AS1-conn2"
+          },
+          {
+            "name": "AS1-Router3",
+            "ip": "10.0.1.129",
+            "connectPoint": "of:00000000000000a3/1",
+            "intfName": "AS1-conn3"
+          },
+          {
+            "ip": "10.0.1.2",
+            "connectPoint": "of:00000000000000a1/1",
+            "intfName": "AS1-conn2"
+          }
+        ]
+      }
     },
     "org.onosproject.router" : {
       "bgp" : {
@@ -60,8 +86,15 @@
             "connectPoint" : "of:00000000000000a3/1",
             "peers" : [
               "10.0.1.1",
+              "10.0.1.2",
               "10.0.1.129",
-              "10.0.3.1",
+              "10.0.2.1",
+              "10.0.3.1"
+            ]
+          },
+          {
+            "connectPoint" : "of:00000000000000a3/1",
+            "peers" : [
               "10.0.4.1"
             ]
           }
@@ -69,4 +102,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/sdx-l3/src/main/resources/config-examples/route-server_network-cfg.json b/sdx-l3/src/main/resources/config-examples/route-server_network-cfg.json
index c2ea2e3..1bdc232 100644
--- a/sdx-l3/src/main/resources/config-examples/route-server_network-cfg.json
+++ b/sdx-l3/src/main/resources/config-examples/route-server_network-cfg.json
@@ -21,18 +21,22 @@
   },
   "apps" : {
     "org.onosproject.sdxl3" : {
-      "bgpPeers" : [
-        {
-          "name" : "AS65001-R1",
-          "ip" : "10.0.0.1",
-          "interface" : "AS 65001"
-        },
-        {
-          "name" : "AS65002-R2",
-          "ip" : "10.0.0.2",
-          "interface" : "AS 65002"
-        }
-      ]
+      "providers" : {
+        "bgpPeers": [
+          {
+            "name": "AS65001-R1",
+            "ip": "10.0.0.1",
+            "connectPoint": "of:00000000000000a1/1",
+            "intfName": "AS 65001"
+          },
+          {
+            "name": "AS65002-R2",
+            "ip": "10.0.0.2",
+            "connectPoint": "of:00000000000000a1/2",
+            "intfName": "AS 65002"
+          }
+        ]
+      }
     },
     "org.onosproject.router" : {
       "bgp" : {
diff --git a/sdx-l3/src/test/java/org/onosproject/sdxl3/BgpPeersConfigTest.java b/sdx-l3/src/test/java/org/onosproject/sdxl3/BgpPeersConfigTest.java
deleted file mode 100644
index fc2a6ed..0000000
--- a/sdx-l3/src/test/java/org/onosproject/sdxl3/BgpPeersConfigTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2014-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.sdxl3;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Sets;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.IpAddress;
-import org.onosproject.TestApplicationId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.incubator.net.config.basics.ConfigException;
-import org.onosproject.net.config.Config;
-import org.onosproject.net.config.ConfigApplyDelegate;
-import org.onosproject.sdxl3.config.BgpPeersConfig;
-
-import java.util.Optional;
-import java.util.Set;
-
-import static junit.framework.TestCase.assertEquals;
-
-public class BgpPeersConfigTest {
-    private static final ApplicationId APP_ID =
-            new TestApplicationId(SdxL3.SDX_L3_APP);
-    private static final String KEY = "key";
-
-    public static final String NAME1 = "peer1";
-    public static final String IP1_STRING = "10.0.1.1";
-    public static final IpAddress IP1 = IpAddress.valueOf(IP1_STRING);
-    public static final String INTF1 = "conn_point1";
-
-    public static final String IP2_STRING = "10.0.2.1";
-    public static final IpAddress IP2 = IpAddress.valueOf(IP2_STRING);
-    public static final String INTF2 = "conn_point2";
-
-    private static final String JSON_TREE = "[{" +
-            "\"" + BgpPeersConfig.NAME + "\" : \"" + NAME1 + "\", " +
-            "\"" + BgpPeersConfig.IP + "\" : \"" + IP1_STRING + "\", " +
-            "\"" + BgpPeersConfig.INTERFACE + "\" : \"" + INTF1 + "\"}, " +
-            "{ \"" + BgpPeersConfig.IP + "\" : \"" + IP2_STRING + "\", " +
-            "\"" + BgpPeersConfig.INTERFACE + "\" : \"" + INTF2 + "\"}] ";
-
-    BgpPeersConfig peersConfig = new BgpPeersConfig();
-
-    private final ConfigApplyDelegate delegate = new MockCfgDelegate();
-    private final ObjectMapper mapper = new ObjectMapper();
-
-    @Before
-    public void setUp()  throws Exception {
-        JsonNode node = new ObjectMapper().readTree(JSON_TREE);
-        peersConfig.init(APP_ID, KEY, node, mapper, delegate);
-    }
-
-    /**
-     * Tests if peers can be retrieved from JSON.
-     */
-    @Test
-    public void testBgpPeers() throws Exception {
-        assertEquals(createPeers(), peersConfig.bgpPeers());
-    }
-
-    /**
-     * Tests if interface name can be retrieved for given peer's IP.
-     */
-    @Test
-    public void testGetInterfaceNameForPeer() throws Exception {
-        assertEquals(INTF1, peersConfig.getInterfaceNameForPeer(IP1));
-    }
-
-    private Set<BgpPeersConfig.PeerConfig> createPeers() throws ConfigException {
-        Set<BgpPeersConfig.PeerConfig> peers = Sets.newHashSet();
-
-        peers.add(new BgpPeersConfig.PeerConfig(Optional.of(NAME1), IP1, INTF1));
-        peers.add(new BgpPeersConfig.PeerConfig(Optional.empty(), IP2, INTF2));
-
-        return peers;
-    }
-
-    private class MockCfgDelegate implements ConfigApplyDelegate {
-
-        @Override
-        public void onApply(@SuppressWarnings("rawtypes") Config config) {
-            config.apply();
-        }
-
-    }
-}
-
diff --git a/sdx-l3/src/test/java/org/onosproject/sdxl3/SdxProvidersConfigTest.java b/sdx-l3/src/test/java/org/onosproject/sdxl3/SdxProvidersConfigTest.java
new file mode 100644
index 0000000..f0f7bd0
--- /dev/null
+++ b/sdx-l3/src/test/java/org/onosproject/sdxl3/SdxProvidersConfigTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2016 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.sdxl3;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.sdxl3.config.SdxProvidersConfig;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class SdxProvidersConfigTest {
+    private static final ApplicationId APP_ID =
+            new TestApplicationId(SdxL3.SDX_L3_APP);
+    private static final String KEY = "key";
+
+    private static final String NAME1 = "peer1";
+    private static final String IP_STRING1 = "10.0.1.1";
+    private static final IpAddress IP1 = IpAddress.valueOf(IP_STRING1);
+    private static final String PORT_STRING1 = "of:00000000000000a1/1";
+    private static final ConnectPoint PORT1 =
+            ConnectPoint.deviceConnectPoint(PORT_STRING1);
+    private static final String INTF_NAME1 = "conn_point1";
+
+    private static final String IP_STRING2 = "10.0.2.1";
+    private static final IpAddress IP2 = IpAddress.valueOf(IP_STRING2);
+    private static final String PORT_STRING2 = "of:00000000000000a1/2";
+    private static final ConnectPoint PORT2 =
+            ConnectPoint.deviceConnectPoint(PORT_STRING2);
+    private static final String INTF_NAME2 = "conn_point2";
+
+    private static final String NAME3 = "new_peer";
+    private static final String IP_STRING3 = "10.0.3.1";
+    private static final String PORT_STRING3 = "of:00000000000000a1/3";
+    private static final ConnectPoint PORT3 =
+            ConnectPoint.deviceConnectPoint(PORT_STRING3);
+    private static final IpAddress IP3 = IpAddress.valueOf(IP_STRING3);
+    private static final String INTF_NAME3 = "conn_point3";
+
+    private static final String JSON_TREE = "{\"" + SdxProvidersConfig.PEERS + "\"" +
+            ": [{\"" + SdxProvidersConfig.NAME + "\" : \"" + NAME1 + "\", " +
+            "\"" + SdxProvidersConfig.IP + "\" : \"" + IP_STRING1 + "\", " +
+            "\"" + SdxProvidersConfig.CONN_POINT + "\" : \"" + PORT_STRING1 + "\", " +
+            "\"" + SdxProvidersConfig.INTF_NAME + "\" : \"" + INTF_NAME1 + "\"}, " +
+            "{ \"" + SdxProvidersConfig.IP + "\" : \"" + IP_STRING2 + "\", " +
+            "\"" + SdxProvidersConfig.CONN_POINT + "\" : \"" + PORT_STRING2 + "\", " +
+            "\"" + SdxProvidersConfig.INTF_NAME + "\" : \"" + INTF_NAME2 + "\"}]}";
+
+    private static final String EMPTY_JSON_TREE = "{ }";
+
+    private Set<SdxProvidersConfig.PeerConfig> peers = new HashSet<>();
+    private SdxProvidersConfig.PeerConfig peer1;
+
+    private SdxProvidersConfig peersConfig = new SdxProvidersConfig();
+    private SdxProvidersConfig emptyPeersConfig = new SdxProvidersConfig();
+
+    private final ConfigApplyDelegate delegate = new MockCfgDelegate();
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    @Before
+    public void setUp()  throws Exception {
+        peers = createPeers();
+        JsonNode node = new ObjectMapper().readTree(JSON_TREE);
+        peersConfig.init(APP_ID, KEY, node, mapper, delegate);
+        JsonNode emptyTree = new ObjectMapper().readTree(EMPTY_JSON_TREE);
+        emptyPeersConfig.init(APP_ID, KEY, emptyTree, mapper, delegate);
+    }
+
+    /**
+     * Tests if peers can be retrieved from JSON.
+     */
+    @Test
+    public void testBgpPeers() throws Exception {
+        assertEquals(peers, peersConfig.bgpPeers());
+    }
+
+    /**
+     * Tests if interface name can be retrieved for given peer's IP.
+     */
+    @Test
+    public void testGetInterfaceNameForPeer() throws Exception {
+        assertEquals(INTF_NAME1, peersConfig.getInterfaceNameForPeer(IP1));
+    }
+
+    /**
+     * Tests addition of new peer.
+     */
+    @Test
+    public void testAddPeer() throws Exception {
+        int initialSize = peersConfig.bgpPeers().size();
+        SdxProvidersConfig.PeerConfig newPeer = createNewPeer();
+        peersConfig.addPeer(newPeer);
+        assertEquals(initialSize + 1, peersConfig.bgpPeers().size());
+        peers.add(newPeer);
+        assertEquals(peers, peersConfig.bgpPeers());
+    }
+
+    /**
+     * Tests addition of new peer to empty configuration.
+     */
+    @Test
+    public void testAddPeerToEmpty() throws Exception {
+        emptyPeersConfig.addPeer(createNewPeer());
+        assertFalse(emptyPeersConfig.bgpPeers().isEmpty());
+    }
+
+    /**
+     * Tests getting peer configuration based on given name.
+     */
+    @Test
+    public void testGetPeerForName() throws Exception {
+        assertEquals(peer1, peersConfig.getPeerForName(Optional.of(NAME1)));
+    }
+
+    /**
+     * Tests getting peer configuration based on given IP.
+     */
+    @Test
+    public void testGetPeerForIp() throws Exception {
+        assertEquals(peer1, peersConfig.getPeerForIp(IP1));
+    }
+
+    /**
+     * Tests removing peer details based on given IP.
+     */
+    @Test
+    public void testRemovePeer() throws Exception {
+        int initialSize = peersConfig.bgpPeers().size();
+        peersConfig.removePeer(IP1);
+        assertEquals(initialSize - 1, peersConfig.bgpPeers().size());
+        peers.remove(peer1);
+        assertEquals(peers, peersConfig.bgpPeers());    }
+
+    private Set<SdxProvidersConfig.PeerConfig> createPeers() {
+        Set<SdxProvidersConfig.PeerConfig> peers = Sets.newHashSet();
+
+        peer1 = new SdxProvidersConfig.
+                PeerConfig(Optional.of(NAME1), IP1, PORT1, INTF_NAME1);
+        peers.add(peer1);
+        peers.add(new SdxProvidersConfig.
+                PeerConfig(Optional.empty(), IP2, PORT2, INTF_NAME2));
+
+        return peers;
+    }
+
+    private SdxProvidersConfig.PeerConfig createNewPeer() {
+        return new SdxProvidersConfig.
+                PeerConfig(Optional.of(NAME3), IP3, PORT3, INTF_NAME3);
+    }
+
+    private class MockCfgDelegate implements ConfigApplyDelegate {
+
+        @Override
+        public void onApply(@SuppressWarnings("rawtypes") Config config) {
+            config.apply();
+        }
+
+    }
+}
+