/* * 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.interfaces.rev20140508.ietfinterfaces.devices.device.Interfaces; 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.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.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; /** * 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 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 ResourceId id; private ResourceId module; private ResourceId sites; private boolean isElectedLeader; @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()); getResourceId(); configService.addListener(configListener); log.info("Started"); } @Deactivate protected void deactivate() { configService.removeListener(configListener); leadershipService.withdraw(appId.name()); leadershipService.removeListener(leadershipEventListener); log.info("Stopped"); } /** * 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; } } } }