[ONOS-6224] L3VPN service delete

Change-Id: I2eabb231def39dba6613dc5b95f2b16594133ad4
diff --git a/apps/l3vpn/netl3vpn/src/main/java/org/onosproject/l3vpn/netl3vpn/impl/NetL3VpnManager.java b/apps/l3vpn/netl3vpn/src/main/java/org/onosproject/l3vpn/netl3vpn/impl/NetL3VpnManager.java
new file mode 100644
index 0000000..67c6237
--- /dev/null
+++ b/apps/l3vpn/netl3vpn/src/main/java/org/onosproject/l3vpn/netl3vpn/impl/NetL3VpnManager.java
@@ -0,0 +1,1140 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.l3vpn.netl3vpn.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.util.AbstractAccumulator;
+import org.onlab.util.Accumulator;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipEvent;
+import org.onosproject.cluster.LeadershipEventListener;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.config.DynamicConfigEvent;
+import org.onosproject.config.DynamicConfigListener;
+import org.onosproject.config.DynamicConfigService;
+import org.onosproject.config.FailedException;
+import org.onosproject.config.Filter;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.l3vpn.netl3vpn.AccessInfo;
+import org.onosproject.l3vpn.netl3vpn.BgpDriverInfo;
+import org.onosproject.l3vpn.netl3vpn.BgpInfo;
+import org.onosproject.l3vpn.netl3vpn.DeviceInfo;
+import org.onosproject.l3vpn.netl3vpn.FullMeshVpnConfig;
+import org.onosproject.l3vpn.netl3vpn.HubSpokeVpnConfig;
+import org.onosproject.l3vpn.netl3vpn.InterfaceInfo;
+import org.onosproject.l3vpn.netl3vpn.NetL3VpnException;
+import org.onosproject.l3vpn.netl3vpn.NetL3VpnStore;
+import org.onosproject.l3vpn.netl3vpn.VpnConfig;
+import org.onosproject.l3vpn.netl3vpn.VpnInstance;
+import org.onosproject.l3vpn.netl3vpn.VpnSiteRole;
+import org.onosproject.l3vpn.netl3vpn.VpnType;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev20130715.IetfInetTypes;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev20140508.ietfinterfaces.devices.device.Interfaces;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.IetfL3VpnSvc;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.DefaultL3VpnSvc;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.L3VpnSvc;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.accessvpnpolicy.VpnAttachment;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.accessvpnpolicy.vpnattachment.AttachmentFlavor;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.accessvpnpolicy.vpnattachment.attachmentflavor.DefaultVpnId;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.l3vpnsvc.DefaultSites;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.l3vpnsvc.Sites;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.l3vpnsvc.VpnServices;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.l3vpnsvc.sites.Site;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.l3vpnsvc.sites.site.SiteNetworkAccesses;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.l3vpnsvc.sites.site.sitenetworkaccesses.SiteNetworkAccess;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.l3vpnsvc.vpnservices.VpnSvc;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.siteattachmentbearer.Bearer;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.siteattachmentbearer.DefaultBearer;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.siteattachmentbearer.bearer.DefaultRequestedType;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.siteattachmentbearer.bearer.RequestedType;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.siteattachmentipconnection.IpConnection;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.siterouting.RoutingProtocols;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.l3vpn.svc.rev20160730.ietfl3vpnsvc.siterouting.routingprotocols.RoutingProtocol;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.instance.rev20160623.ietfnetworkinstance.devices.device.NetworkInstances;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev20130715.IetfYangTypes;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.l3vpn.svc.ext.rev20160730.L3VpnSvcExt;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.l3vpn.svc.ext.rev20160730.l3vpnsvcext.l3vpnsvc.sites.site.sitenetworkaccesses.sitenetworkaccess.bearer.DefaultAugmentedL3VpnBearer;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.l3vpn.svc.ext.rev20160730.l3vpnsvcext.l3vpnsvc.sites.site.sitenetworkaccesses.sitenetworkaccess.bearer.requestedtype.DefaultAugmentedL3VpnRequestedType;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.l3vpn.svc.ext.rev20160730.l3vpnsvcext.requestedtypegrouping.requestedtypeprofile.RequestedTypeChoice;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.l3vpn.svc.ext.rev20160730.l3vpnsvcext.requestedtypegrouping.requestedtypeprofile.requestedtypechoice.DefaultDot1Qcase;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.l3vpn.svc.ext.rev20160730.l3vpnsvcext.requestedtypegrouping.requestedtypeprofile.requestedtypechoice.DefaultPhysicalCase;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.DefaultModelObjectData;
+import org.onosproject.yang.model.ModelConverter;
+import org.onosproject.yang.model.ModelObject;
+import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.model.ModelObjectId;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceData;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.model.YangModel;
+import org.onosproject.yang.model.YangModuleId;
+import org.onosproject.yang.runtime.DefaultAppModuleInfo;
+import org.onosproject.yang.runtime.DefaultModelRegistrationParam;
+import org.onosproject.yang.runtime.ModelRegistrationParam;
+import org.onosproject.yang.runtime.YangModelRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
+import static org.onosproject.l3vpn.netl3vpn.VpnType.HUB;
+import static org.onosproject.l3vpn.netl3vpn.impl.BgpConstructionUtil.createBgpInfo;
+import static org.onosproject.l3vpn.netl3vpn.impl.InsConstructionUtil.createInstance;
+import static org.onosproject.l3vpn.netl3vpn.impl.InsConstructionUtil.deleteInstance;
+import static org.onosproject.l3vpn.netl3vpn.impl.IntConstructionUtil.createInterface;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.BEARER_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.CONS_HUNDRED;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.DEVICE_INFO_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.EVENT_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.ID_LIMIT;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.ID_LIMIT_EXCEEDED;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.INT_INFO_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.IP;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.IP_INT_INFO_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.MAX_BATCH_MS;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.MAX_EVENTS;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.MAX_IDLE_MS;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.PORT_NAME;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.SITE_ROLE_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.SITE_VPN_MISMATCH;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.TIMER;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.UNKNOWN_EVENT;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.VPN_ATTACHMENT_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.VPN_POLICY_NOT_SUPPORTED;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.VPN_TYPE_UNSUPPORTED;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getBgpCreateConfigObj;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getIntCreateModObj;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getIntNotAvailable;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getMgmtIpUnAvailErr;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getModIdForL3VpnSvc;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getModIdForSites;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getResourceData;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getRole;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getVpnBgpDelModObj;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getVpnCreateModObj;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.getVpnDelModObj;
+import static org.onosproject.yang.runtime.helperutils.YangApacheUtils.getYangModel;
+
+/**
+ * The IETF net l3vpn manager implementation.
+ */
+@Component(immediate = true)
+public class NetL3VpnManager {
+
+    private static final String APP_ID = "org.onosproject.app.l3vpn";
+    private static final String L3_VPN_ID_TOPIC = "l3vpn-id";
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private final DynamicConfigListener configListener =
+            new InternalConfigListener();
+
+    private final Accumulator<DynamicConfigEvent> accumulator =
+            new InternalEventAccumulator();
+
+    private final InternalLeadershipListener leadershipEventListener =
+            new InternalLeadershipListener();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DriverService driverService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected YangModelRegistry modelRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ModelConverter modelConverter;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DynamicConfigService configService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetL3VpnStore l3VpnStore;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LeadershipService leadershipService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterService clusterService;
+
+    protected IdGenerator l3VpnIdGen;
+
+    private NodeId localNodeId;
+
+    private ApplicationId appId;
+
+    private ModelRegistrationParam regParam;
+
+    private ResourceId id;
+
+    private ResourceId module;
+
+    private ResourceId sites;
+
+    private boolean isElectedLeader = false;
+
+    @Activate
+    protected void activate() {
+        appId = coreService.registerApplication(APP_ID);
+        l3VpnIdGen = coreService.getIdGenerator(L3_VPN_ID_TOPIC);
+
+        localNodeId = clusterService.getLocalNode().id();
+
+        leadershipService.addListener(leadershipEventListener);
+        leadershipService.runForLeadership(appId.name());
+
+        registerModel();
+        getResourceId();
+        configService.addListener(configListener);
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        modelRegistry.unregisterModel(regParam);
+        configService.removeListener(configListener);
+
+        leadershipService.withdraw(appId.name());
+        leadershipService.removeListener(leadershipEventListener);
+
+        log.info("Stopped");
+    }
+
+    private void registerModel() {
+        YangModel model = getYangModel(IetfInetTypes.class);
+        Iterator<YangModuleId> it = model.getYangModulesId().iterator();
+
+        //Create model registration param.
+        ModelRegistrationParam.Builder b =
+                DefaultModelRegistrationParam.builder().setYangModel(model);
+
+        YangModuleId id;
+        while (it.hasNext()) {
+            id = it.next();
+            switch (id.moduleName()) {
+                case "ietf-inet-types":
+                    b.addAppModuleInfo(id, new DefaultAppModuleInfo(
+                            IetfInetTypes.class, null));
+                    break;
+                case "ietf-l3vpn-svc":
+                    b.addAppModuleInfo(id, new DefaultAppModuleInfo(
+                            IetfL3VpnSvc.class, null));
+                    break;
+                case "ietf-yang-types":
+                    b.addAppModuleInfo(id, new DefaultAppModuleInfo(
+                            IetfYangTypes.class, null));
+                    break;
+                case "l3vpn-svc-ext":
+                    b.addAppModuleInfo(id, new DefaultAppModuleInfo(
+                            L3VpnSvcExt.class, null));
+                    break;
+                default:
+                    break;
+            }
+        }
+        regParam = b.build();
+        modelRegistry.registerModel(regParam);
+    }
+
+    /**
+     * Returns id as string. If the id is not in the freed list a new id is
+     * generated else the id from the freed list is used.
+     *
+     * @return id
+     */
+    private String getIdFromGen() {
+        Long value;
+        Iterable<Long> freeIds = l3VpnStore.getFreedIdList();
+        Iterator<Long> it = freeIds.iterator();
+        if (it.hasNext()) {
+            value = it.next();
+            l3VpnStore.removeIdFromFreeList(value);
+        } else {
+            value = l3VpnIdGen.getNewId();
+        }
+        if (value > ID_LIMIT) {
+            throw new RuntimeException(ID_LIMIT_EXCEEDED);
+        }
+        return CONS_HUNDRED + String.valueOf(value);
+    }
+
+    /**
+     * Returns the resource id, after constructing model object id and
+     * converting it.
+     */
+    private void getResourceId() {
+
+        ModelObjectId moduleId = ModelObjectId.builder().build();
+        module = getResourceVal(moduleId);
+
+        ModelObjectId svcId = getModIdForL3VpnSvc();
+        id = getResourceVal(svcId);
+
+        ModelObjectId sitesId = getModIdForSites();
+        sites = getResourceVal(sitesId);
+    }
+
+    /**
+     * Returns resource id from model converter.
+     *
+     * @param modelId model object id
+     * @return resource id
+     */
+    private ResourceId getResourceVal(ModelObjectId modelId) {
+        DefaultModelObjectData.Builder data = DefaultModelObjectData.builder()
+                .identifier(modelId);
+        ResourceData resData = modelConverter.createDataNode(data.build());
+        return resData.resourceId();
+    }
+
+    /**
+     * Processes create request from the store, by taking the root object.
+     * The root object is then used for l3VPN processing.
+     *
+     * @param storeId store resource id
+     * @param node    data node
+     */
+    private void processCreateFromStore(ResourceId storeId, DataNode node) {
+        if (isElectedLeader) {
+            List<NodeKey> keys = storeId.nodeKeys();
+            List<ModelObject> objects = null;
+            if (keys.size() == 1) {
+                objects = getModelObjects(node, module);
+            } else if (keys.size() == 2) {
+                objects = getModelObjects(node, id);
+            }
+            if (objects != null) {
+                for (ModelObject obj : objects) {
+                    if (obj instanceof DefaultL3VpnSvc) {
+                        DefaultL3VpnSvc l3VpnSvc = (DefaultL3VpnSvc) obj;
+                        createGlobalConfig(l3VpnSvc);
+                    } else if (obj instanceof DefaultSites) {
+                        DefaultSites sites = (DefaultSites) obj;
+                        createInterfaceConfig(sites);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Processes delete request from the store, by taking the root object.
+     * The root object would have got deleted from store. So all the
+     * configurations are removed.
+     *
+     * @param dataNode data node
+     */
+    private void processDeleteFromStore(DataNode dataNode) {
+        if (isElectedLeader) {
+            if (dataNode == null) {
+                //TODO: Delete for inner nodes.
+                deleteGlobalConfig(null);
+            }
+        }
+    }
+
+    /**
+     * Returns model objects of the store. The data node read from store
+     * gives the particular node. So the node's parent resource id is taken
+     * and the data node is given to model converter.
+     *
+     * @param dataNode data node from store
+     * @param appId    parent resource id
+     * @return model objects
+     */
+    public List<ModelObject> getModelObjects(DataNode dataNode,
+                                             ResourceId appId) {
+        ResourceData data = getResourceData(dataNode, appId);
+        ModelObjectData modelData = modelConverter.createModel(data);
+        return modelData.modelObjects();
+    }
+
+    /**
+     * Returns true if the event resource id points to the root level node
+     * only and event is for addition and deletion; false otherwise.
+     *
+     * @param event config event
+     * @return true if event is supported; false otherwise
+     */
+    public boolean isSupported(DynamicConfigEvent event) {
+        ResourceId rsId = event.subject();
+        List<NodeKey> storeKeys = rsId.nodeKeys();
+        List<NodeKey> regKeys = id.nodeKeys();
+        List<NodeKey> sitesKeys = sites.nodeKeys();
+        if (storeKeys != null) {
+            int storeSize = storeKeys.size();
+            if (storeSize == 1) {
+                return storeKeys.get(0).equals(regKeys.get(1)) &&
+                        (event.type() == NODE_ADDED ||
+                                event.type() == NODE_DELETED);
+            } else if (storeSize == 2) {
+                return (storeKeys.get(0).equals(sitesKeys.get(1))) &&
+                        storeKeys.get(1).equals(sitesKeys.get(2)) &&
+                        (event.type() == NODE_ADDED ||
+                                event.type() == NODE_DELETED);
+            }
+        }
+        return false;
+    }
+
+    /***
+     * Creates all configuration in the standard device model.
+     *
+     * @param l3VpnSvc l3VPN service object
+     */
+    void createGlobalConfig(L3VpnSvc l3VpnSvc) {
+        if (l3VpnSvc.vpnServices() != null) {
+            createVpnServices(l3VpnSvc.vpnServices());
+        }
+        if (l3VpnSvc.sites() != null) {
+            createInterfaceConfig(l3VpnSvc.sites());
+        }
+    }
+
+    /**
+     * Creates the VPN instances from the VPN services object, if only that
+     * VPN instance is not already created.
+     *
+     * @param vpnSvcs VPN services object
+     */
+    private void createVpnServices(VpnServices vpnSvcs) {
+        if (vpnSvcs != null && vpnSvcs.vpnSvc() != null) {
+            List<VpnSvc> svcList = vpnSvcs.vpnSvc();
+            for (VpnSvc svc : svcList) {
+                String vpnName = svc.vpnId().string();
+                l3VpnStore.addVpnInsIfAbsent(vpnName, new VpnInstance(vpnName));
+            }
+        }
+    }
+
+    /**
+     * Creates interface configuration from the site network access if
+     * available.
+     *
+     * @param sites sites object
+     */
+    private void createInterfaceConfig(Sites sites) {
+        if (sites.site() != null) {
+            List<Site> sitesList = sites.site();
+            for (Site site : sitesList) {
+                if (site.siteNetworkAccesses() != null) {
+                    SiteNetworkAccesses accesses = site.siteNetworkAccesses();
+                    List<SiteNetworkAccess> accessList =
+                            accesses.siteNetworkAccess();
+                    for (SiteNetworkAccess access : accessList) {
+                        createFromAccess(access, site.siteId().string());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates the interface and VPN related configurations from the access
+     * and site id value.
+     *
+     * @param access site network access
+     * @param siteId site id
+     */
+    private void createFromAccess(SiteNetworkAccess access, String siteId) {
+        Map<AccessInfo, InterfaceInfo> intMap = l3VpnStore.getInterfaceInfo();
+        Map<String, VpnInstance> insMap = l3VpnStore.getVpnInstances();
+        String accessId = access.siteNetworkAccessId().string();
+        AccessInfo info = new AccessInfo(siteId, accessId);
+
+        if (intMap.get(info) == null) {
+            VpnSiteRole siteRole = getSiteRole(access.vpnAttachment());
+            VpnInstance instance = insMap.get(siteRole.name());
+            if (instance == null) {
+                throw new NetL3VpnException(SITE_VPN_MISMATCH);
+            }
+            buildFromAccess(instance, info, access, siteRole);
+        }
+    }
+
+    /**
+     * Returns the VPN site role from the VPN attachment.
+     *
+     * @param attach VPN attachment
+     * @return VPN site role
+     */
+    private VpnSiteRole getSiteRole(VpnAttachment attach) {
+        if (attach == null || attach.attachmentFlavor() == null) {
+            throw new NetL3VpnException(VPN_ATTACHMENT_NULL);
+        }
+        AttachmentFlavor flavor = attach.attachmentFlavor();
+        if (!(flavor instanceof DefaultVpnId)) {
+            throw new NetL3VpnException(VPN_POLICY_NOT_SUPPORTED);
+        }
+        DefaultVpnId vpnId = (DefaultVpnId) flavor;
+        if (vpnId.siteRole() == null) {
+            throw new NetL3VpnException(SITE_ROLE_NULL);
+        }
+        VpnType role = getRole(vpnId.siteRole());
+        return new VpnSiteRole(String.valueOf(vpnId.vpnId()), role);
+    }
+
+    /**
+     * Builds the required details for device standard model from the site
+     * network access info available.
+     *
+     * @param instance VPN instance
+     * @param info     access info
+     * @param access   network access
+     * @param role     VPN site role
+     */
+    private void buildFromAccess(VpnInstance instance, AccessInfo info,
+                                 SiteNetworkAccess access, VpnSiteRole role) {
+        Bearer bearer = access.bearer();
+        if (bearer == null) {
+            throw new NetL3VpnException(BEARER_NULL);
+        }
+
+        RequestedType reqType = bearer.requestedType();
+        IpConnection connect = access.ipConnection();
+        RoutingProtocols pro = access.routingProtocols();
+
+        if (reqType == null || connect == null) {
+            throw new NetL3VpnException(IP_INT_INFO_NULL);
+        }
+        buildDeviceDetails(instance, info, role, bearer, connect,
+                           reqType, pro);
+    }
+
+    /**
+     * Builds the device details such as, VPN instance value if it is for
+     * the first time, interface values and BGP info if available in service.
+     *
+     * @param instance VPN instance
+     * @param accInfo  access info
+     * @param role     VPN site role
+     * @param bearer   bearer object
+     * @param connect  ip connect object
+     * @param reqType  requested type
+     * @param pro      routing protocol
+     */
+    private void buildDeviceDetails(VpnInstance instance, AccessInfo accInfo,
+                                    VpnSiteRole role, Bearer bearer,
+                                    IpConnection connect, RequestedType reqType,
+                                    RoutingProtocols pro) {
+        Map<AccessInfo, InterfaceInfo> interMap = l3VpnStore.getInterfaceInfo();
+        InterfaceInfo intInfo = interMap.get(accInfo);
+        if (intInfo != null) {
+            return;
+        }
+
+        DeviceInfo info = buildDevVpnIns(bearer, instance, role, connect);
+        String portName = getInterfaceName(info, reqType);
+        buildDevVpnInt(info, instance, connect, portName, accInfo);
+
+        if (pro != null && pro.routingProtocol() != null) {
+            buildBgpInfo(pro.routingProtocol(), info,
+                         role.name(), connect, accInfo);
+        }
+        InterfaceInfo interInfo = new InterfaceInfo(info, portName,
+                                                    instance.vpnName());
+        l3VpnStore.addInterfaceInfo(accInfo, interInfo);
+        l3VpnStore.addVpnIns(instance.vpnName(), instance);
+    }
+
+    /**
+     * Builds device VPN instance with the service objects. It returns
+     *
+     * @param bearer  bearer object
+     * @param ins     VPN instance
+     * @param role    VPN site role
+     * @param connect ip connection
+     * @return return
+     */
+    private DeviceInfo buildDevVpnIns(Bearer bearer, VpnInstance ins,
+                                      VpnSiteRole role, IpConnection connect) {
+        DefaultAugmentedL3VpnBearer augBearer = ((DefaultBearer) bearer)
+                .augmentation(DefaultAugmentedL3VpnBearer.class);
+        DeviceId id = getDeviceId(augBearer);
+        Map<DeviceId, DeviceInfo> devices = ins.devInfo();
+        DeviceInfo info = null;
+        if (devices != null) {
+            info = devices.get(id);
+        }
+        if (info == null) {
+            info = createVpnInstance(id, role, ins, connect);
+        }
+        return info;
+    }
+
+    /**
+     * Returns the device id from the bearer augment attachment of service.
+     * If the attachment in augment is not available it throws error.
+     *
+     * @param attach augmented bearer
+     * @return device id
+     */
+    private DeviceId getDeviceId(DefaultAugmentedL3VpnBearer attach) {
+        if (attach == null || attach.bearerAttachment() == null ||
+                attach.bearerAttachment().peMgmtIp() == null ||
+                attach.bearerAttachment().peMgmtIp().string() == null) {
+            throw new NetL3VpnException(DEVICE_INFO_NULL);
+        }
+        String ip = attach.bearerAttachment().peMgmtIp().string();
+        return getId(ip);
+    }
+
+    /**
+     * Returns the device id whose management ip address matches with the ip
+     * received.
+     *
+     * @param ip ip address
+     * @return device id
+     */
+    public DeviceId getId(String ip) {
+        for (Device device : deviceService.getAvailableDevices()) {
+            String val = device.annotations().value(IP);
+            if (ip.equals(val)) {
+                return device.id();
+            }
+        }
+        throw new NetL3VpnException(getMgmtIpUnAvailErr(ip));
+    }
+
+    /**
+     * Creates the VPN instance by constructing standard device model of
+     * instances. It adds the RD and RT values to the VPN instance.
+     *
+     * @param id   device id
+     * @param role VPN site role
+     * @param inst VPN instance
+     * @param ip   ip connection
+     * @return device info
+     */
+    private DeviceInfo createVpnInstance(DeviceId id, VpnSiteRole role,
+                                         VpnInstance inst, IpConnection ip) {
+        Map<AccessInfo, InterfaceInfo> intMap = l3VpnStore.getInterfaceInfo();
+        generateRdRt(inst, role);
+        DeviceInfo info = new DeviceInfo(id);
+
+        NetworkInstances instances = createInstance(inst, role, ip);
+        ModelObjectData devMod = getVpnCreateModObj(intMap, instances,
+                                                    id.toString());
+        ModelObjectData driMod = info.processCreateInstance(driverService,
+                                                            devMod);
+        ResourceData resData = modelConverter.createDataNode(driMod);
+        addToStore(resData);
+        l3VpnStore.addVpnIns(inst.vpnName(), inst);
+        inst.addDevInfo(id, info);
+        return info;
+    }
+
+    /**
+     * Adds the resource data that is received from the driver, after
+     * converting from the model object data.
+     *
+     * @param resData resource data
+     */
+    private void addToStore(ResourceData resData) {
+        if (resData != null && resData.dataNodes() != null) {
+            List<DataNode> dataNodes = resData.dataNodes();
+            for (DataNode node : dataNodes) {
+                configService.createNodeRecursive(resData.resourceId(), node);
+            }
+        }
+    }
+
+    /**
+     * Generates RD and RT value for the VPN instance for the first time VPN
+     * instance creation.
+     *
+     * @param ins  VPN instance
+     * @param role VPN site role
+     */
+    private void generateRdRt(VpnInstance ins, VpnSiteRole role) {
+        ins.type(role.role());
+        VpnConfig config = ins.vpnConfig();
+        String rd = null;
+        if (config == null) {
+            rd = getIdFromGen();
+        }
+        switch (ins.type()) {
+            case ANY_TO_ANY:
+                if (config == null) {
+                    config = new FullMeshVpnConfig(rd);
+                    config.rd(rd);
+                }
+                break;
+
+            case HUB:
+            case SPOKE:
+                if (config == null) {
+                    config = new HubSpokeVpnConfig();
+                    config.rd(rd);
+                }
+                createImpRtVal((HubSpokeVpnConfig) config, ins.type());
+                createExpRtVal((HubSpokeVpnConfig) config, ins.type());
+                break;
+
+            default:
+                throw new NetL3VpnException(VPN_TYPE_UNSUPPORTED);
+        }
+        ins.vpnConfig(config);
+    }
+
+    /**
+     * Creates import RT value for HUB and SPOKE, according to the type, if
+     * the values are not present.
+     *
+     * @param config VPN config
+     * @param type   VPN type
+     */
+    private void createImpRtVal(HubSpokeVpnConfig config, VpnType type) {
+        if (type == HUB) {
+            if (config.hubImpRt() != null) {
+                return;
+            }
+            setHubImpRt(config);
+        } else {
+            if (config.spokeImpRt() != null) {
+                return;
+            }
+            config.spokeImpRt(config.rd());
+        }
+    }
+
+    /**
+     * Sets the HUB import RT, from the spoke export RT. If it is not
+     * available a new ID is generated.
+     *
+     * @param config VPN config
+     */
+    public void setHubImpRt(HubSpokeVpnConfig config) {
+        String hubImp;
+        if (config.spokeExpRt() != null) {
+            hubImp = config.spokeExpRt();
+        } else {
+            hubImp = getIdFromGen();
+        }
+        config.hubImpRt(hubImp);
+    }
+
+    /**
+     * Creates export RT value for HUB and SPOKE, according to the type, if
+     * the values are not present.
+     *
+     * @param config VPN config
+     * @param type   VPN type
+     */
+    private void createExpRtVal(HubSpokeVpnConfig config, VpnType type) {
+        if (type == HUB) {
+            if (config.hubExpRt() != null) {
+                return;
+            }
+            config.hubExpRt(config.rd());
+        } else {
+            if (config.spokeExpRt() != null) {
+                return;
+            }
+            setSpokeExpRt(config);
+        }
+    }
+
+    /**
+     * Sets the SPOKE export RT, from the hub import RT. If it is not
+     * available a new ID is generated.
+     *
+     * @param config VPN config
+     */
+    public void setSpokeExpRt(HubSpokeVpnConfig config) {
+        String spokeExp;
+        if (config.hubImpRt() != null) {
+            spokeExp = config.hubImpRt();
+        } else {
+            spokeExp = getIdFromGen();
+        }
+        config.spokeExpRt(spokeExp);
+    }
+
+    /**
+     * Returns the interface name from the requested type service object.
+     *
+     * @param info    device info
+     * @param reqType requested type
+     * @return interface name
+     */
+    private String getInterfaceName(DeviceInfo info, RequestedType reqType) {
+        DefaultAugmentedL3VpnRequestedType req =
+                ((DefaultRequestedType) reqType).augmentation(
+                        DefaultAugmentedL3VpnRequestedType.class);
+        if (req == null || req.requestedTypeProfile() == null ||
+                req.requestedTypeProfile().requestedTypeChoice() == null) {
+            throw new NetL3VpnException(INT_INFO_NULL);
+        }
+        RequestedTypeChoice reqChoice = req.requestedTypeProfile()
+                .requestedTypeChoice();
+        return getNameFromChoice(reqChoice, info.deviceId());
+    }
+
+    /**
+     * Returns the interface name from the type choice provided.
+     *
+     * @param choice service choice
+     * @param id     device id
+     * @return interface name
+     */
+    private String getNameFromChoice(RequestedTypeChoice choice, DeviceId id) {
+        if (choice == null) {
+            throw new NetL3VpnException(INT_INFO_NULL);
+        }
+        String intName;
+        if (choice instanceof DefaultDot1Qcase) {
+            if (((DefaultDot1Qcase) choice).dot1q() == null ||
+                    ((DefaultDot1Qcase) choice).dot1q()
+                            .physicalIf() == null) {
+                throw new NetL3VpnException(INT_INFO_NULL);
+            }
+            intName = ((DefaultDot1Qcase) choice).dot1q().physicalIf();
+        } else {
+            if (((DefaultPhysicalCase) choice).physical() == null ||
+                    ((DefaultPhysicalCase) choice).physical()
+                            .physicalIf() == null) {
+                throw new NetL3VpnException(INT_INFO_NULL);
+            }
+            intName = ((DefaultPhysicalCase) choice).physical().physicalIf();
+        }
+        return getPortName(intName, id);
+    }
+
+    /**
+     * Returns the port name when it the port is available in the device.
+     *
+     * @param intName interface name
+     * @param id      device id
+     * @return port name
+     */
+    private String getPortName(String intName, DeviceId id) {
+        List<Port> ports = deviceService.getPorts(id);
+        for (Port port : ports) {
+            String pName = port.annotations().value(PORT_NAME);
+            if (pName.equals(intName)) {
+                return intName;
+            }
+        }
+        throw new NetL3VpnException(getIntNotAvailable(intName));
+    }
+
+    /**
+     * Builds the interface for the device binding with the VPN instance.
+     *
+     * @param info    device info
+     * @param ins     VPN instance
+     * @param connect IP connection
+     * @param pName   port name
+     * @param access  access info
+     */
+    private void buildDevVpnInt(DeviceInfo info, VpnInstance ins,
+                                IpConnection connect, String pName,
+                                AccessInfo access) {
+        Map<AccessInfo, InterfaceInfo> intMap = l3VpnStore.getInterfaceInfo();
+        info.addAccessInfo(access);
+        info.addIfName(pName);
+        Interfaces interfaces = createInterface(pName, ins.vpnName(),
+                                                connect);
+        ModelObjectData devMod = getIntCreateModObj(
+                info.ifNames(), interfaces, info.deviceId().toString());
+        ModelObjectData driMod = info.processCreateInterface(driverService,
+                                                             devMod);
+        ResourceData resData = modelConverter.createDataNode(driMod);
+        addToStore(resData);
+    }
+
+    /**
+     * Builds the BGP information from the routes that are given from the
+     * service.
+     *
+     * @param routes  routing protocol
+     * @param info    device info
+     * @param name    VPN name
+     * @param connect IP connection
+     * @param access  access info
+     */
+    private void buildBgpInfo(List<RoutingProtocol> routes, DeviceInfo info,
+                              String name, IpConnection connect,
+                              AccessInfo access) {
+        Map<BgpInfo, DeviceId> bgpMap = l3VpnStore.getBgpInfo();
+        BgpInfo intBgp = createBgpInfo(routes, info, name, connect, access);
+        if (intBgp != null) {
+            intBgp.vpnName(name);
+            BgpDriverInfo config = getBgpCreateConfigObj(
+                    bgpMap, info.deviceId().toString(), info.bgpInfo(), intBgp);
+            ModelObjectData driData = info.processCreateBgpInfo(
+                    driverService, intBgp, config);
+            l3VpnStore.addBgpInfo(info.bgpInfo(), info.deviceId());
+            ResourceData resData = modelConverter.createDataNode(driData);
+            addToStore(resData);
+        }
+    }
+
+    /**
+     * Creates all configuration in the standard device model.
+     *
+     * @param l3VpnSvc l3 VPN service
+     */
+    void deleteGlobalConfig(L3VpnSvc l3VpnSvc) {
+        deleteGlobalVpn(l3VpnSvc);
+        //TODO: Site and access deletion needs to be added.
+    }
+
+    /**
+     * Deletes the global VPN from the device model and delete from the device.
+     *
+     * @param l3VpnSvc L3 VPN service
+     */
+    private void deleteGlobalVpn(L3VpnSvc l3VpnSvc) {
+        Map<String, VpnInstance> insMap = l3VpnStore.getVpnInstances();
+        //TODO: check for VPN delete deleting interface from store.
+        if (l3VpnSvc == null || l3VpnSvc.vpnServices() == null ||
+                l3VpnSvc.vpnServices().vpnSvc() == null) {
+            for (Map.Entry<String, VpnInstance> vpnMap : insMap.entrySet()) {
+                deleteVpnInstance(vpnMap.getValue(), false);
+            }
+            return;
+        }
+        List<VpnSvc> vpnList = l3VpnSvc.vpnServices().vpnSvc();
+        for (Map.Entry<String, VpnInstance> vpnMap : insMap.entrySet()) {
+            boolean isPresent = isVpnPresent(vpnMap.getKey(), vpnList);
+            if (!isPresent) {
+                deleteVpnInstance(vpnMap.getValue(), false);
+            }
+        }
+    }
+
+    /**
+     * Returns true if the VPN in the distributed map is also present in the
+     * service; false otherwise.
+     *
+     * @param vpnName VPN name from store
+     * @param vpnList VPN list from service
+     * @return true if VPN available; false otherwise
+     */
+    private boolean isVpnPresent(String vpnName, List<VpnSvc> vpnList) {
+        for (VpnSvc svc : vpnList) {
+            if (svc.vpnId().string().equals(vpnName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Deletes the VPN instance by constructing standard device model of
+     * instances.
+     *
+     * @param instance     VPN instance
+     * @param isIntDeleted if interface already removed.
+     */
+    private void deleteVpnInstance(VpnInstance instance, boolean isIntDeleted) {
+        Map<DeviceId, DeviceInfo> devices = instance.devInfo();
+        if (devices != null) {
+            for (Map.Entry<DeviceId, DeviceInfo> device : devices.entrySet()) {
+                NetworkInstances ins = deleteInstance(instance.vpnName());
+                DeviceInfo dev = device.getValue();
+                if (!isIntDeleted) {
+                    remVpnBgp(dev);
+                    remInterfaceFromMap(dev);
+                }
+                Map<AccessInfo, InterfaceInfo> intMap =
+                        l3VpnStore.getInterfaceInfo();
+                String id = dev.deviceId().toString();
+                ModelObjectData devMod = getVpnDelModObj(intMap, ins, id);
+                ModelObjectData driMod = dev.processDeleteInstance(
+                        driverService, devMod);
+                ResourceData resData = modelConverter.createDataNode(driMod);
+                deleteFromStore(resData);
+            }
+            l3VpnStore.removeVpnInstance(instance.vpnName());
+        }
+    }
+
+    /**
+     * Removes the BGP information for that complete VPN instance.
+     *
+     * @param dev device info
+     */
+    private void remVpnBgp(DeviceInfo dev) {
+        BgpInfo devBgp = dev.bgpInfo();
+        if (devBgp != null) {
+            l3VpnStore.removeBgpInfo(devBgp);
+            BgpInfo delInfo = new BgpInfo();
+            delInfo.vpnName(devBgp.vpnName());
+            String id = dev.deviceId().toString();
+            Map<BgpInfo, DeviceId> bgpMap = l3VpnStore.getBgpInfo();
+            BgpDriverInfo driConfig = getVpnBgpDelModObj(bgpMap, id);
+            ModelObjectData driData = dev.processDeleteBgpInfo(
+                    driverService, delInfo, driConfig);
+            ResourceData resData = modelConverter.createDataNode(driData);
+            deleteFromStore(resData);
+            l3VpnStore.removeBgpInfo(devBgp);
+        }
+    }
+
+    /**
+     * Deletes the resource data that is received from the driver, after
+     * converting from the model object data.
+     *
+     * @param resData resource data
+     */
+    private void deleteFromStore(ResourceData resData) {
+        if (resData != null) {
+            configService.deleteNodeRecursive(resData.resourceId());
+        }
+    }
+
+    /**
+     * Removes the interface from the app distributed map, if the driver
+     * interfaces are already removed from the store.
+     *
+     * @param deviceInfo device info
+     */
+    private void remInterfaceFromMap(DeviceInfo deviceInfo) {
+        List<AccessInfo> accesses = deviceInfo.accesses();
+        if (accesses != null) {
+            for (AccessInfo access : accesses) {
+                l3VpnStore.removeInterfaceInfo(access);
+            }
+        }
+        deviceInfo.ifNames(null);
+        deviceInfo.accesses(null);
+    }
+
+    /**
+     * Signals that the leadership has changed.
+     *
+     * @param isLeader true if this instance is now the leader, otherwise false
+     */
+    private void leaderChanged(boolean isLeader) {
+        log.debug("Leader changed: {}", isLeader);
+        isElectedLeader = isLeader;
+    }
+
+    /**
+     * Representation of internal listener, listening for dynamic config event.
+     */
+    private class InternalConfigListener implements DynamicConfigListener {
+
+        @Override
+        public boolean isRelevant(DynamicConfigEvent event) {
+            return isSupported(event);
+        }
+
+        @Override
+        public void event(DynamicConfigEvent event) {
+            accumulator.add(event);
+        }
+    }
+
+    /**
+     * Accumulates events to allow processing after a desired number of
+     * events were accumulated.
+     */
+    private class InternalEventAccumulator extends
+            AbstractAccumulator<DynamicConfigEvent> {
+
+        /**
+         * Constructs the event accumulator with timer and event limit.
+         */
+        protected InternalEventAccumulator() {
+            super(new Timer(TIMER), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
+        }
+
+        @Override
+        public void processItems(List<DynamicConfigEvent> events) {
+            for (DynamicConfigEvent event : events) {
+                checkNotNull(event, EVENT_NULL);
+                Filter filter = new Filter();
+                DataNode node;
+                try {
+                    node = configService.readNode(event.subject(), filter);
+                } catch (FailedException e) {
+                    node = null;
+                }
+                switch (event.type()) {
+                    case NODE_ADDED:
+                        processCreateFromStore(event.subject(), node);
+                        break;
+
+                    case NODE_DELETED:
+                        processDeleteFromStore(node);
+                        break;
+
+                    default:
+                        log.warn(UNKNOWN_EVENT, event.type());
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * A listener for leadership events.
+     */
+    private class InternalLeadershipListener implements LeadershipEventListener {
+
+        @Override
+        public boolean isRelevant(LeadershipEvent event) {
+            return event.subject().topic().equals(appId.name());
+        }
+
+        @Override
+        public void event(LeadershipEvent event) {
+            switch (event.type()) {
+                case LEADER_CHANGED:
+                case LEADER_AND_CANDIDATES_CHANGED:
+                    if (localNodeId.equals(event.subject().leaderNodeId())) {
+                        log.info("Net l3vpn manager gained leadership");
+                        leaderChanged(true);
+                    } else {
+                        log.info("Net l3vpn manager leader changed. New " +
+                                         "leader is {}", event.subject()
+                                         .leaderNodeId());
+                        leaderChanged(false);
+                    }
+                default:
+                    break;
+            }
+        }
+    }
+}