fixed cache
diff --git a/.gitignore b/.gitignore
index bff2d76..22535db 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.iml
+*.log
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 7c15f01..430fb09 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcManager.java
@@ -22,6 +22,7 @@
 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;
@@ -184,6 +185,10 @@
                 DefaultModelObjectData.builder().addModelObject(output).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));
     }
 
@@ -224,7 +229,7 @@
         } catch (Exception e) {
             // if there is an exception respond with an error.
             DefaultErr defaultErr = new DefaultErr();
-            defaultErr.errorInfo(ExceptionUtils.getMessage(e));
+            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
             defaultErr.errorTypeId(ErrorTypeId.of(0));
             configureOutput.resultType(defaultErr);
             configureOutput.result(Result.of(ResultEnum.ERR));
@@ -236,6 +241,10 @@
                         .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));
     }
 
@@ -292,6 +301,10 @@
                         .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));
     }
 
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 9fb67ff..8862ffc 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/TenantManager.java
@@ -148,6 +148,16 @@
                 .findFirst();
     }
 
+    public Optional<DefaultTenant> getDefaultTenant() {
+        Filter filter = Filter.builder().build();
+        DataNode dataNode = dynamicConfigService.readNode(defaultTenant, filter);
+
+        return getModelObjects(dataNode, tenants)
+                .stream()
+                .map(modelObject -> (DefaultTenant) modelObject)
+                .findFirst();
+    }
+
     @Override
     public Optional<DefaultTenant> getTenant(ClientIdentifier clientId) {
         return Optional.ofNullable(clientIdMap.get(clientId));
@@ -289,7 +299,8 @@
                                     .addChild(DefaultFpcMobility.class)
                                     .build();
                             createNode(convertContext, modelObjectId);
-                            cacheManager.contextsCache.invalidate(context.contextId());
+//                            cacheManager.contextsCache.invalidate(context.contextId());
+                            cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
                         }));
 
                         if (commands.contains("downlink")) {
@@ -308,28 +319,15 @@
                                         .addChild(DefaultFpcMobility.class)
                                         .build();
                                 createNode(convertContext, modelObjectId);
-                                cacheManager.contextsCache.invalidate(context.contextId());
+//                                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")) {
-//                                    tasks.add(Executors.callable(() -> {
-//                                        dpnCommunicationService.create_bearer_ul(
-//                                                topic_id,
-//                                                imsi,
-//                                                lbi,
-//                                                default_ebi,
-//                                                ulLocalAddress,
-//                                                s1u_sgw_gtpu_teid
-//                                        );
-//
-//                                        getDefaultTenant().ifPresent(
-//                                                tenant -> tenant.fpcMobility().addToContexts(convertContext(context))
-//                                        );
-//                                    }));
+                        // TODO create bearer ul
                     }
-
                 }
             }
 
@@ -353,7 +351,7 @@
             log.error(ExceptionUtils.getFullStackTrace(e));
             DefaultErr defaultErr = new DefaultErr();
             configureOutput.resultType(defaultErr);
-            defaultErr.errorInfo(ExceptionUtils.getMessage(e));
+            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
             defaultErr.errorTypeId(ErrorTypeId.of(0));
         }
         return configureOutput;
@@ -438,15 +436,11 @@
                                         .addChild(DefaultFpcMobility.class)
                                         .build();
                                 updateNode(convertContext, modelObjectId);
-                                cacheManager.contextsCache.invalidate(context.contextId());
+//                                cacheManager.contextsCache.invalidate(context.contextId());
+                                cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
                             }));
                         } else {
-//                                        tasks.add(Executors.callable(() ->
-//                                                dpnCommunicationService.delete_bearer(
-//                                                        topic_id,
-//                                                        s1u_enb_gtpu_teid
-//                                                )
-//                                        ));
+                            // TODO delete bearer
                         }
                     }
                     if (commands.contains("uplink")) {
@@ -466,15 +460,11 @@
                                         .addChild(DefaultFpcMobility.class)
                                         .build();
                                 updateNode(convertContext, modelObjectId);
-                                cacheManager.contextsCache.invalidate(context.contextId());
+//                                cacheManager.contextsCache.invalidate(context.contextId());
+                                cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
                             }));
                         } else {
-//                                        tasks.add(Executors.callable(() ->
-//                                                dpnCommunicationService.delete_bearer(
-//                                                        topic_id,
-//                                                        s1u_sgw_gtpu_teid
-//                                                )
-//                                        ));
+                            // TODO delete bearer
                         }
                     }
 
@@ -502,7 +492,7 @@
             // if there is an exception respond with an error.
             log.error(ExceptionUtils.getFullStackTrace(e));
             DefaultErr defaultErr = new DefaultErr();
-            defaultErr.errorInfo(ExceptionUtils.getMessage(e));
+            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
             defaultErr.errorTypeId(ErrorTypeId.of(0));
             configureOutput.resultType(defaultErr);
             configureOutput.result(Result.of(ResultEnum.ERR));
@@ -592,6 +582,7 @@
                                     .addChild(DefaultContexts.class, contextsKeys)
                                     .build());
                             dynamicConfigService.deleteNode(resourceVal);
+                            cacheManager.contextsCache.invalidate(context.contextId());
                         }));
                     }
                 }
@@ -618,7 +609,7 @@
             log.error(ExceptionUtils.getFullStackTrace(e));
             DefaultErr defaultErr = new DefaultErr();
             configureOutput.resultType(defaultErr);
-            defaultErr.errorInfo(ExceptionUtils.getMessage(e));
+            defaultErr.errorInfo(ExceptionUtils.getFullStackTrace(e));
             defaultErr.errorTypeId(ErrorTypeId.of(0));
         }
 
@@ -671,7 +662,15 @@
 //                                Filter filter = Filter.builder().build();
 //                                DataNode node = dynamicConfigService.readNode(FpcUtil.tenants, filter);
 //                                getModelObjects(node, null).forEach(
-//                                        modelObject -> fpcAgentData.tenants((DefaultTenants) modelObject)
+//                                        modelObject -> {
+//                                            DefaultTenants tenants = (DefaultTenants) modelObject;
+//                                            tenants.tenant()
+//                                                    .parallelStream()
+//                                                    .forEach(tenant -> cacheManager.tenantCache.put(
+//                                                            tenant.tenantId(),
+//                                                            Optional.of((DefaultTenant) tenant))
+//                                                    );
+//                                        }
 //                                );
                                 break;
                             default:
@@ -696,10 +695,6 @@
          * @return true if event is supported; false otherwise
          */
         private boolean isSupported(DynamicConfigEvent event) {
-//            ResourceId rsId = event.subject();
-//            List<NodeKey> storeKeys = rsId.nodeKeys();
-//            List<NodeKey> tenantKeys = FpcUtil.tenants.nodeKeys();
-//            return storeKeys.size() >= 2 && storeKeys.get(0).equals(tenantKeys.get(1));
             return true;
         }
 
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
new file mode 100644
index 0000000..6b9c86a
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/CacheManager.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.fpcagent.util;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+public class CacheManager {
+
+    public static CacheManager _instance;
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    public LoadingCache<FpcContextId, Optional<DefaultContexts>> contextsCache;
+    public LoadingCache<FpcDpnId, Optional<DefaultDpns>> dpnsCache;
+
+    private TenantManager tenantManager;
+
+    private CacheManager() {
+        contextsCache = CacheBuilder.newBuilder()
+                .maximumSize(100)
+                .build(
+                        new CacheLoader<FpcContextId, Optional<DefaultContexts>>() {
+                            @Override
+                            public Optional<DefaultContexts> load(FpcContextId fpcContextId) throws Exception {
+                                try {
+                                    Optional<DefaultTenant> defaultTenant = tenantManager.getDefaultTenant();
+                                    if (defaultTenant.isPresent()) {
+                                        DefaultTenant tenant = defaultTenant.get();
+                                        log.debug("tenant {}", defaultTenant);
+                                        if (tenant.fpcMobility().contexts() != null) {
+                                            return tenant.fpcMobility().contexts().stream()
+                                                    .filter(contexts -> contexts.contextId().equals(fpcContextId))
+                                                    .findFirst()
+                                                    .map(c -> (DefaultContexts) c);
+                                        }
+                                    }
+                                } catch (Exception e) {
+                                    Thread.sleep(1000);
+                                    return load(fpcContextId);
+                                }
+                                return Optional.empty();
+                            }
+                        }
+                );
+
+        dpnsCache = CacheBuilder.newBuilder()
+                .maximumSize(100)
+                .build(
+                        new CacheLoader<FpcDpnId, Optional<DefaultDpns>>() {
+                            @Override
+                            public Optional<DefaultDpns> load(FpcDpnId fpcDpnId) throws Exception {
+                                try {
+                                    Optional<DefaultTenant> defaultTenant = tenantManager.getDefaultTenant();
+                                    if (defaultTenant.isPresent()) {
+                                        DefaultTenant tenant = defaultTenant.get();
+                                        log.debug("tenant {}", tenant);
+                                        if (tenant.fpcTopology().dpns() != null) {
+                                            return tenant.fpcTopology().dpns().stream()
+                                                    .filter(dpns -> dpns.dpnId().equals(fpcDpnId))
+                                                    .findFirst()
+                                                    .map(d -> (DefaultDpns) d);
+                                        }
+                                    }
+                                } catch (Exception e) {
+                                    Thread.sleep(1000);
+                                    return load(fpcDpnId);
+                                }
+                                return Optional.empty();
+                            }
+                        }
+                );
+    }
+
+    public static CacheManager getInstance() {
+        if (_instance == null) {
+            _instance = new CacheManager();
+        }
+
+        return _instance;
+    }
+
+    public void addManager(TenantManager manager) {
+        this.tenantManager = manager;
+    }
+
+
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/ConfigHelper.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/ConfigHelper.java
new file mode 100644
index 0000000..20868af
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/ConfigHelper.java
@@ -0,0 +1,315 @@
+package org.onosproject.fpcagent.util;
+
+import com.fasterxml.jackson.annotation.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "monitor-threads",
+        "scheduled-monitors-poolsize",
+        "dpn-subscriber-uri",
+        "dpn-listener-id",
+        "dpn-publisher-uri",
+        "dpn-client-threads",
+        "metricsupdate-ms",
+        "mobilityupdate-ms",
+        "activation-threads",
+        "target-read-limit",
+        "http-notifier-clients",
+        "zmq-nbi-server-poolsize",
+        "zmq-nbi-server-uri",
+        "zmq-nbi-inproc-uri",
+        "zmq-nbi-handler-poolsize",
+        "http-nio2-nb-poolsize",
+        "http-nio2-nb-port",
+        "node-id",
+        "network-id",
+        "zmq-broadcast-controllers",
+        "zmq-broadcast-dpns",
+        "zmq-broadcast-all"
+})
+public class ConfigHelper {
+    @JsonProperty("monitor-threads")
+    private Integer monitorThreads;
+    @JsonProperty("scheduled-monitors-poolsize")
+    private Integer scheduledMonitorsPoolsize;
+    @JsonProperty("dpn-subscriber-uri")
+    private String dpnSubscriberUri;
+    @JsonProperty("dpn-listener-id")
+    private Integer dpnListenerId;
+    @JsonProperty("dpn-publisher-uri")
+    private String dpnPublisherUri;
+    @JsonProperty("dpn-client-threads")
+    private Integer dpnClientThreads;
+    @JsonProperty("metricsupdate-ms")
+    private Integer metricsupdateMs;
+    @JsonProperty("mobilityupdate-ms")
+    private Integer mobilityupdateMs;
+    @JsonProperty("activation-threads")
+    private Integer activationThreads;
+    @JsonProperty("target-read-limit")
+    private Integer targetReadLimit;
+    @JsonProperty("http-notifier-clients")
+    private Integer httpNotifierClients;
+    @JsonProperty("zmq-nbi-server-poolsize")
+    private Integer zmqNbiServerPoolsize;
+    @JsonProperty("zmq-nbi-server-uri")
+    private String zmqNbiServerUri;
+    @JsonProperty("zmq-nbi-inproc-uri")
+    private String zmqNbiInprocUri;
+    @JsonProperty("zmq-nbi-handler-poolsize")
+    private Integer zmqNbiHandlerPoolsize;
+    @JsonProperty("http-nio2-nb-poolsize")
+    private Integer httpNio2NbPoolsize;
+    @JsonProperty("http-nio2-nb-port")
+    private Integer httpNio2NbPort;
+    @JsonProperty("node-id")
+    private String nodeId;
+    @JsonProperty("network-id")
+    private String networkId;
+    @JsonProperty("zmq-broadcast-controllers")
+    private String zmqBroadcastControllers;
+    @JsonProperty("zmq-broadcast-dpns")
+    private String zmqBroadcastDpns;
+    @JsonProperty("zmq-broadcast-all")
+    private String zmqBroadcastAll;
+    @JsonIgnore
+    private Map<String, Object> additionalProperties = new HashMap<>();
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public ConfigHelper() {
+    }
+
+
+    public Integer monitorThreads() {
+        return monitorThreads;
+    }
+
+
+    public void setMonitorThreads(Integer monitorThreads) {
+        this.monitorThreads = monitorThreads;
+    }
+
+
+    public Integer scheduledMonitorsPoolsize() {
+        return scheduledMonitorsPoolsize;
+    }
+
+
+    public void setScheduledMonitorsPoolsize(Integer scheduledMonitorsPoolsize) {
+        this.scheduledMonitorsPoolsize = scheduledMonitorsPoolsize;
+    }
+
+
+    public String dpnSubscriberUri() {
+        return dpnSubscriberUri;
+    }
+
+
+    public void setDpnSubscriberUri(String dpnSubscriberUri) {
+        this.dpnSubscriberUri = dpnSubscriberUri;
+    }
+
+
+    public Integer dpnListenerId() {
+        return dpnListenerId;
+    }
+
+
+    public void setDpnListenerId(Integer dpnListenerId) {
+        this.dpnListenerId = dpnListenerId;
+    }
+
+
+    public String dpnPublisherUri() {
+        return dpnPublisherUri;
+    }
+
+    public void setDpnPublisherUri(String dpnPublisherUri) {
+        this.dpnPublisherUri = dpnPublisherUri;
+    }
+
+
+    public Integer dpnClientThreads() {
+        return dpnClientThreads;
+    }
+
+
+    public void setDpnClientThreads(Integer dpnClientThreads) {
+        this.dpnClientThreads = dpnClientThreads;
+    }
+
+
+    public Integer metricUpdateMs() {
+        return metricsupdateMs;
+    }
+
+
+    public void setMetricsupdateMs(Integer metricsupdateMs) {
+        this.metricsupdateMs = metricsupdateMs;
+    }
+
+
+    public Integer mobilityUpdateMs() {
+        return mobilityupdateMs;
+    }
+
+
+    public void setMobilityupdateMs(Integer mobilityupdateMs) {
+        this.mobilityupdateMs = mobilityupdateMs;
+    }
+
+
+    public Integer activationThreads() {
+        return activationThreads;
+    }
+
+
+    public void setActivationThreads(Integer activationThreads) {
+        this.activationThreads = activationThreads;
+    }
+
+
+    public Integer targetReadLimit() {
+        return targetReadLimit;
+    }
+
+
+    public void setTargetReadLimit(Integer targetReadLimit) {
+        this.targetReadLimit = targetReadLimit;
+    }
+
+
+    public Integer httpNotifierClients() {
+        return httpNotifierClients;
+    }
+
+
+    public void setHttpNotifierClients(Integer httpNotifierClients) {
+        this.httpNotifierClients = httpNotifierClients;
+    }
+
+
+    public Integer zmqServerPoolsize() {
+        return zmqNbiServerPoolsize;
+    }
+
+
+    public void setZmqNbiServerPoolsize(Integer zmqNbiServerPoolsize) {
+        this.zmqNbiServerPoolsize = zmqNbiServerPoolsize;
+    }
+
+
+    public String zmqServerUri() {
+        return zmqNbiServerUri;
+    }
+
+
+    public void setZmqNbiServerUri(String zmqNbiServerUri) {
+        this.zmqNbiServerUri = zmqNbiServerUri;
+    }
+
+
+    public String zmqInprocUri() {
+        return zmqNbiInprocUri;
+    }
+
+
+    public void setZmqNbiInprocUri(String zmqNbiInprocUri) {
+        this.zmqNbiInprocUri = zmqNbiInprocUri;
+    }
+
+
+    public Integer zmqHandlerPoolsize() {
+        return zmqNbiHandlerPoolsize;
+    }
+
+
+    public void setZmqNbiHandlerPoolsize(Integer zmqNbiHandlerPoolsize) {
+        this.zmqNbiHandlerPoolsize = zmqNbiHandlerPoolsize;
+    }
+
+
+    public Integer httpNio2Poolsize() {
+        return httpNio2NbPoolsize;
+    }
+
+
+    public void setHttpNio2NbPoolsize(Integer httpNio2NbPoolsize) {
+        this.httpNio2NbPoolsize = httpNio2NbPoolsize;
+    }
+
+
+    public Integer httpNio2Port() {
+        return httpNio2NbPort;
+    }
+
+
+    public void setHttpNio2NbPort(Integer httpNio2NbPort) {
+        this.httpNio2NbPort = httpNio2NbPort;
+    }
+
+
+    public String nodeId() {
+        return nodeId;
+    }
+
+
+    public void setNodeId(String node_id) {
+        this.nodeId = node_id;
+    }
+
+
+    public String networkId() {
+        return networkId;
+    }
+
+
+    public void setNetworkId(String network_id) {
+        this.networkId = network_id;
+    }
+
+
+    public String zmqBroadcastControllers() {
+        return zmqBroadcastControllers;
+    }
+
+
+    public void setZmqBroadcastControllers(String zmqBroadcastControllers) {
+        this.zmqBroadcastControllers = zmqBroadcastControllers;
+    }
+
+    public String zmqBroadcastDpns() {
+        return zmqBroadcastDpns;
+    }
+
+
+    public void setZmqBroadcastDpns(String zmqBroadcastDpns) {
+        this.zmqBroadcastDpns = zmqBroadcastDpns;
+    }
+
+
+    public String zmqBroadcastAll() {
+        return zmqBroadcastAll;
+    }
+
+
+    public void setZmqBroadcastAll(String zmqBroadcastAll) {
+        this.zmqBroadcastAll = zmqBroadcastAll;
+    }
+
+    @JsonAnyGetter
+    public Map<String, Object> getAdditionalProperties() {
+        return this.additionalProperties;
+    }
+
+    @JsonAnySetter
+    public void setAdditionalProperty(String name, Object value) {
+        this.additionalProperties.put(name, value);
+    }
+
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/Converter.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/Converter.java
new file mode 100644
index 0000000..5c6b3ce
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/Converter.java
@@ -0,0 +1,169 @@
+package org.onosproject.fpcagent.util;
+
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.ClientIdentifier;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.tenant.fpcmobility.DefaultContexts;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcContextId;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcDpnGroupId;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcIdentity;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcPortId;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.fpccontext.Dl;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.fpccontext.Dpns;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.fpccontext.Ul;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.fpcidentity.FpcIdentityUnion;
+import org.onosproject.yang.gen.v1.ietfdmmthreegpp.rev20160803.ietfdmmthreegpp.EbiType;
+import org.onosproject.yang.gen.v1.ietfdmmthreegpp.rev20160803.ietfdmmthreegpp.ImsiType;
+import org.onosproject.yang.gen.v1.ietfinettypes.rev20130715.ietfinettypes.IpPrefix;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+
+public class Converter {
+    private static final Logger log = LoggerFactory.getLogger(Converter.class);
+    /**
+     * Short to Byte
+     *
+     * @param value - Short
+     * @return byte value
+     */
+    public static byte toUint8(Short value) {
+        return value.byteValue();
+    }
+
+    /**
+     * Short to byte array
+     *
+     * @param value - Short
+     * @return byte array
+     */
+    public static byte[] toUint16(Short value) {
+        return new byte[]{(byte) (value >>> 8), (byte) (value & 0xFF)};
+    }
+
+    /**
+     * Lower two bytes of an integer to byte array
+     *
+     * @param value - integer value
+     * @return byte array
+     */
+    public static byte[] toUint16(Integer value) {
+        return new byte[]{(byte) (value >>> 8), (byte) (value & 0xFF)};
+    }
+
+    /**
+     * Long to byte array.
+     *
+     * @param value - long
+     * @return byte array
+     */
+    public static byte[] toUint32(long value) {
+        return new byte[]{(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) (value & 0xFF)};
+    }
+
+    /**
+     * BigInteger to byte array.
+     *
+     * @param value - BigInteger
+     * @return byte array
+     */
+    public static byte[] toUint64(BigInteger value) {
+        return new byte[]{value.shiftRight(56).byteValue(), value.shiftRight(48).byteValue(), value.shiftRight(40).byteValue(),
+                value.shiftRight(32).byteValue(), value.shiftRight(24).byteValue(), value.shiftRight(16).byteValue(),
+                value.shiftRight(8).byteValue(), value.and(BigInteger.valueOf(0xFF)).byteValue()};
+    }
+
+    /**
+     * Decodes a 32 bit value
+     *
+     * @param source - byte array
+     * @param offset - offset in the array where the 8 bytes begins
+     * @return integer
+     */
+    public static int toInt(byte[] source, int offset) {
+        return new BigInteger(Arrays.copyOfRange(source, offset, offset + 4)).intValue();
+    }
+
+    /**
+     * Converts a byte array to BigInteger
+     *
+     * @param source - byte array
+     * @param offset - offset in the array where the 8 bytes begins
+     * @return BigInteger representing a Uint64
+     */
+    public static BigInteger toBigInt(byte[] source, int offset) {
+        return new BigInteger(Arrays.copyOfRange(source, offset, offset + 8));
+    }
+
+    /**
+     * Converts an integer to a long (used for larger unsigned integers)
+     *
+     * @param source - message buffer (byte array)
+     * @param offset - offset in the array where the 4 bytes begins
+     * @return Long value of the unsigned integer
+     */
+    public static long fromIntToLong(byte[] source, int offset) {
+        long value = 0;
+        for (int i = offset; i < offset + 4; i++) {
+            value = (value << 8) + (source[i] & 0xff);
+        }
+        return value;
+    }
+
+    public static Function<String, FpcIdentity> getFpcIdentity = (v) -> new FpcIdentity(new FpcIdentityUnion(v));
+    public static Function<String, ClientIdentifier> getClientIdentity = (v) -> new ClientIdentifier(getFpcIdentity.apply(v));
+
+    public static DefaultContexts convertContext(org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.payload.Contexts contexts) {
+        DefaultContexts ctx = new DefaultContexts();
+        FpcContextId fpcContextId = contexts.contextId();
+        List<IpPrefix> ipPrefixes = contexts.delegatingIpPrefixes();
+        Dl dl = contexts.dl();
+        Ul ul = contexts.ul();
+        boolean dormant = contexts.dormant();
+        FpcDpnGroupId fpcDpnGroupId = contexts.dpnGroup();
+        List<Dpns> dpns = contexts.dpns();
+        EbiType ebi = contexts.ebi();
+        EbiType lbi = contexts.lbi();
+        ImsiType imsi = contexts.imsi();
+        FpcContextId fpcContextId1 = contexts.parentContext();
+        List<FpcPortId> ports = contexts.ports();
+
+        if (fpcContextId != null) {
+            ctx.contextId(fpcContextId);
+        }
+        if (ipPrefixes != null) {
+            ctx.delegatingIpPrefixes(ipPrefixes);
+        }
+        if (dl != null) {
+            ctx.dl(dl);
+        }
+        if (ul != null) {
+            ctx.ul(ul);
+        }
+        ctx.dormant(dormant);
+        if (fpcDpnGroupId != null) {
+            ctx.dpnGroup(fpcDpnGroupId);
+        }
+        if (dpns != null) {
+            ctx.dpns(dpns);
+        }
+        if (ebi != null) {
+            ctx.ebi(ebi);
+        }
+        if (lbi != null) {
+            ctx.lbi(lbi);
+        }
+        if (imsi != null) {
+            ctx.imsi(imsi);
+        }
+        if (fpcContextId1 != null) {
+            ctx.parentContext(fpcContextId1);
+        }
+        if (ports != null) {
+            ctx.ports(ports);
+        }
+        return ctx;
+    }
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/DpnCommunicationService.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/DpnCommunicationService.java
new file mode 100644
index 0000000..e1bcd17
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/DpnCommunicationService.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.fpcagent.util;
+
+import org.onlab.packet.Ip4Address;
+
+import java.math.BigInteger;
+
+/**
+ * Communication Service which sends packets to desired DPNs.
+ */
+public interface DpnCommunicationService {
+
+    /**
+     * Creates Mobility Session.
+     *
+     * @param topic_id     - DPN Topic ID
+     * @param imsi         - IMSI identifier
+     * @param default_ebi  - EBI
+     * @param ue_ipv4      - UE IPv4 Address
+     * @param s1u_sgw_teid - SGW Tunnel Identifier
+     * @param s1u_sgw_ipv4 - SGW IPv4
+     * @param session_id   - Context Identifier
+     * @param client_id    - Client Identifier
+     * @param op_id        - Operation Identifier
+     */
+    void create_session(
+            Short topic_id,
+            BigInteger imsi,
+            Short default_ebi,
+            Ip4Address ue_ipv4,
+            Long s1u_sgw_teid,
+            Ip4Address s1u_sgw_ipv4,
+            Long session_id,
+            Long client_id,
+            BigInteger op_id
+    );
+
+    /**
+     * Modifies Bearer.
+     *
+     * @param topic_id        - DPN Topic ID
+     * @param s1u_sgw_ipv4    - SGW IPv4 Address
+     * @param s1u_enodeb_teid - ENodeB Tunnel Identifier
+     * @param s1u_enodeb_ipv4 - ENodeB IPv4 Address
+     * @param session_id      - Context Identifier
+     * @param client_id       - Client Identifier
+     * @param op_id           - Operation Identifier
+     */
+    void modify_bearer(
+            Short topic_id,
+            Ip4Address s1u_sgw_ipv4,
+            Long s1u_enodeb_teid,
+            Ip4Address s1u_enodeb_ipv4,
+            Long session_id,
+            Long client_id,
+            BigInteger op_id
+    );
+
+    /**
+     * Deletes Mobility Session.
+     *
+     * @param topic_id   - DPN Topic ID
+     * @param session_id - Context Identifier
+     * @param client_id  - Client Identifier
+     * @param op_id      - Operation Identifier
+     */
+    void delete_session(
+            Short topic_id,
+            Long session_id,
+            Long client_id,
+            BigInteger op_id
+    );
+
+    /**
+     * Creates the byte buffer to send ADC rules over ZMQ
+     *
+     * @param topic        - DPN Topic ID
+     * @param domain_name  - domain
+     * @param ip           - ipaddress/ipprefix (i.e. 127.0.0.1/32)
+     * @param drop         - Drop if 1
+     * @param rating_group - Rating Group
+     * @param service_ID   - Service ID
+     * @param sponsor_ID   - Sponsor ID
+     */
+    void send_ADC_rules(
+            Short topic,
+            String domain_name,
+            String ip,
+            Short drop,
+            Long rating_group,
+            Long service_ID,
+            String sponsor_ID
+    );
+}
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/DpnNgicCommunicator.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/DpnNgicCommunicator.java
new file mode 100644
index 0000000..82618f4
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/DpnNgicCommunicator.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.fpcagent.util;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.fpcagent.workers.ZMQSBPublisherManager;
+import org.onosproject.fpcagent.workers.ZMQSBSubscriberManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+import static org.onosproject.fpcagent.util.Converter.*;
+
+/**
+ * DPDK DPN API over ZeroMQ for NGIC.
+ */
+public class DpnNgicCommunicator implements DpnCommunicationService {
+    protected static final Logger log = LoggerFactory.getLogger(DpnNgicCommunicator.class);
+
+    @Override
+    public void create_session(
+            Short topic_id,
+            BigInteger imsi,
+            Short default_ebi,
+            Ip4Address ue_ipv4,
+            Long s1u_sgw_teid,
+            Ip4Address s1u_sgw_ipv4,
+            Long session_id,
+            Long client_id,
+            BigInteger op_id
+    ) {
+        /* NGIC Create Session expected buffer:
+            uint8_t topic_id;
+	        uint8_t type;
+            struct create_session_t {
+                uint64_t imsi;
+                uint8_t  default_ebi;
+                uint32_t ue_ipv4;
+                uint32_t s1u_sgw_teid;
+                uint32_t s1u_sgw_ipv4;
+                uint64_t session_id;
+                uint8_t  controller_topic;
+                uint32_t client_id;
+                uint32_t op_id;
+            } create_session_msg;
+         */
+        // TODO: check if subscriber is open.
+        ByteBuffer bb = ByteBuffer.allocate(41)
+                .put(toUint8(topic_id))
+                .put(s11MsgType.CREATE_SESSION.getType())
+                .put(toUint64(imsi))
+                .put(toUint8(default_ebi))
+                .put(toUint32(ue_ipv4.toInt()))
+                .put(toUint32(s1u_sgw_teid))
+                .put(toUint32(s1u_sgw_ipv4.toInt()))
+                .put(toUint64(BigInteger.valueOf(session_id)))
+                .put(toUint8(ZMQSBSubscriberManager.getControllerTopic()))
+                .put(toUint32(client_id))
+                .put(toUint32(op_id.longValue()));
+
+        log.debug("create_session: {}", bb.array());
+        ZMQSBPublisherManager.getInstance().send(bb);
+    }
+
+    @Override
+    public void modify_bearer(
+            Short topic_id,
+            Ip4Address s1u_sgw_ipv4,
+            Long s1u_enodeb_teid,
+            Ip4Address s1u_enodeb_ipv4,
+            Long session_id,
+            Long client_id,
+            BigInteger op_id
+    ) {
+        /*
+           NGIC Modify Session expected buffer:
+           	uint8_t topic_id;
+	        uint8_t type;
+	        struct modify_bearer_t {
+			    uint32_t s1u_sgw_ipv4;
+			    uint32_t s1u_enodeb_teid;
+			    uint32_t s1u_enodeb_ipv4;
+			    uint64_t session_id;
+			    uint8_t  controller_topic;
+			    uint32_t client_id;
+			    uint32_t op_id;
+		    } modify_bearer_msg;
+         */
+        ByteBuffer bb = ByteBuffer.allocate(32)
+                .put(toUint8(topic_id))
+                .put(s11MsgType.MODIFY_BEARER.getType())
+                .put(toUint32(s1u_sgw_ipv4.toInt()))
+                .put(toUint32(s1u_enodeb_teid))
+                .put(toUint32(s1u_enodeb_ipv4.toInt()))
+                .put(toUint64(BigInteger.valueOf(session_id)))
+                .put(toUint8(ZMQSBSubscriberManager.getControllerTopic()))
+                .put(toUint32(client_id))
+                .put(toUint32(op_id.longValue()));
+
+        log.debug("modify_bearer: {}", bb.array());
+        ZMQSBPublisherManager.getInstance().send(bb);
+    }
+
+    @Override
+    public void delete_session(
+            Short topic_id,
+            Long session_id,
+            Long client_id,
+            BigInteger op_id
+    ) {
+        /*
+            NGIC Delete Session expected buffer:
+            uint8_t topic_id;
+	        uint8_t type;
+            struct delete_session_t {
+			    uint64_t session_id;
+			    uint8_t  controller_topic;
+			    uint32_t client_id;
+			    uint32_t op_id;
+		    } delete_session_msg;
+         */
+        ByteBuffer bb = ByteBuffer.allocate(19)
+                .put(toUint8(topic_id))
+                .put(s11MsgType.DELETE_SESSION.getType())
+                .put(toUint64(BigInteger.valueOf(session_id)))
+                .put(toUint8(ZMQSBSubscriberManager.getControllerTopic()))
+                .put(toUint32(client_id))
+                .put(toUint32(op_id.longValue()));
+
+        log.debug("delete_session: {}", bb.array());
+        ZMQSBPublisherManager.getInstance().send(bb);
+    }
+
+    @Override
+    public void send_ADC_rules(
+            Short topic,
+            String domain_name,
+            String ip,
+            Short drop,
+            Long rating_group,
+            Long service_ID, String sponsor_ID
+    ) {
+        // TODO take a look for this function. Not tested.
+        Ip4Prefix ip_prefix = null;
+        if (ip != null) {
+            ip_prefix = Ip4Prefix.valueOf(ip);
+        }
+        Short selector_type = (short) (domain_name != null ? 0 : ip_prefix != null ? 2 : ip_prefix.address() != null ? 1 : 255);
+        if (selector_type == 255) {
+            log.warn("Domain/IP not found, failed to send rules");
+            return;
+        }
+        ByteBuffer bb = ByteBuffer.allocate(200);
+        bb.put(toUint8(topic))
+                .put(s11MsgType.ADC_RULE.getType())
+                .put(toUint8(selector_type));
+        if (selector_type == 0) {
+            bb.put(toUint8((short) domain_name.length()))
+                    .put(domain_name.getBytes());
+        }
+        if ((selector_type == 1) || (selector_type == 2)) {
+            int ip_address_long = ip_prefix.address().toInt();
+            bb.put(toUint32(ip_address_long));
+        }
+        if (selector_type == 2) {
+            bb.put(toUint16(ip_prefix.prefixLength()));
+        }
+        if (drop != null)
+            bb.put(toUint8(drop));
+        if (rating_group != null)
+            bb.put(toUint32(rating_group));
+        if (service_ID != null)
+            bb.put(toUint32(service_ID));
+        if (sponsor_ID != null && (short) sponsor_ID.length() > 0) {
+            bb.put(toUint8((short) sponsor_ID.length()))
+                    .put(sponsor_ID.getBytes());
+        }
+        bb.put(toUint8(ZMQSBSubscriberManager.getControllerTopic()));
+
+        log.info("send_ADC_rules: {}", bb.array());
+        ZMQSBPublisherManager.getInstance().send(bb);
+    }
+
+    /**
+     * Following the NGIC message types.
+     *
+     * This type structure is defined in NGIC at interface/zmq/zmqsub.h:51
+     */
+    enum s11MsgType {
+        CREATE_SESSION(1),
+        MODIFY_BEARER(2),
+        DELETE_SESSION(3),
+        DPN_RESPONSE(4),
+        DDN(5),
+        ASSIGN_TOPIC(10),
+        ASSIGN_CONFLICT(11),
+        DPN_STATUS_INDICATION(12),
+        DPN_STATUS_ACK(13),
+        CONTROLLER_STATUS_INDICATION(14),
+        ADC_RULE(17),
+        PCC_RULE(18),
+        METER_RULE(19),
+        SDF_RULE(20);
+
+        private byte type;
+
+        s11MsgType(int type) {
+            this.type = (byte) type;
+        }
+
+        public byte getType() {
+            return type;
+        }
+    }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..a0ff5f7
--- /dev/null
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.fpcagent.util;
+
+import com.google.common.collect.Maps;
+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.tenants.DefaultTenant;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.TenantKeys;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.yangautoprefixnotify.value.DefaultDownlinkDataNotification;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.yangautoprefixnotify.value.DownlinkDataNotification;
+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.fpcidentity.FpcIdentityUnion;
+import org.onosproject.yang.model.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Map;
+
+import static org.onosproject.fpcagent.util.Converter.*;
+
+/**
+ * Helper class which stores all the static variables.
+ */
+public class FpcUtil {
+    public static final int MAX_EVENTS = 1000;
+    public static final int MAX_BATCH_MS = 5000;
+    public static final int MAX_IDLE_MS = 1000;
+    public static final String TIMER = "dynamic-config-fpcagent-timer";
+    public static final String UNKNOWN_EVENT = "FPC Agent listener: unknown event: {}";
+    public static final String EVENT_NULL = "Event cannot be null";
+    public static final String FPC_APP_ID = "org.onosproject.fpcagent";
+    protected static final Logger log = LoggerFactory.getLogger(FpcUtil.class);
+    private static final Map<String, FpcDpnId> uplinkDpnMap = Maps.newConcurrentMap();
+    private static final Map<String, Short> nodeToTopicMap = Maps.newConcurrentMap();
+    public static ModelConverter modelConverter = null;
+    // Resource ID for Configure DPN RPC command
+    public static ResourceId configureDpn;
+    // Resource ID for Configure RPC command
+    public static ResourceId configure;
+    // Resource ID for tenants data
+    public static ResourceId tenants;
+    public static ResourceId defaultTenant;
+    public static ResourceId configureBundles;
+    public static ResourceId module;
+    public static ResourceId registerClientResourceId;
+    public static ResourceId deregisterClientResourceId;
+
+    public static FpcIdentity defaultIdentity = getFpcIdentity.apply("default");
+
+    private static byte DPN_HELLO = 0b0000_0001;
+    private static byte DPN_BYE = 0b0000_0010;
+    private static byte DOWNLINK_DATA_NOTIFICATION = 0b0000_0101;
+    private static byte DPN_STATUS_INDICATION = 0b0000_1100;
+    private static byte DPN_OVERLOAD_INDICATION = 0b0000_0101;
+    private static byte DPN_REPLY = 0b0000_0100;
+    private static String DOWNLINK_DATA_NOTIFICATION_STRING = "Downlink-Data-Notification";
+
+    /**
+     * Returns resource id from model converter.
+     *
+     * @param modelId model object id
+     * @return resource id
+     */
+    public static ResourceId getResourceVal(ModelObjectId modelId) {
+        DefaultModelObjectData.Builder data = DefaultModelObjectData.builder()
+                .identifier(modelId);
+        ResourceData resData = modelConverter.createDataNode(data.build());
+        return resData.resourceId();
+    }
+
+    /**
+     * Returns the resource id, after constructing model object id and
+     * converting it.
+     */
+    public static void getResourceId() {
+        ModelObjectId moduleId = ModelObjectId.builder().build();
+        module = getResourceVal(moduleId);
+
+        ModelObjectId tenantsId = ModelObjectId.builder()
+                .addChild(DefaultTenants.class)
+                .build();
+
+        tenants = getResourceVal(tenantsId);
+
+        TenantKeys tenantKeys = new TenantKeys();
+        tenantKeys.tenantId(defaultIdentity);
+
+        ModelObjectId defaultTenantId = ModelObjectId.builder()
+                .addChild(DefaultTenants.class)
+                .addChild(DefaultTenant.class, tenantKeys)
+                .build();
+
+        defaultTenant = getResourceVal(defaultTenantId);
+
+        configure = ResourceId.builder()
+                .addBranchPointSchema("/", null)
+                .addBranchPointSchema("configure", "urn:ietf:params:xml:ns:yang:fpcagent")
+                .build();
+
+        configureDpn = ResourceId.builder()
+                .addBranchPointSchema("/", null)
+                .addBranchPointSchema("configure-dpn", "urn:ietf:params:xml:ns:yang:fpcagent")
+                .build();
+
+        configureBundles = ResourceId.builder()
+                .addBranchPointSchema("/", null)
+                .addBranchPointSchema("configure-bundles", "urn:ietf:params:xml:ns:yang:fpcagent")
+                .build();
+    }
+
+    public static ModelObjectId.Builder defaultTenantBuilder() {
+        TenantKeys tenantKeys = new TenantKeys();
+        tenantKeys.tenantId(defaultIdentity);
+
+        return ModelObjectId.builder()
+                .addChild(DefaultTenants.class)
+                .addChild(DefaultTenant.class, tenantKeys);
+    }
+
+    /**
+     * Returns resource id for the specific tenant ID.
+     *
+     * @param tenantId tenant id
+     * @return resource ids
+     */
+    public static ResourceId getTenantResourceId(FpcIdentity tenantId) {
+        TenantKeys tenantKeys = new TenantKeys();
+        tenantKeys.tenantId(tenantId);
+
+        return getResourceVal(ModelObjectId.builder()
+                .addChild(DefaultTenants.class)
+                .addChild(DefaultTenant.class, tenantKeys)
+                .build());
+    }
+
+    /**
+     * 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
+     * @return unsigned session id
+     */
+    private static BigInteger checkSessionId(BigInteger sessionId) {
+        if (sessionId.compareTo(BigInteger.ZERO) < 0) {
+            sessionId = sessionId.add(BigInteger.ONE.shiftLeft(64));
+        }
+        return sessionId;
+    }
+
+    /**
+     * Decodes a DownlinkDataNotification
+     *
+     * @param buf - message buffer
+     * @param key - Concatenation of node id + / + network id
+     * @return DownlinkDataNotification or null if it could not be successfully decoded
+     */
+    private static DownlinkDataNotification processDDN(byte[] buf, String key) {
+        DownlinkDataNotification ddnB = new DefaultDownlinkDataNotification();
+        ddnB.sessionId(checkSessionId(toBigInt(buf, 2)));
+        ddnB.notificationMessageType(DOWNLINK_DATA_NOTIFICATION_STRING);
+        ddnB.clientId(ClientIdentifier.of(FpcIdentity.of(FpcIdentityUnion.of(fromIntToLong(buf, 10)))));
+        ddnB.opId(OpIdentifier.of(BigInteger.valueOf(fromIntToLong(buf, 14))));
+        ddnB.notificationDpnId(uplinkDpnMap.get(key));
+        return ddnB;
+    }
+
+    /**
+     * Decodes a DPN message.
+     *
+     * @param buf - message buffer
+     * @return - A pair with the DPN Id and decoded Object
+     */
+    public static Map.Entry<FpcDpnId, Object> decode(byte[] buf) {
+        if (buf[1] == DPN_REPLY) {
+            return null;
+        } else if (buf[1] == DOWNLINK_DATA_NOTIFICATION) {
+            short nodeIdLen = buf[18];
+            short networkIdLen = buf[19 + nodeIdLen];
+            String key = new String(Arrays.copyOfRange(buf, 19, 19 + nodeIdLen)) + "/" + new String(Arrays.copyOfRange(buf, 20 + nodeIdLen, 20 + nodeIdLen + networkIdLen));
+            return uplinkDpnMap.get(key) == null ? null : new AbstractMap.SimpleEntry<>(uplinkDpnMap.get(key), processDDN(buf, key));
+        } else if (buf[1] == DPN_STATUS_INDICATION) {
+            DPNStatusIndication.Status status = null;
+
+            short nodeIdLen = buf[8];
+            short networkIdLen = buf[9 + nodeIdLen];
+            String key = new String(Arrays.copyOfRange(buf, 9, 9 + nodeIdLen)) + "/" + new String(Arrays.copyOfRange(buf, 10 + nodeIdLen, 10 + nodeIdLen + networkIdLen));
+            if (buf[3] == DPN_OVERLOAD_INDICATION) {
+                status = DPNStatusIndication.Status.OVERLOAD_INDICATION;
+            } else if (buf[3] == DPN_HELLO) {
+                status = DPNStatusIndication.Status.HELLO;
+                log.info("Hello {} on topic {}", key, buf[2]);
+                nodeToTopicMap.put(key, (short) buf[2]);
+            } else if (buf[3] == DPN_BYE) {
+                status = DPNStatusIndication.Status.BYE;
+                log.info("Bye {}", key);
+                nodeToTopicMap.remove(key);
+            }
+            return new AbstractMap.SimpleEntry<>(uplinkDpnMap.get(key), new DPNStatusIndication(status, key));
+        }
+        return null;
+    }
+
+    /**
+     * Gets the mapping for node id / network id to ZMQ Topic
+     *
+     * @param Key - Concatenation of node id + / + network id
+     * @return - ZMQ Topic
+     */
+    public static Short getTopicFromNode(String Key) {
+        return nodeToTopicMap.get(Key);
+    }
+
+    /**
+     * Provides basic status changes,
+     */
+    public static class DPNStatusIndication {
+        private final Status status;
+        private final String key; //nodeId +"/"+ networkId
+        /**
+         * Node Reference of the DPN
+         */
+        public Short nodeRef;
+
+        /**
+         * Constructor providing the DPN and its associated Status.
+         *
+         * @param status - DPN Status
+         * @param key    - Combination of node id and network id
+         */
+        public DPNStatusIndication(Status status,
+                                   String key) {
+            this.status = status;
+            this.key = key;
+        }
+
+        /**
+         * Provides DPN Status
+         *
+         * @return Status associated to the DPN.
+         */
+        public Status getStatus() {
+            return status;
+        }
+
+        /**
+         * Provides the DPN key - nodeId +"/"+ networkId
+         *
+         * @return FpcDpnId
+         */
+        public String getKey() {
+            return this.key;
+        }
+
+        /**
+         * Basic DPN Status
+         */
+        public enum Status {
+            HELLO,
+            BYE,
+            OVERLOAD_INDICATION
+        }
+    }
+}
diff --git a/scripts/benchmark.sh b/scripts/benchmark.sh
index 1cc3b93..1d3a6ac 100755
--- a/scripts/benchmark.sh
+++ b/scripts/benchmark.sh
@@ -1,19 +1,23 @@
 #!/bin/sh
 
+rm -rf create.log delete.log
+
 ./addDPN.sh 1 &> /dev/null 
 
 for (( i=1; i<=100; i++)); do
-	./configureCreateOrUpdate.sh create $i 1 &> /dev/null &
+	./configure.sh create $i 1 >> create.log 2> /dev/null &
 	if ! (($i % 10)); then
 		wait
 	fi
 done
 
-#for (( i=1; i<=100; i++)); do
-#	./configureDeleteOrQuery.sh delete $i &> /dev/null &
-#	if ! (($i % 10)); then
-#		wait
-#	fi
-#done
+wait
+
+for (( i=1; i<=100; i++)); do
+	./configure.sh delete $i >> delete.log 2> /dev/null &
+	if ! (($i % 10)); then
+		wait
+	fi
+done
 
 ./deleteDPN.sh 1 &> /dev/null 
diff --git a/scripts/configureCreateOrUpdate.sh b/scripts/configure.sh
similarity index 71%
rename from scripts/configureCreateOrUpdate.sh
rename to scripts/configure.sh
index 5ce3bbe..a77d853 100755
--- a/scripts/configureCreateOrUpdate.sh
+++ b/scripts/configure.sh
@@ -1,6 +1,30 @@
 #!/bin/bash
 
-if [ "$#" -eq 3 ]; then
+if [ "$#" -eq 2 ] && [ $1 == "delete" ]; then
+    echo ""
+    json='{
+            "input": {
+                "op-id": '$2',
+                "targets": [
+                    {
+                        "target": "/ietf-dmm-fpcagent:tenants/tenant=default/fpc-mobility/contexts='$2'"
+                    }
+                ],
+                "client-id": "1",
+                "session-state": "complete",
+                "admin-state": "enabled",
+                "op-type": "'$1'",
+                "op-ref-scope": "none"
+            }
+        }'
+
+    curl -X POST \
+        --header 'Content-Type: application/json' \
+        -u onos:rocks \
+        --header 'Accept: application/json' \
+        -d "$json" \
+        'http://localhost:8181/onos/restconf/operations/ietf-dmm-fpcagent:configure' | python -m json.tool
+elif [ "$#" -eq 3 ] && [ $1 == "create" ]; then
     echo ""
     json='{
             "input": {
@@ -46,7 +70,7 @@
                         }
                     }
                 ],
-                "op-id": "1",
+                "op-id": '$2',
                 "op-ref-scope": "op",
                 "op-type": "'$1'",
                 "session-state": "complete"
@@ -61,5 +85,5 @@
         'http://localhost:8181/onos/restconf/operations/ietf-dmm-fpcagent:configure' | python -m json.tool
     echo ""
 else
-    echo "usage: "$0" type contextId dpnId"
+    echo "usage: "$0" type contextId"
 fi
\ No newline at end of file
diff --git a/scripts/configureDeleteOrQuery.sh b/scripts/configureDeleteOrQuery.sh
deleted file mode 100755
index 5735d72..0000000
--- a/scripts/configureDeleteOrQuery.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-
-if [ "$#" -eq 2 ]; then
-    echo ""
-    json='{
-            "input": {
-                "op-id": "3",
-                "targets": [
-                    {
-                        "target": "/ietf-dmm-fpcagent:tenants/tenant=default/fpc-mobility/contexts='$2'"
-                    }
-                ],
-                "client-id": "1",
-                "session-state": "complete",
-                "admin-state": "enabled",
-                "op-type": "'$1'",
-                "op-ref-scope": "none"
-            }
-        }'
-
-    curl -X POST \
-        --header 'Content-Type: application/json' \
-        -u onos:rocks \
-        --header 'Accept: application/json' \
-        -d "$json" \
-        'http://localhost:8181/onos/restconf/operations/ietf-dmm-fpcagent:configure' | python -m json.tool
-else
-    echo "usage: "$0" type contextId"
-fi
\ No newline at end of file