added multi-tenant support
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/ActivationManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/ActivationManager.java
new file mode 100644
index 0000000..a32fe12
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/ActivationManager.java
@@ -0,0 +1,4 @@
+package org.onosproject.fpcagent;
+
+public class ActivationManager {
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
index 430fb09..3447f83 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
@@ -17,18 +17,23 @@
 package org.onosproject.fpcagent;
 
 import com.google.common.base.Stopwatch;
+import com.google.common.collect.Maps;
 import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.felix.scr.annotations.*;
 import org.onosproject.config.DynamicConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
-import org.onosproject.fpcagent.util.CacheManager;
 import org.onosproject.fpcagent.util.ConfigHelper;
 import org.onosproject.fpcagent.workers.ZMQSBPublisherManager;
 import org.onosproject.fpcagent.workers.ZMQSBSubscriberManager;
 import org.onosproject.net.config.*;
 import org.onosproject.net.config.basics.SubjectFactories;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.connectioninfo.DefaultConnections;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.deregisterclient.DefaultDeregisterClientOutput;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.registerclient.DefaultRegisterClientInput;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.registerclient.DefaultRegisterClientOutput;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.IetfDmmFpcagentService;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.ClientIdentifier;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.ErrorTypeId;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.Result;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configure.DefaultConfigureInput;
@@ -49,6 +54,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.Optional;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 
 import static org.onosproject.fpcagent.util.FpcUtil.*;
@@ -58,7 +64,9 @@
  */
 @Component(immediate = true)
 @Service
-public class FpcManager implements IetfDmmFpcagentService, FpcService {
+public class FpcManager implements IetfDmmFpcagentService,
+        FpcService,
+        org.onosproject.yang.gen.v1.fpc.rev20150105.FpcService {
     private static final Logger log = LoggerFactory.getLogger(FpcManager.class);
 
     private static final Class<FpcConfig> CONFIG_CLASS = FpcConfig.class;
@@ -89,6 +97,7 @@
 
     /* Variables */
     private FpcConfig fpcConfig;
+    private ConcurrentMap<ClientIdentifier, DefaultRegisterClientInput> clientInfo = Maps.newConcurrentMap();
 
     /* Config */
     private ConfigFactory<ApplicationId, FpcConfig> fpcConfigConfigFactory =
@@ -122,6 +131,8 @@
 
         rpcRegistry.unregisterRpcService(this);
 
+        clientInfo.clear();
+
         log.info("FPC Agent Stopped");
     }
 
@@ -159,43 +170,45 @@
     @Override
     public RpcOutput configureDpn(RpcInput rpcInput) {
         Stopwatch timer = Stopwatch.createStarted();
-        DefaultConfigureDpnOutput output = new DefaultConfigureDpnOutput();
-        output.result(Result.of(ResultEnum.OK));
-        output.resultType(new DefaultEmptyCase());
+        DefaultConfigureDpnOutput configureDpnOutput = new DefaultConfigureDpnOutput();
+        configureDpnOutput.result(Result.of(ResultEnum.OK));
+        configureDpnOutput.resultType(new DefaultEmptyCase());
+        RpcOutput.Status status = RpcOutput.Status.RPC_SUCCESS;
         try {
-            tenantService.getModelObjects(rpcInput.data(), configureDpn).forEach(
-                    modelObject -> {
-                        DefaultConfigureDpnInput input = (DefaultConfigureDpnInput) modelObject;
-                        String dpnId = input.inputDpnId().fpcIdentity().union().string();
-                        switch (input.operation().enumeration()) {
-                            case ADD:
-                                log.info("Adding DPN {}", dpnId);
-                                // TODO
-                                break;
-                            case REMOVE:
-                                log.info("Removing DPN {}", dpnId);
-                                // TODO
-                                break;
-                        }
-                    });
+            for (ModelObject modelObject : tenantService.getModelObjects(rpcInput.data(), configureDpn)) {
+                DefaultConfigureDpnInput input = (DefaultConfigureDpnInput) modelObject;
+                switch (input.operation().enumeration()) {
+                    case ADD:
+                        configureDpnOutput = tenantService.configureDpnAdd(input);
+                        break;
+                    case REMOVE:
+                        configureDpnOutput = tenantService.configureDpnRemove(input);
+                        break;
+                }
+            }
         } catch (Exception e) {
+            status = RpcOutput.Status.RPC_FAILURE;
+            org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbodydpn.resulttype.DefaultErr defaultErr = new org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbodydpn.resulttype.DefaultErr();
+            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
+            defaultErr.errorTypeId(ErrorTypeId.of(0));
+            configureDpnOutput.resultType(defaultErr);
+            configureDpnOutput.result(Result.of(ResultEnum.ERR));
             log.error(ExceptionUtils.getFullStackTrace(e));
         }
         ResourceData dataNode = modelConverter.createDataNode(
-                DefaultModelObjectData.builder().addModelObject(output).build()
+                DefaultModelObjectData.builder()
+                        .addModelObject(configureDpnOutput)
+                        .build()
         );
         log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
-        log.debug("Stats:\nContexts: {}\nDpns: {}",
-                CacheManager.getInstance().contextsCache.stats(),
-                CacheManager.getInstance().dpnsCache.stats()
-        );
-        return new RpcOutput(RpcOutput.Status.RPC_SUCCESS, dataNode.dataNodes().get(0));
+        return new RpcOutput(status, dataNode.dataNodes().get(0));
     }
 
     @Override
     public RpcOutput configure(RpcInput rpcInput) {
         Stopwatch timer = Stopwatch.createStarted();
         DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
+        RpcOutput.Status status = RpcOutput.Status.RPC_SUCCESS;
         try {
             for (ModelObject modelObject : tenantService.getModelObjects(rpcInput.data(), configure)) {
                 DefaultConfigureInput input = (DefaultConfigureInput) modelObject;
@@ -203,14 +216,14 @@
                     case CREATE:
                         configureOutput = tenantService.configureCreate(
                                 (CreateOrUpdate) input.opBody(),
-                                input.clientId(),
+                                clientInfo.get(input.clientId()),
                                 input.opId()
                         );
                         break;
                     case UPDATE:
                         configureOutput = tenantService.configureUpdate(
                                 (CreateOrUpdate) input.opBody(),
-                                input.clientId(),
+                                clientInfo.get(input.clientId()),
                                 input.opId()
                         );
                         break;
@@ -219,7 +232,7 @@
                     case DELETE:
                         configureOutput = tenantService.configureDelete(
                                 (DeleteOrQuery) input.opBody(),
-                                input.clientId(),
+                                clientInfo.get(input.clientId()),
                                 input.opId()
                         );
                         break;
@@ -228,6 +241,7 @@
             }
         } catch (Exception e) {
             // if there is an exception respond with an error.
+            status = RpcOutput.Status.RPC_FAILURE;
             DefaultErr defaultErr = new DefaultErr();
             defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
             defaultErr.errorTypeId(ErrorTypeId.of(0));
@@ -241,58 +255,54 @@
                         .build()
         );
         log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
-        log.debug("Stats:\nContexts: {}\nDpns: {}",
-                CacheManager.getInstance().contextsCache.stats(),
-                CacheManager.getInstance().dpnsCache.stats()
-        );
-        return new RpcOutput(RpcOutput.Status.RPC_SUCCESS, dataNode.dataNodes().get(0));
+        return new RpcOutput(status, dataNode.dataNodes().get(0));
     }
 
     @Override
     public RpcOutput configureBundles(RpcInput rpcInput) {
         Stopwatch timer = Stopwatch.createStarted();
         DefaultConfigureBundlesOutput configureBundlesOutput = new DefaultConfigureBundlesOutput();
+        RpcOutput.Status status = RpcOutput.Status.RPC_SUCCESS;
         try {
             for (ModelObject modelObject : tenantService.getModelObjects(rpcInput.data(), configureBundles)) {
                 DefaultConfigureBundlesInput input = (DefaultConfigureBundlesInput) modelObject;
-                input.bundles().forEach(
-                        bundle -> {
-                            DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
-                            switch (bundle.opType()) {
-                                case CREATE:
-                                    configureOutput = tenantService.configureCreate(
-                                            (CreateOrUpdate) bundle.opBody(),
-                                            bundle.clientId(),
-                                            bundle.opId()
-                                    );
-                                    break;
-                                case UPDATE:
-                                    configureOutput = tenantService.configureUpdate(
-                                            (CreateOrUpdate) bundle.opBody(),
-                                            bundle.clientId(),
-                                            bundle.opId()
-                                    );
-                                    break;
-                                case QUERY:
-                                    break;
-                                case DELETE:
-                                    configureOutput = tenantService.configureDelete(
-                                            (DeleteOrQuery) bundle.opBody(),
-                                            bundle.clientId(),
-                                            bundle.opId()
-                                    );
-                                    break;
-                            }
-                            Bundles result = new DefaultBundles();
-                            result.opId(bundle.opId());
-                            result.result(configureOutput.result());
-                            result.resultType(configureOutput.resultType());
-                            configureBundlesOutput.addToBundles(result);
-                        }
-                );
+                for (org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configurebundles.configurebundlesinput.Bundles bundle : input.bundles()) {
+                    DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
+                    switch (bundle.opType()) {
+                        case CREATE:
+                            configureOutput = tenantService.configureCreate(
+                                    (CreateOrUpdate) bundle.opBody(),
+                                    clientInfo.get(input.clientId()),
+                                    bundle.opId()
+                            );
+                            break;
+                        case UPDATE:
+                            configureOutput = tenantService.configureUpdate(
+                                    (CreateOrUpdate) bundle.opBody(),
+                                    clientInfo.get(input.clientId()),
+                                    bundle.opId()
+                            );
+                            break;
+                        case QUERY:
+                            break;
+                        case DELETE:
+                            configureOutput = tenantService.configureDelete(
+                                    (DeleteOrQuery) bundle.opBody(),
+                                    clientInfo.get(input.clientId()),
+                                    bundle.opId()
+                            );
+                            break;
+                    }
+                    Bundles result = new DefaultBundles();
+                    result.opId(bundle.opId());
+                    result.result(configureOutput.result());
+                    result.resultType(configureOutput.resultType());
+                    configureBundlesOutput.addToBundles(result);
+                }
             }
         } catch (Exception e) {
             // if there is an exception respond with an error.
+            status = RpcOutput.Status.RPC_FAILURE;
             log.error(ExceptionUtils.getFullStackTrace(e));
         }
         ResourceData dataNode = modelConverter.createDataNode(
@@ -301,28 +311,101 @@
                         .build()
         );
         log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
-        log.debug("Stats:\nContexts: {}\nDpns: {}",
-                CacheManager.getInstance().contextsCache.stats(),
-                CacheManager.getInstance().dpnsCache.stats()
-        );
-        return new RpcOutput(RpcOutput.Status.RPC_SUCCESS, dataNode.dataNodes().get(0));
+        return new RpcOutput(status, dataNode.dataNodes().get(0));
     }
 
     @Override
     public RpcOutput eventRegister(RpcInput rpcInput) {
+        Stopwatch timer = Stopwatch.createStarted();
+        log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
         return null;
     }
 
     @Override
     public RpcOutput eventDeregister(RpcInput rpcInput) {
+        Stopwatch timer = Stopwatch.createStarted();
+        log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
         return null;
     }
 
     @Override
     public RpcOutput probe(RpcInput rpcInput) {
+        Stopwatch timer = Stopwatch.createStarted();
+        log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
         return null;
     }
 
+    @Override
+    public RpcOutput registerClient(RpcInput rpcInput) {
+        Stopwatch timer = Stopwatch.createStarted();
+        DefaultRegisterClientOutput registerClientOutput = new DefaultRegisterClientOutput();
+        RpcOutput.Status status = RpcOutput.Status.RPC_SUCCESS;
+
+        try {
+            for (ModelObject modelObject : tenantService.getModelObjects(rpcInput.data(), registerClient)) {
+                DefaultRegisterClientInput input = (DefaultRegisterClientInput) modelObject;
+                if (clientInfo.containsKey(input.clientId())) {
+                    throw new RuntimeException("Client already registered.");
+                }
+                clientInfo.put(input.clientId(), input);
+                registerClientOutput.clientId(input.clientId());
+                registerClientOutput.supportedFeatures(input.supportedFeatures());
+                registerClientOutput.endpointUri(input.endpointUri());
+                registerClientOutput.supportsAckModel(input.supportsAckModel());
+                registerClientOutput.tenantId(input.tenantId());
+
+//                tenantService.createNode();
+            }
+        } catch (Exception e) {
+            // if there is an exception respond with an error.
+            status = RpcOutput.Status.RPC_FAILURE;
+            log.error(ExceptionUtils.getFullStackTrace(e));
+        }
+
+        ResourceData dataNode = modelConverter.createDataNode(
+                DefaultModelObjectData.builder()
+                        .addModelObject(registerClientOutput)
+                        .build()
+        );
+
+        log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
+        return new RpcOutput(status, dataNode.dataNodes().get(0));
+    }
+
+    @Override
+    public RpcOutput deregisterClient(RpcInput rpcInput) {
+        Stopwatch timer = Stopwatch.createStarted();
+        DefaultDeregisterClientOutput deregisterClientOutput = new DefaultDeregisterClientOutput();
+        RpcOutput.Status status = RpcOutput.Status.RPC_SUCCESS;
+
+        try {
+            for (ModelObject modelObject : tenantService.getModelObjects(rpcInput.data(), registerClient)) {
+                DefaultRegisterClientInput input = (DefaultRegisterClientInput) modelObject;
+                if (!clientInfo.containsKey(input.clientId())) {
+                    throw new RuntimeException("Client does not exist.");
+                }
+                clientInfo.remove(input.clientId());
+                deregisterClientOutput.clientId(input.clientId());
+
+                DefaultConnections defaultConnections = new DefaultConnections();
+                defaultConnections.clientId(input.clientId().toString());
+            }
+        } catch (Exception e) {
+            // if there is an exception respond with an error.
+            status = RpcOutput.Status.RPC_FAILURE;
+            log.error(ExceptionUtils.getFullStackTrace(e));
+        }
+
+        ResourceData dataNode = modelConverter.createDataNode(
+                DefaultModelObjectData.builder()
+                        .addModelObject(deregisterClientOutput)
+                        .build()
+        );
+
+        log.debug("Time Elapsed {} ms", timer.stop().elapsed(TimeUnit.MILLISECONDS));
+        return new RpcOutput(status, dataNode.dataNodes().get(0));
+    }
+
     private class InternalNetworkConfigListener implements NetworkConfigListener {
 
         @Override
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantManager.java
index 0eedd7b..19b0960 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantManager.java
@@ -16,7 +16,6 @@
 
 package org.onosproject.fpcagent;
 
-import com.google.common.collect.Maps;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.felix.scr.annotations.*;
@@ -24,16 +23,17 @@
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.util.AbstractAccumulator;
 import org.onlab.util.Accumulator;
-import org.onosproject.config.DynamicConfigEvent;
-import org.onosproject.config.DynamicConfigListener;
-import org.onosproject.config.DynamicConfigService;
-import org.onosproject.config.Filter;
+import org.onosproject.config.*;
 import org.onosproject.fpcagent.util.CacheManager;
 import org.onosproject.fpcagent.util.DpnCommunicationService;
 import org.onosproject.fpcagent.util.DpnNgicCommunicator;
 import org.onosproject.fpcagent.util.FpcUtil;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.DefaultConnectionInfo;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.registerclient.DefaultRegisterClientInput;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.*;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configure.DefaultConfigureOutput;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configuredpn.DefaultConfigureDpnInput;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configuredpn.DefaultConfigureDpnOutput;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.instructions.instructions.instrtype.Instr3GppMob;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.opinput.opbody.CreateOrUpdate;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.opinput.opbody.DeleteOrQuery;
@@ -41,14 +41,17 @@
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.result.ResultEnum;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbody.resulttype.DefaultCommonSuccess;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbody.resulttype.DefaultDeleteSuccess;
-import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbody.resulttype.DefaultErr;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbodydpn.resulttype.DefaultCommonDeleteSuccess;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbodydpn.resulttype.DefaultEmptyCase;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.DefaultTenant;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.DefaultFpcMobility;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.DefaultFpcPolicy;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.DefaultFpcTopology;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpcmobility.ContextsKeys;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpcmobility.DefaultContexts;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpctopology.DefaultDpns;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcContextId;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcDpnId;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcIdentity;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.fpccontext.Dpns;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.mobilityinfo.mobprofileparameters.ThreegppTunnel;
@@ -74,8 +77,6 @@
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
-    private final Map<ClientIdentifier, DefaultTenant> clientIdMap = Maps.newHashMap();
-
     private final InternalConfigListener listener = new InternalConfigListener();
 
     private final Accumulator<DynamicConfigEvent> accumulator = new InternalEventAccumulator();
@@ -86,13 +87,14 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private DynamicConfigService dynamicConfigService;
 
-    private DpnCommunicationService dpnCommunicationService;
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private DynamicConfigStore dynamicConfigStore;
 
-    private CacheManager cacheManager = CacheManager.getInstance();
+    private DpnCommunicationService dpnCommunicationService;
 
     @Activate
     protected void activate() {
-        cacheManager.addManager(this);
+        CacheManager.addManager(this);
         FpcUtil.modelConverter = modelConverter;
         getResourceId();
 
@@ -114,8 +116,12 @@
 
         // Create nodes in dynamic configuration store for RESTCONF accessibility.
         final ModelObjectId root = ModelObjectId.builder().build();
+
+        final DefaultConnectionInfo defaultConnectionInfo = new DefaultConnectionInfo();
+
         createNode(tenants, root);
         createNode(fpcAgentInfo, root);
+        createNode(defaultConnectionInfo, root);
 
         log.info("Tenant Service Started");
     }
@@ -160,17 +166,7 @@
 
     @Override
     public Optional<DefaultTenant> getTenant(ClientIdentifier clientId) {
-        return Optional.ofNullable(clientIdMap.get(clientId));
-    }
-
-    @Override
-    public Optional<DefaultTenant> registerClient(ClientIdentifier clientId, FpcIdentity tenantId) {
-        return getTenant(tenantId).map(tenant -> clientIdMap.put(clientId, tenant));
-    }
-
-    @Override
-    public Optional<DefaultTenant> deregisterClient(ClientIdentifier clientId) {
-        return Optional.ofNullable(clientIdMap.remove(clientId));
+        return Optional.empty();
     }
 
     @Override
@@ -206,434 +202,505 @@
         );
     }
 
+    private Collection<Callable<Object>> create(
+            Dpns dpn,
+            Contexts context,
+            DefaultRegisterClientInput clientId,
+            OpIdentifier operationId
+    ) throws Exception {
+        Collection<Callable<Object>> tasks = new ArrayList<>();
+        CacheManager cacheManager = CacheManager.getInstance(clientId.tenantId());
+        // check if dpns exists and if there is a DPN registered for the wanted identifier.
+        if (!cacheManager.dpnsCache.get(dpn.dpnId()).isPresent()) {
+            // throw exception if DPN ID is not registered.
+            throw new RuntimeException("DPN ID is not registered to the topology.");
+        }
+
+        // handle only 3GPP instructions.
+        if (!(context.instructions().instrType() instanceof Instr3GppMob)) {
+            throw new RuntimeException("No 3GPP instructions where given.");
+        }
+
+        // from DPN ID find the Network and Node Identifiers
+        Optional<String> key = cacheManager.dpnsCache.get(dpn.dpnId())
+                .map(node -> node.nodeId() + "/" + node.networkId());
+        if (!key.isPresent()) {
+            throw new RuntimeException("DPN does not have node and network ID defined.");
+        }
+
+        // get DPN Topic from Node/Network pair
+        Short topic_id = getTopicFromNode(key.get());
+        if (topic_id == null) {
+            throw new RuntimeException("Could not find Topic ID");
+        }
+
+        // parse tunnel identifiers. throw exception if mobility profile parameters are missing.
+        if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+            throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+
+        }
+        if (!(context.dl().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+            throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+        }
+
+        // Extract variables
+        Instr3GppMob instr3GppMob = (Instr3GppMob) context.instructions().instrType();
+        String commands = Bits.toString(instr3GppMob.instr3GppMob().bits());
+
+        Ip4Address s1u_enodeb_ipv4 = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
+                s1u_sgw_ipv4 = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
+
+        long client_id = clientId.clientId().fpcIdentity().union().int64(),
+                session_id = context.contextId().fpcIdentity().union().int64(),
+                s1u_sgw_gtpu_teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+                        .mobprofileParameters()).tunnelIdentifier(),
+                s1u_enb_gtpu_teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+                        .mobprofileParameters()).tunnelIdentifier();
+
+        BigInteger op_id = operationId.uint64(),
+                imsi = context.imsi().uint64();
+
+        short default_ebi = context.ebi().uint8();
+
+        // TODO try to make sense out of this...
+        if (commands.contains("session")) {
+            DefaultContexts convertContext = convertContext(context);
+            tasks.add(Executors.callable(() -> {
+                dpnCommunicationService.create_session(
+                        topic_id,
+                        imsi,
+                        default_ebi,
+                        Ip4Prefix.valueOf(context.delegatingIpPrefixes().get(0).toString()).address(),
+                        s1u_sgw_gtpu_teid,
+                        s1u_sgw_ipv4,
+                        session_id,
+                        client_id,
+                        op_id
+                );
+
+                ModelObjectId modelObjectId = defaultTenantBuilder()
+                        .addChild(DefaultFpcMobility.class)
+                        .build();
+                createNode(convertContext, modelObjectId);
+                cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+            }));
+
+            if (commands.contains("downlink")) {
+                tasks.add(Executors.callable(() -> {
+                    dpnCommunicationService.modify_bearer(
+                            topic_id,
+                            s1u_sgw_ipv4,
+                            s1u_enb_gtpu_teid,
+                            s1u_enodeb_ipv4,
+                            session_id,
+                            client_id,
+                            op_id
+                    );
+
+                    ModelObjectId modelObjectId = defaultTenantBuilder()
+                            .addChild(DefaultFpcMobility.class)
+                            .build();
+                    createNode(convertContext, modelObjectId);
+                    cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+                }));
+            }
+        } else if (commands.contains("indirect-forward")) {
+            // TODO - Modify API for Indirect Forwarding to/from another SGW
+        } else if (commands.contains("uplink")) {
+            // TODO create bearer ul
+        }
+        return tasks;
+    }
+
     @Override
     public DefaultConfigureOutput configureCreate(
             CreateOrUpdate create,
-            ClientIdentifier clientId,
+            DefaultRegisterClientInput clientInfo,
             OpIdentifier operationId
-    ) {
+    ) throws Exception {
         DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
         Collection<Callable<Object>> tasks = new ArrayList<>();
-        try {
-            DefaultCommonSuccess defaultCommonSuccess = new DefaultCommonSuccess();
-            for (Contexts context : create.contexts()) {
-                // add context to response.
-                defaultCommonSuccess.addToContexts(context);
 
-                // check if mobility exists and if the context id exists.
-                if (cacheManager.contextsCache.get(context.contextId()).isPresent()) {
-                    // throw exception if trying to create a Context that already exists.
-                    throw new IllegalStateException("Context tried to create already exists. Please issue update operation..");
-                }
+        DefaultCommonSuccess defaultCommonSuccess = new DefaultCommonSuccess();
+        for (Contexts context : create.contexts()) {
+            // add context to response.
+            defaultCommonSuccess.addToContexts(context);
 
-                for (Dpns dpn : context.dpns()) {
-                    // check if dpns exists and if there is a DPN registered for the wanted identifier.
-                    if (!cacheManager.dpnsCache.get(dpn.dpnId()).isPresent()) {
-                        // throw exception if DPN ID is not registered.
-                        throw new IllegalStateException("DPN ID is not registered to the topology.");
-                    }
-
-                    // handle only 3GPP instructions.
-                    if (!(context.instructions().instrType() instanceof Instr3GppMob)) {
-                        throw new IllegalArgumentException("No 3GPP instructions where given.");
-                    }
-
-                    // from DPN ID find the Network and Node Identifiers
-                    Optional<String> key = cacheManager.dpnsCache.get(dpn.dpnId())
-                            .map(node -> node.nodeId() + "/" + node.networkId());
-                    if (!key.isPresent()) {
-                        throw new IllegalArgumentException("DPN does not have node and network ID defined.");
-                    }
-
-                    // get DPN Topic from Node/Network pair
-                    Short topic_id = getTopicFromNode(key.get());
-                    if (topic_id == null) {
-                        throw new IllegalArgumentException("Could not find Topic ID");
-                    }
-
-                    // parse tunnel identifiers. throw exception if mobility profile parameters are missing.
-                    if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
-                        throw new IllegalArgumentException("mobprofileParameters are not instance of ThreegppTunnel");
-
-                    }
-                    if (!(context.dl().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
-                        throw new IllegalArgumentException("mobprofileParameters are not instance of ThreegppTunnel");
-                    }
-
-                    // Extract variables
-                    Instr3GppMob instr3GppMob = (Instr3GppMob) context.instructions().instrType();
-                    String commands = Bits.toString(instr3GppMob.instr3GppMob().bits());
-
-                    Ip4Address s1u_enodeb_ipv4 = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
-                            s1u_sgw_ipv4 = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
-
-                    long client_id = clientId.fpcIdentity().union().int64(),
-                            session_id = context.contextId().fpcIdentity().union().int64(),
-                            s1u_sgw_gtpu_teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
-                                    .mobprofileParameters()).tunnelIdentifier(),
-                            s1u_enb_gtpu_teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
-                                    .mobprofileParameters()).tunnelIdentifier();
-
-                    BigInteger op_id = operationId.uint64(),
-                            imsi = context.imsi().uint64();
-
-                    short default_ebi = context.ebi().uint8();
-
-                    // TODO try to make sense out of this...
-                    if (commands.contains("session")) {
-                        DefaultContexts convertContext = convertContext(context);
-                        tasks.add(Executors.callable(() -> {
-                            dpnCommunicationService.create_session(
-                                    topic_id,
-                                    imsi,
-                                    default_ebi,
-                                    Ip4Prefix.valueOf(context.delegatingIpPrefixes().get(0).toString()).address(),
-                                    s1u_sgw_gtpu_teid,
-                                    s1u_sgw_ipv4,
-                                    session_id,
-                                    client_id,
-                                    op_id
-                            );
-
-                            ModelObjectId modelObjectId = defaultTenantBuilder()
-                                    .addChild(DefaultFpcMobility.class)
-                                    .build();
-                            createNode(convertContext, modelObjectId);
-//                            cacheManager.contextsCache.invalidate(context.contextId());
-                            cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
-                        }));
-
-                        if (commands.contains("downlink")) {
-                            tasks.add(Executors.callable(() -> {
-                                dpnCommunicationService.modify_bearer(
-                                        topic_id,
-                                        s1u_sgw_ipv4,
-                                        s1u_enb_gtpu_teid,
-                                        s1u_enodeb_ipv4,
-                                        session_id,
-                                        client_id,
-                                        op_id
-                                );
-
-                                ModelObjectId modelObjectId = defaultTenantBuilder()
-                                        .addChild(DefaultFpcMobility.class)
-                                        .build();
-                                createNode(convertContext, modelObjectId);
-//                                cacheManager.contextsCache.invalidate(context.contextId());
-                                cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
-                            }));
-                        }
-                    } else if (commands.contains("indirect-forward")) {
-                        // TODO - Modify API for Indirect Forwarding to/from another SGW
-                    } else if (commands.contains("uplink")) {
-                        // TODO create bearer ul
-                    }
-                }
+            // check if mobility exists and if the context id exists.
+            if (CacheManager.getInstance(clientInfo.tenantId()).contextsCache.get(context.contextId()).isPresent()) {
+                // throw exception if trying to create a Context that already exists.
+                throw new RuntimeException("Context tried to create already exists. Please issue update operation..");
             }
 
-            // execute all tasks.
-            ExecutorService executor = Executors.newWorkStealingPool();
-            executor.invokeAll(tasks).forEach(
-                    future -> {
-                        try {
-                            future.get();
-                        } catch (Exception e) {
-                            log.error(ExceptionUtils.getFullStackTrace(e));
-                            throw new IllegalStateException(e);
-                        }
-                    }
-            );
-
-            configureOutput.resultType(defaultCommonSuccess);
-            configureOutput.result(Result.of(ResultEnum.OK));
-        } catch (Exception e) {
-            // if there is an exception respond with an error.
-            log.error(ExceptionUtils.getFullStackTrace(e));
-            DefaultErr defaultErr = new DefaultErr();
-            configureOutput.resultType(defaultErr);
-            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
-            defaultErr.errorTypeId(ErrorTypeId.of(0));
+            for (Dpns dpn : context.dpns()) {
+                tasks = create(dpn, context, clientInfo, operationId);
+            }
         }
+
+        // execute all tasks.
+        ExecutorService executor = Executors.newWorkStealingPool();
+        executor.invokeAll(tasks).forEach(
+                future -> {
+                    try {
+                        future.get();
+                    } catch (Exception e) {
+                        log.error(ExceptionUtils.getFullStackTrace(e));
+                        throw new RuntimeException(e);
+                    }
+                }
+        );
+
+        configureOutput.resultType(defaultCommonSuccess);
+        configureOutput.result(Result.of(ResultEnum.OK));
+
         return configureOutput;
     }
 
+    private Collection<Callable<Object>> update(
+            Dpns dpn,
+            Contexts context,
+            DefaultRegisterClientInput clientId,
+            OpIdentifier operationId
+    ) throws Exception {
+        Collection<Callable<Object>> tasks = new ArrayList<>();
+        CacheManager cacheManager = CacheManager.getInstance(clientId.tenantId());
+        // check if dpns exists and if there is a DPN registered for the wanted identifier.
+        if (!cacheManager.dpnsCache.get(dpn.dpnId()).isPresent()) {
+            // throw exception if DPN ID is not registered.
+            throw new RuntimeException("DPN ID is not registered to the topology.");
+        }
+
+        // handle only 3GPP instructions.
+        if (!(context.instructions().instrType() instanceof Instr3GppMob)) {
+            throw new RuntimeException("No 3GPP instructions where given.");
+        }
+
+        // from DPN ID find the Network and Node Identifiers
+        Optional<String> key = cacheManager.dpnsCache.get(dpn.dpnId())
+                .map(node -> node.nodeId() + "/" + node.networkId());
+        if (!key.isPresent()) {
+            throw new RuntimeException("DPN does not have node and network ID defined.");
+        }
+
+        // get DPN Topic from Node/Network pair
+        Short topic_id = getTopicFromNode(key.get());
+        if (topic_id == null) {
+            throw new RuntimeException("Could not find Topic ID");
+        }
+
+        if (!(context.dl().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+            throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+        }
+
+        Instr3GppMob instr3GppMob = (Instr3GppMob) context.instructions().instrType();
+        String commands = Bits.toString(instr3GppMob.instr3GppMob().bits());
+
+        Ip4Address s1u_enodeb_ipv4 = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
+                s1u_sgw_ipv4 = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
+
+        long s1u_enb_gtpu_teid = ((ThreegppTunnel) context.dl().mobilityTunnelParameters().mobprofileParameters()).tunnelIdentifier(),
+                cId = clientId.clientId().fpcIdentity().union().int64(),
+                contextId = context.contextId().fpcIdentity().union().int64();
+
+        BigInteger opId = operationId.uint64();
+
+        DefaultContexts convertContext = convertContext(context);
+        if (commands.contains("downlink")) {
+            if (context.dl().lifetime() >= 0L) {
+                tasks.add(Executors.callable(() -> {
+                    dpnCommunicationService.modify_bearer(
+                            topic_id,
+                            s1u_sgw_ipv4,
+                            s1u_enb_gtpu_teid,
+                            s1u_enodeb_ipv4,
+                            contextId,
+                            cId,
+                            opId
+                    );
+
+                    ModelObjectId modelObjectId = defaultTenantBuilder()
+                            .addChild(DefaultFpcMobility.class)
+                            .build();
+                    updateNode(convertContext, modelObjectId);
+                    cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+                }));
+            } else {
+                // TODO delete bearer
+            }
+        }
+        if (commands.contains("uplink")) {
+            if (context.ul().lifetime() >= 0L) {
+                tasks.add(Executors.callable(() -> {
+                    dpnCommunicationService.modify_bearer(
+                            topic_id,
+                            s1u_sgw_ipv4,
+                            s1u_enb_gtpu_teid,
+                            s1u_enodeb_ipv4,
+                            contextId,
+                            cId,
+                            opId
+                    );
+
+                    ModelObjectId modelObjectId = defaultTenantBuilder()
+                            .addChild(DefaultFpcMobility.class)
+                            .build();
+                    updateNode(convertContext, modelObjectId);
+                    cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+                }));
+            } else {
+                // TODO delete bearer
+            }
+        }
+        return tasks;
+    }
+
     @Override
     public DefaultConfigureOutput configureUpdate(
             CreateOrUpdate update,
-            ClientIdentifier clientId,
+            DefaultRegisterClientInput clientInfo,
             OpIdentifier operationId
-    ) {
+    ) throws Exception {
         DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
         Collection<Callable<Object>> tasks = new ArrayList<>();
-        try {
-            DefaultCommonSuccess defaultCommonSuccess = new DefaultCommonSuccess();
-            for (Contexts context : update.contexts()) {
-                // add updated context to response.
-                defaultCommonSuccess.addToContexts(context);
 
-                // check if contexts are populated and if they include the wanted context to update.
-                if (!cacheManager.contextsCache.get(context.contextId()).isPresent()) {
-                    // throw exception if wanted context does not exist.
-                    throw new IllegalStateException("Context doesn't exist. Please issue create operation..");
-                }
+        DefaultCommonSuccess defaultCommonSuccess = new DefaultCommonSuccess();
+        for (Contexts context : update.contexts()) {
+            // add updated context to response.
+            defaultCommonSuccess.addToContexts(context);
 
-                for (Dpns dpn : context.dpns()) {
-                    // check if dpns exists and if there is a DPN registered for the wanted identifier.
-                    if (!cacheManager.dpnsCache.get(dpn.dpnId()).isPresent()) {
-                        // throw exception if DPN ID is not registered.
-                        throw new IllegalStateException("DPN ID is not registered to the topology.");
-                    }
-
-                    // handle only 3GPP instructions.
-                    if (!(context.instructions().instrType() instanceof Instr3GppMob)) {
-                        throw new IllegalArgumentException("No 3GPP instructions where given.");
-                    }
-
-                    // from DPN ID find the Network and Node Identifiers
-                    Optional<String> key = cacheManager.dpnsCache.get(dpn.dpnId())
-                            .map(node -> node.nodeId() + "/" + node.networkId());
-                    if (!key.isPresent()) {
-                        throw new IllegalArgumentException("DPN does not have node and network ID defined.");
-                    }
-
-                    // get DPN Topic from Node/Network pair
-                    Short topic_id = getTopicFromNode(key.get());
-                    if (topic_id == null) {
-                        throw new IllegalArgumentException("Could not find Topic ID");
-                    }
-
-                    if (!(context.dl().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
-                        throw new IllegalArgumentException("mobprofileParameters are not instance of ThreegppTunnel");
-                    }
-
-                    Instr3GppMob instr3GppMob = (Instr3GppMob) context.instructions().instrType();
-                    String commands = Bits.toString(instr3GppMob.instr3GppMob().bits());
-
-                    Ip4Address s1u_enodeb_ipv4 = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
-                            s1u_sgw_ipv4 = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
-
-                    long s1u_enb_gtpu_teid = ((ThreegppTunnel) context.dl().mobilityTunnelParameters().mobprofileParameters()).tunnelIdentifier(),
-                            cId = clientId.fpcIdentity().union().int64(),
-                            contextId = context.contextId().fpcIdentity().union().int64();
-
-                    BigInteger opId = operationId.uint64();
-
-                    DefaultContexts convertContext = convertContext(context);
-                    if (commands.contains("downlink")) {
-                        if (context.dl().lifetime() >= 0L) {
-                            tasks.add(Executors.callable(() -> {
-                                dpnCommunicationService.modify_bearer(
-                                        topic_id,
-                                        s1u_sgw_ipv4,
-                                        s1u_enb_gtpu_teid,
-                                        s1u_enodeb_ipv4,
-                                        contextId,
-                                        cId,
-                                        opId
-                                );
-
-                                ModelObjectId modelObjectId = defaultTenantBuilder()
-                                        .addChild(DefaultFpcMobility.class)
-                                        .build();
-                                updateNode(convertContext, modelObjectId);
-//                                cacheManager.contextsCache.invalidate(context.contextId());
-                                cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
-                            }));
-                        } else {
-                            // TODO delete bearer
-                        }
-                    }
-                    if (commands.contains("uplink")) {
-                        if (context.ul().lifetime() >= 0L) {
-                            tasks.add(Executors.callable(() -> {
-                                dpnCommunicationService.modify_bearer(
-                                        topic_id,
-                                        s1u_sgw_ipv4,
-                                        s1u_enb_gtpu_teid,
-                                        s1u_enodeb_ipv4,
-                                        contextId,
-                                        cId,
-                                        opId
-                                );
-
-                                ModelObjectId modelObjectId = defaultTenantBuilder()
-                                        .addChild(DefaultFpcMobility.class)
-                                        .build();
-                                updateNode(convertContext, modelObjectId);
-//                                cacheManager.contextsCache.invalidate(context.contextId());
-                                cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
-                            }));
-                        } else {
-                            // TODO delete bearer
-                        }
-                    }
-
-
-                }
-
+            // check if contexts are populated and if they include the wanted context to update.
+            if (!CacheManager.getInstance(clientInfo.tenantId()).contextsCache.get(context.contextId()).isPresent()) {
+                // throw exception if wanted context does not exist.
+                throw new RuntimeException("Context doesn't exist. Please issue create operation..");
             }
 
-            // execute all tasks.
-            ExecutorService executor = Executors.newWorkStealingPool();
-            executor.invokeAll(tasks).forEach(
-                    future -> {
-                        try {
-                            future.get();
-                        } catch (Exception e) {
-                            log.error(ExceptionUtils.getFullStackTrace(e));
-                            throw new IllegalStateException(e);
-                        }
-                    }
-            );
-
-            configureOutput.resultType(defaultCommonSuccess);
-            configureOutput.result(Result.of(ResultEnum.OK));
-        } catch (Exception e) {
-            // if there is an exception respond with an error.
-            log.error(ExceptionUtils.getFullStackTrace(e));
-            DefaultErr defaultErr = new DefaultErr();
-            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
-            defaultErr.errorTypeId(ErrorTypeId.of(0));
-            configureOutput.resultType(defaultErr);
-            configureOutput.result(Result.of(ResultEnum.ERR));
+            for (Dpns dpn : context.dpns()) {
+                update(dpn, context, clientInfo, operationId);
+            }
         }
 
+        // execute all tasks.
+        ExecutorService executor = Executors.newWorkStealingPool();
+        executor.invokeAll(tasks).forEach(
+                future -> {
+                    try {
+                        future.get();
+                    } catch (Exception e) {
+                        log.error(ExceptionUtils.getFullStackTrace(e));
+                        throw new RuntimeException(e);
+                    }
+                }
+        );
+
+        configureOutput.resultType(defaultCommonSuccess);
+        configureOutput.result(Result.of(ResultEnum.OK));
         return configureOutput;
     }
 
+    private Collection<Callable<Object>> delete(
+            Dpns dpn,
+            DefaultContexts context,
+            DefaultRegisterClientInput clientId,
+            OpIdentifier operationId,
+            String target
+    ) throws Exception {
+        Collection<Callable<Object>> tasks = new ArrayList<>();
+        CacheManager cacheManager = CacheManager.getInstance(clientId.tenantId());
+        // check if dpns exists and if there is a DPN registered for the wanted identifier.
+        if (!cacheManager.dpnsCache.get(dpn.dpnId()).isPresent()) {
+            // throw exception if DPN ID is not registered.
+            throw new RuntimeException("DPN ID is not registered to the topology.");
+        }
+
+        // from DPN ID find the Network and Node Identifiers
+        Optional<String> key = cacheManager.dpnsCache.get(dpn.dpnId())
+                .map(node -> node.nodeId() + "/" + node.networkId());
+        if (!key.isPresent()) {
+            throw new RuntimeException("DPN does not have node and network ID defined.");
+        }
+
+        // find DPN Topic from Node/Network ID pair.
+        Short topic_id = getTopicFromNode(key.get());
+        if (topic_id == null) {
+            throw new RuntimeException("Could not find Topic ID");
+        }
+
+        if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+            throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+        }
+
+        Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters().mobprofileParameters()).tunnelIdentifier();
+        long client_id = clientId.clientId().fpcIdentity().union().int64();
+        BigInteger op_id = operationId.uint64();
+
+        // TODO figure out what is going on.
+        if (target.endsWith("ul") || target.endsWith("dl")) {
+            // TODO delete bearer
+        } else {
+            tasks.add(Executors.callable(() -> {
+                dpnCommunicationService.delete_session(
+                        topic_id,
+                        context.contextId().fpcIdentity().union().int64(),
+                        client_id,
+                        op_id
+                );
+
+                ContextsKeys contextsKeys = new ContextsKeys();
+                contextsKeys.contextId(context.contextId());
+
+                ResourceId resourceVal = getResourceVal(defaultTenantBuilder()
+                        .addChild(DefaultFpcMobility.class)
+                        .addChild(DefaultContexts.class, contextsKeys)
+                        .build());
+
+                dynamicConfigService.deleteNode(resourceVal);
+                cacheManager.contextsCache.put(context.contextId(), Optional.empty());
+            }));
+        }
+        return tasks;
+    }
+
     @Override
     public DefaultConfigureOutput configureDelete(
             DeleteOrQuery delete,
-            ClientIdentifier clientId,
+            DefaultRegisterClientInput clientInfo,
             OpIdentifier operationId
-    ) {
+    ) throws Exception {
         DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
         Collection<Callable<Object>> tasks = new ArrayList<>();
-        try {
-            DefaultDeleteSuccess defaultDeleteSuccess = new DefaultDeleteSuccess();
-            for (Targets target : delete.targets()) {
-                defaultDeleteSuccess.addToTargets(target);
-                // parse context id.
-                String targetStr = target.target().toString(),
-                        s = StringUtils.substringBetween(targetStr, "contexts=", "/"),
-                        trgt = s != null ? s : StringUtils.substringAfter(targetStr, "contexts=");
 
-                // find context that this target is about.
-                FpcContextId fpcContextId = FpcContextId.of(FpcIdentity.fromString(trgt));
-                Optional<DefaultContexts> defaultContexts = cacheManager.contextsCache.get(fpcContextId);
-                if (!defaultContexts.isPresent()) {
-                    throw new IllegalStateException("Context doesn't exist. Please issue create operation..");
-                }
+        DefaultDeleteSuccess defaultDeleteSuccess = new DefaultDeleteSuccess();
+        for (Targets target : delete.targets()) {
+            defaultDeleteSuccess.addToTargets(target);
+            // parse context id.
+            String targetStr = target.target().toString(),
+                    s = StringUtils.substringBetween(targetStr, "contexts=", "/"),
+                    trgt = s != null ? s : StringUtils.substringAfter(targetStr, "contexts=");
 
-                DefaultContexts context = defaultContexts.get();
-                for (Dpns dpn : context.dpns()) {
-                    // check if dpns exists and if there is a DPN registered for the wanted identifier.
-                    if (!cacheManager.dpnsCache.get(dpn.dpnId()).isPresent()) {
-                        // throw exception if DPN ID is not registered.
-                        throw new IllegalStateException("DPN ID is not registered to the topology.");
-                    }
-
-                    // from DPN ID find the Network and Node Identifiers
-                    Optional<String> key = cacheManager.dpnsCache.get(dpn.dpnId())
-                            .map(node -> node.nodeId() + "/" + node.networkId());
-                    if (!key.isPresent()) {
-                        throw new IllegalArgumentException("DPN does not have node and network ID defined.");
-                    }
-
-                    // find DPN Topic from Node/Network ID pair.
-                    Short topic_id = getTopicFromNode(key.get());
-                    if (topic_id == null) {
-                        throw new IllegalArgumentException("Could not find Topic ID");
-                    }
-
-                    if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
-                        throw new IllegalArgumentException("mobprofileParameters are not instance of ThreegppTunnel");
-                    }
-
-                    Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters().mobprofileParameters()).tunnelIdentifier();
-                    long client_id = clientId.fpcIdentity().union().int64();
-                    BigInteger op_id = operationId.uint64();
-
-                    // TODO figure out what is going on.
-                    if (targetStr.endsWith("ul") || targetStr.endsWith("dl")) {
-//                                                tasks.add(Executors.callable(() -> {
-//                                                    dpnCommunicationService.delete_bearer(
-//                                                            topic_id,
-//                                                            teid
-//                                                    );
-//
-//                                                    context.dl(null);
-//                                                    context.ul(null);
-//                                                }));
-                    } else {
-                        tasks.add(Executors.callable(() -> {
-                            dpnCommunicationService.delete_session(
-                                    topic_id,
-                                    context.contextId().fpcIdentity().union().int64(),
-                                    client_id,
-                                    op_id
-                            );
-
-                            ContextsKeys contextsKeys = new ContextsKeys();
-                            contextsKeys.contextId(context.contextId());
-
-                            ResourceId resourceVal = getResourceVal(defaultTenantBuilder()
-                                    .addChild(DefaultFpcMobility.class)
-                                    .addChild(DefaultContexts.class, contextsKeys)
-                                    .build());
-                            dynamicConfigService.deleteNode(resourceVal);
-                            cacheManager.contextsCache.invalidate(context.contextId());
-                        }));
-                    }
-                }
+            // find context that this target is about.
+            FpcContextId fpcContextId = FpcContextId.of(FpcIdentity.fromString(trgt));
+            Optional<DefaultContexts> defaultContexts = CacheManager.getInstance(clientInfo.tenantId()).contextsCache.get(fpcContextId);
+            if (!defaultContexts.isPresent()) {
+                throw new RuntimeException("Context doesn't exist. Please issue create operation..");
             }
 
-
-            // execute all tasks
-            ExecutorService executor = Executors.newWorkStealingPool();
-            executor.invokeAll(tasks).forEach(
-                    future -> {
-                        try {
-                            future.get();
-                        } catch (Exception e) {
-                            log.error(ExceptionUtils.getFullStackTrace(e));
-                            throw new IllegalStateException(e);
-                        }
-                    }
-            );
-
-            configureOutput.resultType(defaultDeleteSuccess);
-            configureOutput.result(Result.of(ResultEnum.OK));
-        } catch (Exception e) {
-            // if there is an exception respond with an error.
-            log.error(ExceptionUtils.getFullStackTrace(e));
-            DefaultErr defaultErr = new DefaultErr();
-            configureOutput.resultType(defaultErr);
-            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
-            defaultErr.errorTypeId(ErrorTypeId.of(0));
+            DefaultContexts context = defaultContexts.get();
+            for (Dpns dpn : context.dpns()) {
+                tasks = delete(dpn, context, clientInfo, operationId, targetStr);
+            }
         }
 
+        // execute all tasks
+        ExecutorService executor = Executors.newWorkStealingPool();
+        executor.invokeAll(tasks).forEach(
+                future -> {
+                    try {
+                        future.get();
+                    } catch (Exception e) {
+                        log.error(ExceptionUtils.getFullStackTrace(e));
+                        throw new RuntimeException(e);
+                    }
+                }
+        );
+
+        configureOutput.resultType(defaultDeleteSuccess);
+        configureOutput.result(Result.of(ResultEnum.OK));
+
         return configureOutput;
     }
 
-    /**
-     * Extract Resource Data from specified DataNode and Resource Id.
-     *
-     * @param dataNode DataNode
-     * @param resId    Resource Identifier
-     * @return Resource Data
-     */
-    private ResourceData getResourceData(DataNode dataNode, ResourceId resId) {
-        if (resId != null) {
-            return DefaultResourceData.builder()
-                    .addDataNode(dataNode)
-                    .resourceId(resId)
-                    .build();
-        } else {
-            return DefaultResourceData.builder()
-                    .addDataNode(dataNode)
-                    .build();
+    @Override
+    public DefaultConfigureDpnOutput configureDpnAdd(DefaultConfigureDpnInput input) throws Exception {
+        DefaultConfigureDpnOutput defaultConfigureDpnOutput = new DefaultConfigureDpnOutput();
+        boolean done = false;
+
+        final FpcDpnId fpcDpnId = input.inputDpnId(),
+                abstractDpnId = input.abstractDpnId();
+        if (fpcDpnId == null || abstractDpnId == null) {
+            throw new RuntimeException("DPN and Abstract DPN must be provided.");
         }
+
+        for (CacheManager cacheManager : CacheManager.cacheInfo.values()) {
+            final Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(fpcDpnId),
+                    optionalvDpn = cacheManager.dpnsCache.get(abstractDpnId);
+
+            if (!optionalDpn.isPresent() || !optionalvDpn.isPresent()) {
+                continue;
+            }
+
+            if (optionalDpn.map(DefaultDpns::yangAutoPrefixAbstract).orElse(false) ||
+                    !optionalvDpn.map(DefaultDpns::yangAutoPrefixAbstract).orElse(false)) {
+                continue;
+            }
+
+            final DefaultDpns dpn = optionalDpn.get(),
+                    vdpn = optionalvDpn.get();
+
+            if (vdpn.dpnIds() == null) {
+                vdpn.dpnIds(new ArrayList<>());
+            }
+
+            if (!vdpn.dpnIds().contains(dpn.dpnId())) {
+                // TODO copy contexts
+                vdpn.addToDpnIds(dpn.dpnId());
+                done = true;
+            }
+        }
+
+        if (!done) {
+            throw new RuntimeException("Could not process");
+        }
+
+        defaultConfigureDpnOutput.resultType(new DefaultEmptyCase());
+        defaultConfigureDpnOutput.result(Result.of(ResultEnum.OK));
+
+        return defaultConfigureDpnOutput;
+    }
+
+    @Override
+    public DefaultConfigureDpnOutput configureDpnRemove(DefaultConfigureDpnInput input) throws Exception {
+        DefaultConfigureDpnOutput defaultConfigureDpnOutput = new DefaultConfigureDpnOutput();
+        boolean done = false;
+
+        final FpcDpnId fpcDpnId = input.inputDpnId(),
+                abstractDpnId = input.abstractDpnId();
+        if (fpcDpnId == null || abstractDpnId == null) {
+            throw new RuntimeException("DPN and Abstract DPN must be provided.");
+        }
+
+        for (CacheManager cacheManager : CacheManager.cacheInfo.values()) {
+            final Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(fpcDpnId),
+                    optionalvDpn = cacheManager.dpnsCache.get(abstractDpnId);
+            if (!optionalDpn.isPresent() || !optionalvDpn.isPresent()) {
+                throw new RuntimeException("DPN or Abstract DPN specified does not exists.");
+            }
+
+            if (optionalDpn.map(DefaultDpns::yangAutoPrefixAbstract).orElse(false) ||
+                    !optionalvDpn.map(DefaultDpns::yangAutoPrefixAbstract).orElse(false)) {
+                throw new RuntimeException("Requested DPN is Abstract or requested Abstract DPN is not abstract.");
+            }
+
+            final DefaultDpns dpn = optionalDpn.get(),
+                    vdpn = optionalvDpn.get();
+
+            if (vdpn.dpnIds() == null || !vdpn.dpnIds().contains(dpn.dpnId())) {
+                throw new RuntimeException("DPN is not part of the vDPN");
+            }
+
+            vdpn.dpnIds().remove(dpn.dpnId());
+            // TODO remove contexts
+            done = true;
+        }
+
+        if (!done) {
+            throw new RuntimeException("Could not process");
+        }
+
+        DefaultCommonDeleteSuccess defaultCommonDeleteSuccess = new DefaultCommonDeleteSuccess();
+        defaultConfigureDpnOutput.resultType(defaultCommonDeleteSuccess);
+        defaultConfigureDpnOutput.result(Result.of(ResultEnum.OK));
+
+        return defaultConfigureDpnOutput;
     }
 
     /**
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantService.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantService.java
index 5b4ea1a..af62447 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantService.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantService.java
@@ -1,10 +1,13 @@
 package org.onosproject.fpcagent;
 
 import com.google.common.annotations.Beta;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.registerclient.DefaultRegisterClientInput;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.ClientIdentifier;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.DefaultTenants;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.OpIdentifier;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configure.DefaultConfigureOutput;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configuredpn.DefaultConfigureDpnInput;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.configuredpn.DefaultConfigureDpnOutput;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.opinput.opbody.CreateOrUpdate;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.opinput.opbody.DeleteOrQuery;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.DefaultTenant;
@@ -59,49 +62,49 @@
 
     Optional<DefaultTenant> getTenant(ClientIdentifier clientId);
 
-    Optional<DefaultTenant> registerClient(ClientIdentifier clientId, FpcIdentity tenantId);
-
-    Optional<DefaultTenant> deregisterClient(ClientIdentifier clientId);
-
     /**
      * Handles create configure operations that are invoked through RPC.
      *
      * @param create      RPC Input converted
-     * @param clientId    Client Identifier
+     * @param clientInfo    Client Identifier
      * @param operationId Operation Identifier
      * @return Result of the configuration
      */
     DefaultConfigureOutput configureCreate(
             CreateOrUpdate create,
-            ClientIdentifier clientId,
+            DefaultRegisterClientInput clientInfo,
             OpIdentifier operationId
-    );
+    ) throws Exception;
 
     /**
      * Handles update configure operations that are invoked through RPC.
      *
      * @param update      RPC Input converted
-     * @param clientId    Client Identifier
+     * @param clientInfo    Client Identifier
      * @param operationId Operation Identifier
      * @return Result of the configuration
      */
     DefaultConfigureOutput configureUpdate(
             CreateOrUpdate update,
-            ClientIdentifier clientId,
+            DefaultRegisterClientInput clientInfo,
             OpIdentifier operationId
-    );
+    ) throws Exception;
 
     /**
      * Handles delete configure operations that are invoked through RPC.
      *
      * @param delete      RPC Input converted
-     * @param clientId    Client Identifier
+     * @param clientInfo    Client Identifier
      * @param operationId Operation Identifier
      * @return Result of the configuration
      */
     DefaultConfigureOutput configureDelete(
             DeleteOrQuery delete,
-            ClientIdentifier clientId,
+            DefaultRegisterClientInput clientInfo,
             OpIdentifier operationId
-    );
+    ) throws Exception;
+
+    DefaultConfigureDpnOutput configureDpnAdd(DefaultConfigureDpnInput input) throws Exception;
+
+    DefaultConfigureDpnOutput configureDpnRemove(DefaultConfigureDpnInput input) throws Exception;
 }
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/CacheManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/CacheManager.java
index c691bea..c7946cc 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/CacheManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/CacheManager.java
@@ -19,27 +19,34 @@
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Maps;
 import org.onosproject.fpcagent.TenantManager;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.DefaultTenant;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpcmobility.DefaultContexts;
 import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpctopology.DefaultDpns;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcContextId;
 import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcDpnId;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcIdentity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Optional;
+import java.util.concurrent.ConcurrentMap;
 
+/**
+ * Cache Manager.
+ */
 public class CacheManager {
 
-    public static CacheManager _instance;
+    // Cacher per different Tenant
+    public static ConcurrentMap<FpcIdentity, CacheManager> cacheInfo = Maps.newConcurrentMap();
     private final Logger log = LoggerFactory.getLogger(getClass());
     public LoadingCache<FpcContextId, Optional<DefaultContexts>> contextsCache;
     public LoadingCache<FpcDpnId, Optional<DefaultDpns>> dpnsCache;
 
-    private TenantManager tenantManager;
+    private static TenantManager tenantManager;
 
-    private CacheManager() {
+    private CacheManager(FpcIdentity identity) {
         contextsCache = CacheBuilder.newBuilder()
                 .maximumSize(100)
                 .build(
@@ -47,7 +54,7 @@
                             @Override
                             public Optional<DefaultContexts> load(FpcContextId fpcContextId) throws Exception {
                                 try {
-                                    Optional<DefaultTenant> defaultTenant = tenantManager.getDefaultTenant();
+                                    Optional<DefaultTenant> defaultTenant = tenantManager.getTenant(identity);
                                     if (defaultTenant.isPresent()) {
                                         DefaultTenant tenant = defaultTenant.get();
                                         log.debug("tenant {}", defaultTenant);
@@ -75,7 +82,7 @@
                             @Override
                             public Optional<DefaultDpns> load(FpcDpnId fpcDpnId) throws Exception {
                                 try {
-                                    Optional<DefaultTenant> defaultTenant = tenantManager.getDefaultTenant();
+                                    Optional<DefaultTenant> defaultTenant = tenantManager.getTenant(identity);
                                     if (defaultTenant.isPresent()) {
                                         DefaultTenant tenant = defaultTenant.get();
                                         log.debug("tenant {}", tenant);
@@ -97,15 +104,11 @@
                 );
     }
 
-    public static CacheManager getInstance() {
-        if (_instance == null) {
-            _instance = new CacheManager();
-        }
-
-        return _instance;
+    public static CacheManager getInstance(FpcIdentity identity) {
+        return cacheInfo.putIfAbsent(identity, new CacheManager(identity));
     }
 
-    public void addManager(TenantManager manager) {
-        this.tenantManager = manager;
+    public static void addManager(TenantManager manager) {
+        tenantManager = manager;
     }
 }
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
index 37f302a..94552ff 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
@@ -63,9 +63,9 @@
     public static ResourceId tenants;
     public static ResourceId defaultTenant;
     public static ResourceId configureBundles;
+    public static ResourceId registerClient;
+    public static ResourceId deregisterClinet;
     public static ResourceId module;
-    public static ResourceId registerClientResourceId;
-    public static ResourceId deregisterClientResourceId;
 
     public static final FpcIdentity defaultIdentity = getFpcIdentity.apply("default");
 
@@ -123,6 +123,51 @@
                 .addBranchPointSchema("/", null)
                 .addBranchPointSchema("configure-bundles", "urn:ietf:params:xml:ns:yang:fpcagent")
                 .build();
+
+        registerClient = ResourceId.builder()
+                .addBranchPointSchema("/", null)
+                .addBranchPointSchema("register-client", "urn:onos:params:xml:ns:yang:fpc")
+                .build();
+
+        deregisterClinet = ResourceId.builder()
+                .addBranchPointSchema("/", null)
+                .addBranchPointSchema("deregister-client", "urn:onos:params:xml:ns:yang:fpc")
+                .build();
+    }
+
+    /**
+     * Extract Resource Data from specified DataNode and Resource Id.
+     *
+     * @param dataNode DataNode
+     * @param resId    Resource Identifier
+     * @return Resource Data
+     */
+    public static ResourceData getResourceData(DataNode dataNode, ResourceId resId) {
+        if (resId != null) {
+            return DefaultResourceData.builder()
+                    .addDataNode(dataNode)
+                    .resourceId(resId)
+                    .build();
+        } else {
+            return DefaultResourceData.builder()
+                    .addDataNode(dataNode)
+                    .build();
+        }
+    }
+
+    /**
+     * Returns the resource ID of the parent data node pointed by {@code path}.
+     *
+     * @param path resource ID of the given data node
+     * @return resource ID of the parent data node
+     */
+    public static ResourceId parentOf(ResourceId path) throws Exception {
+        try {
+            return path.copyBuilder().removeLastKey().build();
+        } catch (CloneNotSupportedException e) {
+            log.error("Could not copy {}", path, e);
+            throw new RuntimeException("Could not copy " + path, e);
+        }
     }
 
     public static ModelObjectId.Builder defaultTenantBuilder() {
@@ -151,26 +196,6 @@
     }
 
     /**
-     * Returns the resource data from the data node and the resource id.
-     *
-     * @param dataNode data node
-     * @param resId    resource id
-     * @return resource data
-     */
-    static ResourceData getResourceData(DataNode dataNode, ResourceId resId) {
-        if (resId != null) {
-            return DefaultResourceData.builder()
-                    .addDataNode(dataNode)
-                    .resourceId(resId)
-                    .build();
-        } else {
-            return DefaultResourceData.builder()
-                    .addDataNode(dataNode)
-                    .build();
-        }
-    }
-
-    /**
      * Ensures the session id is an unsigned 64 bit integer
      *
      * @param sessionId - session id received from the DPN
diff --git a/models/fpcagent/src/main/yang/fpc.yang b/models/fpcagent/src/main/yang/fpc.yang
index 2996283..c3c67b3 100644
--- a/models/fpcagent/src/main/yang/fpc.yang
+++ b/models/fpcagent/src/main/yang/fpc.yang
@@ -161,9 +161,9 @@
         }
       }
       output {
-      	leaf client-id {
+        leaf client-id {
           type fpcagent:client-identifier;
         }
       }
     }
-}
+}
\ No newline at end of file
diff --git a/models/fpcagent/src/main/yang/ietf-pmip-qos.yang b/models/fpcagent/src/main/yang/ietf-pmip-qos.yang
index 4a22355..90ecf3c 100644
--- a/models/fpcagent/src/main/yang/ietf-pmip-qos.yang
+++ b/models/fpcagent/src/main/yang/ietf-pmip-qos.yang
@@ -1,9 +1,7 @@
 module ietf-pmip-qos {
     yang-version 1;
 
-    namespace
-      "urn:ietf:params:xml:ns:yang:ietf-pmip-qos";
-
+    namespace "urn:ietf:params:xml:ns:yang:ietf-pmip-qos";
     prefix "qos-pmip";
 
     import ietf-inet-types {
diff --git a/models/fpcagent/src/main/yang/ietf-traffic-selector-types.yang b/models/fpcagent/src/main/yang/ietf-traffic-selector-types.yang
index 029f3ec..5cf6498 100644
--- a/models/fpcagent/src/main/yang/ietf-traffic-selector-types.yang
+++ b/models/fpcagent/src/main/yang/ietf-traffic-selector-types.yang
@@ -1,9 +1,7 @@
 module ietf-traffic-selector-types {
     yang-version 1;
 
-    namespace
-      "urn:ietf:params:xml:ns:yang:ietf-traffic-selector-types";
-
+    namespace "urn:ietf:params:xml:ns:yang:ietf-traffic-selector-types";
     prefix "ietf-traffic-selectors";
 
     import ietf-inet-types {
diff --git a/scripts/addDPN.sh b/scripts/addDPN.sh
index b1d04d2..f108595 100755
--- a/scripts/addDPN.sh
+++ b/scripts/addDPN.sh
@@ -17,6 +17,23 @@
     }' 'http://localhost:8181/onos/restconf/data/ietf-dmm-fpcagent:tenants/tenant=default/fpc-topology'
     ./getTenants.sh
     echo ""
+elif [ "$#" -eq 2 ]; then
+    echo ""
+    curl -i --header "Content-type: application/json" --request POST -u onos:rocks --data '{
+        "dpns": [
+            {
+                "dpn-id": '$1',
+                "dpn-name": "site1-anchor1",
+                "dpn-groups": [
+                    "foo"
+                ],
+                "node-id": "node'$1'",
+                "network-id": "network'$1'"
+            }
+        ]
+    }' 'http://localhost:8181/onos/restconf/data/ietf-dmm-fpcagent:tenants/tenant='$2'/fpc-topology'
+    ./getTenants.sh
+    echo ""
 else
-    echo "usage: "$0" dpnId"
-fi
\ No newline at end of file
+    echo "usage: "$0" dpnId (tenantId)"
+fi
diff --git a/scripts/addTenant.sh b/scripts/addTenant.sh
new file mode 100755
index 0000000..ecc4f18
--- /dev/null
+++ b/scripts/addTenant.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+if [ "$#" -eq 1 ]; then
+    echo ""
+    curl -i --header "Content-type: application/json" --request POST -u onos:rocks --data '{
+        "tenants": [
+            {
+                "fpc-mobility": {},
+                "fpc-policy": {},
+                "fpc-topology": {},
+                "tenant-id": "'$1'"
+            }
+        ]
+    }' 'http://localhost:8181/onos/restconf/data/ietf-dmm-fpcagent'
+    echo ""
+else
+    echo "usage: "$0" tenantId"
+fi
diff --git a/scripts/benchmark.sh b/scripts/benchmark.sh
index 1d3a6ac..08e90c5 100755
--- a/scripts/benchmark.sh
+++ b/scripts/benchmark.sh
@@ -2,10 +2,11 @@
 
 rm -rf create.log delete.log
 
+./registerClient.sh 1 default &> /dev/null
 ./addDPN.sh 1 &> /dev/null 
 
 for (( i=1; i<=100; i++)); do
-	./configure.sh create $i 1 >> create.log 2> /dev/null &
+	./configure.sh create $i 1 &> /dev/null &
 	if ! (($i % 10)); then
 		wait
 	fi
@@ -14,10 +15,11 @@
 wait
 
 for (( i=1; i<=100; i++)); do
-	./configure.sh delete $i >> delete.log 2> /dev/null &
+	./configure.sh delete $i &> /dev/null &
 	if ! (($i % 10)); then
 		wait
 	fi
 done
 
-./deleteDPN.sh 1 &> /dev/null 
+./deleteDPN.sh 1 &> /dev/null
+./deregisterClient.sh 1 &> /dev/null
diff --git a/scripts/configure.sh b/scripts/configure.sh
index a77d853..b5a351a 100755
--- a/scripts/configure.sh
+++ b/scripts/configure.sh
@@ -85,5 +85,5 @@
         'http://localhost:8181/onos/restconf/operations/ietf-dmm-fpcagent:configure' | python -m json.tool
     echo ""
 else
-    echo "usage: "$0" type contextId"
+    echo "usage: "$0" type (create/delete) contextId (dpnId)"
 fi
\ No newline at end of file
diff --git a/scripts/deleteDPN.sh b/scripts/deleteDPN.sh
index 6633e47..41b7c7f 100755
--- a/scripts/deleteDPN.sh
+++ b/scripts/deleteDPN.sh
@@ -3,6 +3,10 @@
     echo ""
 	curl -X DELETE -u onos:rocks 'http://localhost:8181/onos/restconf/data/ietf-dmm-fpcagent:tenants/tenant=default/fpc-topology/dpns='$1
 	./getTenants.sh
+elif [ "$#" -eq 2 ]; then
+    echo ""
+	curl -X DELETE -u onos:rocks 'http://localhost:8181/onos/restconf/data/ietf-dmm-fpcagent:tenants/tenant='$2'/fpc-topology/dpns='$1
+	./getTenants.sh
 else
-    echo "usage: "$0" dpnId"
+    echo "usage: "$0" dpnId (tenantId)"
 fi
\ No newline at end of file
diff --git a/scripts/deregisterClient.sh b/scripts/deregisterClient.sh
new file mode 100755
index 0000000..a8ba7ce
--- /dev/null
+++ b/scripts/deregisterClient.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+if [ "$#" -eq 1 ]; then
+    echo ""
+    curl -i -s \
+    --header "Content-type: application/json" \
+    --request POST \
+    -u onos:rocks \
+    --data '{
+        "input": {
+            "client-id": "'$1'"
+        }
+    }' 'http://localhost:8181/onos/restconf/operations/fpc:deregister-client'
+    echo ""
+else
+    echo "usage: "$0" clientId"
+fi
diff --git a/scripts/getClients.sh b/scripts/getClients.sh
new file mode 100755
index 0000000..214803e
--- /dev/null
+++ b/scripts/getClients.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+curl -u onos:rocks http://localhost:8181/onos/restconf/data/fpc:connection-info | python -m json.tool
diff --git a/scripts/registerClient.sh b/scripts/registerClient.sh
new file mode 100755
index 0000000..36d108a
--- /dev/null
+++ b/scripts/registerClient.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+if [ "$#" -eq 2 ]; then
+    echo ""
+    curl -i -s \
+    --header "Content-type: application/json" \
+    --request POST \
+    -u onos:rocks \
+    --data '{
+        "input": {
+            "client-id": "'$1'",
+            "tenant-id": "'$2'",
+            "supported-features": [
+                "urn:ietf:params:xml:ns:yang:fpcagent:fpc-bundles",
+                "urn:ietf:params:xml:ns:yang:fpcagent:operation-ref-scope",
+                "urn:ietf:params:xml:ns:yang:fpcagent:fpc-agent-assignments",
+                "urn:ietf:params:xml:ns:yang:fpcagent:instruction-bitset"
+            ],
+    	"endpoint-uri": "http://127.0.0.1:9997/"
+        }
+    }' 'http://localhost:8181/onos/restconf/operations/fpc:register-client'
+    echo ""
+else
+    echo "usage: "$0" clientId tenantId"
+fi