[ONOS-6191] NET L3VPN create operation support

Change-Id: I0ddbf88cae67fdaa0087551dd4b4d066dd3d6c22
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
index 107440c..4ccf0a1 100644
--- 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
@@ -13,7 +13,6 @@
  * 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;
@@ -21,11 +20,67 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.config.DynamicConfigEvent;
+import org.onosproject.config.DynamicConfigListener;
+import org.onosproject.config.DynamicConfigService;
 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.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;
@@ -36,7 +91,42 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
+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.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_NOT_SUPPORTED;
+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_INT_INFO_NULL;
+import static org.onosproject.l3vpn.netl3vpn.impl.NetL3VpnUtil.MG_MT_ADD;
+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.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.getVpnCreateModObj;
+import static org.onosproject.l3vpn.netl3vpn.VpnType.HUB;
 import static org.onosproject.yang.runtime.helperutils.YangApacheUtils.getYangModel;
 
 /**
@@ -47,26 +137,60 @@
 public class NetL3vpnManager {
 
     private static final String APP_ID = "org.onosproject.app.l3vpn";
+    private static final String L3_VPN_ID_TOPIC = "l3vpn-id";
+    private static final String ONOS_NET_L3VPN = "onos/netl3vpn";
+    private static final String EVENT_HANDLER = "event-handler-%d";
+
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     @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;
 
-    private ModelRegistrationParam regParam = null;
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ModelConverter modelConverter;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DynamicConfigService configService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetL3VpnStore l3VpnStore;
+
+    protected IdGenerator l3VpnIdGen;
+
+    private DynamicConfigListener configListener = new InternalConfigListener();
+
+    private ModelRegistrationParam regParam;
+
+    private ExecutorService executor = Executors.newSingleThreadExecutor(
+            groupedThreads(ONOS_NET_L3VPN, EVENT_HANDLER, log));
+
+    private ResourceId id;
+    private ResourceId module;
+    private ResourceId sites;
 
     @Activate
     protected void activate() {
         coreService.registerApplication(APP_ID);
+        l3VpnIdGen = coreService.getIdGenerator(L3_VPN_ID_TOPIC);
+        registerModel();
+        getResourceId();
+        configService.addListener(configListener);
         log.info("Started");
-        //TODO implementation
     }
 
     @Deactivate
     protected void deactivate() {
         modelRegistry.unregisterModel(regParam);
+        configService.removeListener(configListener);
         log.info("Stopped");
     }
 
@@ -105,4 +229,638 @@
         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()
+                .identifer(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
+     */
+    private void processCreateFromStore(ResourceId storeId) {
+        List<ModelObject> objects = getModelObjects(storeId, module);
+        for (ModelObject obj : objects) {
+            if (obj instanceof DefaultL3VpnSvc) {
+                DefaultL3VpnSvc l3VpnSvc = (DefaultL3VpnSvc) obj;
+                createGlobalConfig(l3VpnSvc);
+            }
+        }
+    }
+
+    /**
+     * Returns model objects of the store. The data node is read from the
+     * config store. This returns the resource id's node. So the node's
+     * parent resource id is taken and the data node is given to model
+     * converter.
+     *
+     * @param storeId store resource id
+     * @param appId   parent resource id
+     * @return model objects
+     */
+    public List<ModelObject> getModelObjects(ResourceId storeId,
+                                             ResourceId appId) {
+        DataNode dataNode = configService.readNode(storeId, null);
+        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();
+        if (storeKeys != null) {
+            if (storeKeys.size() == 1) {
+                return storeKeys.get(0).equals(regKeys.get(1)) &&
+                        (event.type() == NODE_ADDED ||
+                                event.type() == NODE_DELETED);
+            }
+        }
+        return false;
+    }
+
+    /***
+     * Creation of all configuration in 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());
+        VpnSiteRole vpnRole = new VpnSiteRole(
+                String.valueOf(vpnId.vpnId()), role);
+        return vpnRole;
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * 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(MG_MT_ADD);
+            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);
+        inst.addDevInfo(id, info);
+
+        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);
+        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(
+                intMap, 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());
+            ModelObjectData driData = info.processCreateBgpInfo(
+                    driverService, intBgp, config);
+            l3VpnStore.addBgpInfo(info.bgpInfo(), info.deviceId());
+            ResourceData resData = modelConverter.createDataNode(driData);
+            addToStore(resData);
+        }
+    }
+
+    /**
+     * 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) {
+            executor.execute(() -> {
+                try {
+                    ResourceId rsId = event.subject();
+                    switch (event.type()) {
+                        case NODE_ADDED:
+                            processCreateFromStore(rsId);
+                            break;
+
+                        case NODE_DELETED:
+                            //TODO: To be committed.
+                            break;
+
+                        default:
+                            throw new NetL3VpnException(EVENT_NOT_SUPPORTED);
+                    }
+                } catch (Exception e) {
+                    log.warn("Failed to process {}", event, e);
+                }
+            });
+        }
+    }
 }