[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);
+ }
+ });
+ }
+ }
}