| /* |
| * Copyright 2016-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.tetopology.management.impl; |
| |
| import static java.util.concurrent.Executors.newFixedThreadPool; |
| import static org.onlab.util.Tools.groupedThreads; |
| import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED; |
| import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED; |
| import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; |
| import static org.onosproject.tetopology.management.api.OptimizationType.NOT_OPTIMIZED; |
| import static org.onosproject.tetopology.management.api.TeTopology.BIT_CUSTOMIZED; |
| import static org.onosproject.tetopology.management.api.TeTopology.BIT_LEARNT; |
| import static org.onosproject.tetopology.management.api.TeTopology.BIT_MERGED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.LINK_ADDED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.LINK_REMOVED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.LINK_UPDATED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.NETWORK_ADDED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.NETWORK_REMOVED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.NODE_ADDED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.NODE_REMOVED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.NODE_UPDATED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_LINK_ADDED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_LINK_REMOVED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_LINK_UPDATED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_NODE_ADDED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_NODE_REMOVED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_NODE_UPDATED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_TOPOLOGY_ADDED; |
| import static org.onosproject.tetopology.management.api.TeTopologyEvent.Type.TE_TOPOLOGY_REMOVED; |
| import static org.onosproject.tetopology.management.impl.TeMgrUtil.linkBuilder; |
| import static org.onosproject.tetopology.management.impl.TeMgrUtil.networkBuilder; |
| import static org.onosproject.tetopology.management.impl.TeMgrUtil.networkLinkKey; |
| import static org.onosproject.tetopology.management.impl.TeMgrUtil.networkNodeKey; |
| import static org.onosproject.tetopology.management.impl.TeMgrUtil.nodeBuilder; |
| import static org.onosproject.tetopology.management.impl.TeMgrUtil.toNetworkId; |
| import static org.onosproject.tetopology.management.impl.TeMgrUtil.toNetworkLinkId; |
| |
| import java.util.BitSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.BlockingQueue; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.LinkedBlockingQueue; |
| |
| import org.apache.commons.collections.CollectionUtils; |
| import org.apache.commons.collections.MapUtils; |
| 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.apache.felix.scr.annotations.Service; |
| import org.onlab.packet.Ip4Address; |
| import org.onosproject.app.ApplicationException; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.core.CoreService; |
| import org.onosproject.incubator.net.config.basics.ConfigException; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.config.ConfigFactory; |
| import org.onosproject.net.config.NetworkConfigEvent; |
| import org.onosproject.net.config.NetworkConfigListener; |
| import org.onosproject.net.config.NetworkConfigRegistry; |
| import org.onosproject.net.device.DeviceProviderRegistry; |
| import org.onosproject.net.device.DeviceService; |
| import org.onosproject.net.link.LinkProviderRegistry; |
| import org.onosproject.net.link.LinkService; |
| import org.onosproject.net.provider.AbstractListenerProviderRegistry; |
| import org.onosproject.net.provider.AbstractProviderService; |
| import org.onosproject.tetopology.management.api.CommonTopologyData; |
| import org.onosproject.tetopology.management.api.DefaultNetwork; |
| import org.onosproject.tetopology.management.api.DefaultNetworks; |
| import org.onosproject.tetopology.management.api.DefaultTeTopologies; |
| import org.onosproject.tetopology.management.api.DefaultTeTopology; |
| import org.onosproject.tetopology.management.api.KeyId; |
| import org.onosproject.tetopology.management.api.Network; |
| import org.onosproject.tetopology.management.api.Networks; |
| import org.onosproject.tetopology.management.api.TeConstants; |
| import org.onosproject.tetopology.management.api.TeTopologies; |
| import org.onosproject.tetopology.management.api.TeTopology; |
| import org.onosproject.tetopology.management.api.TeTopologyEvent; |
| import org.onosproject.tetopology.management.api.TeTopologyKey; |
| import org.onosproject.tetopology.management.api.TeTopologyListener; |
| import org.onosproject.tetopology.management.api.TeTopologyProvider; |
| import org.onosproject.tetopology.management.api.TeTopologyProviderRegistry; |
| import org.onosproject.tetopology.management.api.TeTopologyProviderService; |
| import org.onosproject.tetopology.management.api.TeTopologyService; |
| import org.onosproject.tetopology.management.api.link.CommonLinkData; |
| import org.onosproject.tetopology.management.api.link.DefaultTeLink; |
| import org.onosproject.tetopology.management.api.link.ExternalLink; |
| import org.onosproject.tetopology.management.api.link.LinkBandwidth; |
| import org.onosproject.tetopology.management.api.link.NetworkLink; |
| import org.onosproject.tetopology.management.api.link.NetworkLinkEventSubject; |
| import org.onosproject.tetopology.management.api.link.NetworkLinkKey; |
| import org.onosproject.tetopology.management.api.link.TeLink; |
| import org.onosproject.tetopology.management.api.link.TeLinkEventSubject; |
| import org.onosproject.tetopology.management.api.link.TeLinkTpGlobalKey; |
| import org.onosproject.tetopology.management.api.link.TeLinkTpKey; |
| import org.onosproject.tetopology.management.api.link.TePathAttributes; |
| import org.onosproject.tetopology.management.api.link.UnderlayPath; |
| import org.onosproject.tetopology.management.api.node.CommonNodeData; |
| import org.onosproject.tetopology.management.api.node.ConnectivityMatrix; |
| import org.onosproject.tetopology.management.api.node.DefaultTeNode; |
| import org.onosproject.tetopology.management.api.node.NetworkNode; |
| import org.onosproject.tetopology.management.api.node.NetworkNodeEventSubject; |
| import org.onosproject.tetopology.management.api.node.NetworkNodeKey; |
| import org.onosproject.tetopology.management.api.node.TeNode; |
| import org.onosproject.tetopology.management.api.node.TeNodeEventSubject; |
| import org.onosproject.tetopology.management.api.node.TeNodeKey; |
| import org.onosproject.tetopology.management.api.node.TerminationPoint; |
| import org.onosproject.tetopology.management.api.node.TerminationPointKey; |
| import org.onosproject.tetopology.management.api.node.TtpKey; |
| import org.onosproject.tetopology.management.api.node.TunnelTerminationPoint; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.base.MoreObjects; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Maps; |
| |
| /** |
| * Implementation of the topology management service. |
| */ |
| @Component(immediate = true) |
| @Service |
| public class TeTopologyManager |
| extends AbstractListenerProviderRegistry<TeTopologyEvent, TeTopologyListener, |
| TeTopologyProvider, TeTopologyProviderService> |
| implements TeTopologyService, TeTopologyProviderRegistry { |
| private static final String APP_NAME = "org.onosproject.tetopology"; |
| private static final long DEFAULT_PROVIDER_ID = 77777; |
| private static final long DEFAULT_CLIENT_ID = 0x00L; |
| private long providerId = DEFAULT_PROVIDER_ID; |
| private static final int MAX_THREADS = 1; |
| private static final Ip4Address DEFAULT_TENODE_ID_START = Ip4Address.valueOf("10.10.10.10"); |
| private static final Ip4Address DEFAULT_TENODE_ID_END = Ip4Address.valueOf("250.250.250.250"); |
| private Ip4Address teNodeIpStart = DEFAULT_TENODE_ID_START; |
| private Ip4Address teNodeIpEnd = DEFAULT_TENODE_ID_END; |
| private long nextTeNodeId = teNodeIpStart.toInt(); |
| private boolean mdsc = true; |
| private static final String MDSC_MODE = "true"; |
| |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected CoreService coreService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected NetworkConfigRegistry cfgService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected DeviceService deviceService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected LinkService linkService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected DeviceProviderRegistry deviceProviderRegistry; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected LinkProviderRegistry linkProviderRegistry; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| public TeTopologyStore store; |
| |
| private TeTopologyStoreDelegate delegate = this::post; |
| private final BlockingQueue<TeTopologyEvent> eventQueue = new LinkedBlockingQueue<>(); |
| private final BlockingQueue<TeTopologyMapEvent> mapEventQueue = new LinkedBlockingQueue<>(); |
| private final ConfigFactory<ApplicationId, TeTopologyConfig> factory = |
| new ConfigFactory<ApplicationId, TeTopologyConfig>(APP_SUBJECT_FACTORY, |
| TeTopologyConfig.class, |
| "teTopologyCfg", |
| false) { |
| @Override |
| public TeTopologyConfig createConfig() { |
| return new TeTopologyConfig(); |
| } |
| }; |
| private final NetworkConfigListener cfgLister = new InternalConfigListener(); |
| private ApplicationId appId; |
| // The topology merged in MDSC |
| private TeTopology mergedTopology = null; |
| private TeTopologyKey mergedTopologyKey; |
| private Network mergedNetwork = null; |
| // Track new TE node id by its source TE node key |
| private Map<TeNodeKey, Long> sourceNewTeNodeIdMap = Maps.newHashMap(); |
| // Track the external link keys by the plugId |
| private Map<Long, LinkKeyPair> externalLinkMap = Maps.newHashMap(); |
| private ExecutorService executor; |
| |
| /** |
| * Activation helper function. |
| */ |
| public void activateBasics() { |
| store.setDelegate(delegate); |
| store.setMapEventQueue(mapEventQueue); |
| store.setProviderId(providerId); |
| eventDispatcher.addSink(TeTopologyEvent.class, listenerRegistry); |
| } |
| |
| /** |
| * Deactivation helper function. |
| */ |
| public void deactivateBasics() { |
| store.unsetDelegate(delegate); |
| eventDispatcher.removeSink(TeTopologyEvent.class); |
| } |
| |
| @Activate |
| public void activate() { |
| activateBasics(); |
| appId = coreService.registerApplication(APP_NAME); |
| cfgService.registerConfigFactory(factory); |
| executor = newFixedThreadPool(MAX_THREADS, groupedThreads("onos/tetopology", "build-%d", log)); |
| |
| cfgService.addListener(cfgLister); |
| executor.execute(new TopologyMergerTask()); |
| log.info("Started"); |
| } |
| |
| @Deactivate |
| public void deactivate() { |
| deactivateBasics(); |
| externalLinkMap.clear(); |
| cfgService.removeListener(cfgLister); |
| cfgService.unregisterConfigFactory(factory); |
| executor.shutdownNow(); |
| executor = null; |
| eventQueue.clear(); |
| log.info("Stopped"); |
| } |
| |
| @Override |
| protected TeTopologyProviderService createProviderService(TeTopologyProvider provider) { |
| return new InternalTopologyProviderService(provider); |
| } |
| |
| private class InternalTopologyProviderService |
| extends AbstractProviderService<TeTopologyProvider> |
| implements TeTopologyProviderService { |
| |
| protected InternalTopologyProviderService(TeTopologyProvider provider) { |
| super(provider); |
| } |
| |
| @Override |
| public void networkUpdated(Network network) { |
| store.updateNetwork(network); |
| } |
| |
| @Override |
| public void networkRemoved(KeyId networkId) { |
| store.removeNetwork(networkId); |
| } |
| |
| @Override |
| public void linkUpdated(NetworkLinkKey linkKey, NetworkLink link) { |
| store.updateNetworkLink(linkKey, link); |
| } |
| |
| @Override |
| public void linkRemoved(NetworkLinkKey linkKey) { |
| store.removeNetworkLink(linkKey); |
| } |
| |
| @Override |
| public void nodeUpdated(NetworkNodeKey nodeKey, NetworkNode node) { |
| store.updateNetworkNode(nodeKey, node); |
| } |
| |
| @Override |
| public void nodeRemoved(NetworkNodeKey nodeKey) { |
| store.removeNetworkNode(nodeKey); |
| } |
| |
| @Override |
| public void terminationPointUpdated(TerminationPointKey terminationPointKey, |
| TerminationPoint terminationPoint) { |
| store.updateTerminationPoint(terminationPointKey, terminationPoint); |
| } |
| |
| @Override |
| public void terminationPointRemoved(TerminationPointKey terminationPointKey) { |
| store.removeTerminationPoint(terminationPointKey); |
| } |
| } |
| |
| private boolean isCustomizedLearnedTopology(TeTopologyKey key) { |
| if (store.teTopology(key).flags().get(BIT_CUSTOMIZED) && |
| store.teTopology(key).flags().get(BIT_LEARNT)) { |
| return true; |
| } |
| return false; |
| } |
| |
| // Task for merge the learned topology. |
| private class TopologyMergerTask implements Runnable { |
| |
| public TopologyMergerTask() { |
| } |
| |
| @Override |
| public void run() { |
| try { |
| TeTopologyMapEvent event; |
| while ((event = mapEventQueue.take()) != null) { |
| switch (event.type()) { |
| case TE_TOPOLOGY_ADDED: |
| case TE_TOPOLOGY_UPDATED: |
| TeTopology teTopology = store.teTopology(event.teTopologyKey()); |
| post(new TeTopologyEvent(event.type(), teTopology)); |
| if (mdsc && event.type() == TE_TOPOLOGY_ADDED && |
| teTopology.flags().get(BIT_CUSTOMIZED) && |
| teTopology.flags().get(BIT_LEARNT)) { |
| log.debug("TeTopology to be merged: {}", teTopology); |
| mergeTopology(teTopology); |
| } |
| break; |
| case TE_TOPOLOGY_REMOVED: |
| post(new TeTopologyEvent(TE_TOPOLOGY_REMOVED, |
| new DefaultTeTopology(event.teTopologyKey(), |
| null, null, null, null))); |
| break; |
| case TE_NODE_ADDED: |
| case TE_NODE_UPDATED: |
| TeNode teNode = store.teNode(event.teNodeKey()); |
| post(new TeTopologyEvent(event.type(), |
| new TeNodeEventSubject(event.teNodeKey(), teNode))); |
| if (mdsc && isCustomizedLearnedTopology(event.teNodeKey().teTopologyKey())) { |
| updateSourceTeNode(mergedTopology.teNodes(), |
| event.teNodeKey().teTopologyKey(), teNode, true); |
| } |
| break; |
| case TE_NODE_REMOVED: |
| post(new TeTopologyEvent(TE_NODE_REMOVED, |
| new TeNodeEventSubject(event.teNodeKey(), null))); |
| if (mdsc && isCustomizedLearnedTopology(event.teNodeKey().teTopologyKey())) { |
| removeSourceTeNode(mergedTopology.teNodes(), event.teNodeKey(), true); |
| } |
| break; |
| case TE_LINK_ADDED: |
| case TE_LINK_UPDATED: |
| TeLink teLink = store.teLink(event.teLinkKey()); |
| post(new TeTopologyEvent(event.type(), |
| new TeLinkEventSubject(event.teLinkKey(), teLink))); |
| if (mdsc && isCustomizedLearnedTopology(event.teLinkKey().teTopologyKey())) { |
| Map<TeLinkTpKey, TeLink> teLinks = Maps.newHashMap(mergedTopology.teLinks()); |
| updateSourceTeLink(teLinks, event.teLinkKey().teTopologyKey(), teLink, true); |
| updateMergedTopology(mergedTopology.teNodes(), teLinks); |
| } |
| break; |
| case TE_LINK_REMOVED: |
| post(new TeTopologyEvent(TE_LINK_REMOVED, |
| new TeLinkEventSubject(event.teLinkKey(), null))); |
| if (mdsc && isCustomizedLearnedTopology(event.teLinkKey().teTopologyKey())) { |
| Map<TeLinkTpKey, TeLink> teLinks = Maps.newHashMap(mergedTopology.teLinks()); |
| removeSourceTeLink(teLinks, event.teLinkKey(), true); |
| updateMergedTopology(mergedTopology.teNodes(), teLinks); |
| } |
| break; |
| case NETWORK_ADDED: |
| case NETWORK_UPDATED: |
| Network network = store.network(event.networkKey()); |
| post(new TeTopologyEvent(event.type(), network)); |
| break; |
| case NETWORK_REMOVED: |
| post(new TeTopologyEvent(NETWORK_REMOVED, |
| new DefaultNetwork(event.networkKey(), |
| null, null, null, null, false, null))); |
| break; |
| case NODE_ADDED: |
| case NODE_UPDATED: |
| NetworkNode node = store.networkNode(event.networkNodeKey()); |
| post(new TeTopologyEvent(event.type(), |
| new NetworkNodeEventSubject(event.networkNodeKey(), node))); |
| break; |
| case NODE_REMOVED: |
| post(new TeTopologyEvent(NODE_REMOVED, |
| new NetworkNodeEventSubject(event.networkNodeKey(), null))); |
| break; |
| case LINK_ADDED: |
| case LINK_UPDATED: |
| NetworkLink link = store.networkLink(event.networkLinkKey()); |
| post(new TeTopologyEvent(event.type(), |
| new NetworkLinkEventSubject(event.networkLinkKey(), link))); |
| break; |
| case LINK_REMOVED: |
| post(new TeTopologyEvent(LINK_REMOVED, |
| new NetworkLinkEventSubject(event.networkLinkKey(), null))); |
| break; |
| default: |
| break; |
| } |
| } |
| } catch (InterruptedException e) { |
| log.warn("TopologyMergerTask is interrupted"); |
| } catch (Exception e) { |
| log.warn("Unable to merge topology", e); |
| } |
| } |
| } |
| |
| private void removeSourceTeNode(Map<Long, TeNode> teNodes, |
| TeNodeKey srcNodeKey, boolean postEvent) { |
| Long mergedTeNodeId = sourceNewTeNodeIdMap.remove(srcNodeKey); |
| if (mergedTeNodeId == null) { |
| return; |
| } |
| if (teNodes.remove(mergedTeNodeId) != null && postEvent) { |
| TeNodeKey nodeKey = new TeNodeKey(mergedTopologyKey, |
| mergedTeNodeId); |
| post(new TeTopologyEvent(TE_NODE_REMOVED, |
| new TeNodeEventSubject(nodeKey, null))); |
| post(new TeTopologyEvent(NODE_REMOVED, |
| new NetworkNodeEventSubject(TeMgrUtil |
| .networkNodeKey(nodeKey), null))); |
| } |
| } |
| |
| private void updateSourceTeNode(Map<Long, TeNode> teNodes, TeTopologyKey srcTopoKey, |
| TeNode srcNode, boolean postEvent) { |
| TeNodeKey sourceTeNodeId = new TeNodeKey(srcTopoKey, srcNode.teNodeId()); |
| Long mergedTeNodeId = sourceNewTeNodeIdMap.get(sourceTeNodeId); |
| boolean addNode = false; |
| if (mergedTeNodeId == null) { |
| // New node |
| addNode = true; |
| mergedTeNodeId = nextTeNodeId; |
| nextTeNodeId++; |
| if (nextTeNodeId >= teNodeIpEnd.toInt()) { |
| nextTeNodeId = teNodeIpStart.toInt(); |
| log.warn("TE node Id is wrapped back"); |
| } |
| sourceNewTeNodeIdMap.put(sourceTeNodeId, mergedTeNodeId); |
| } |
| TeTopologyKey underlayTopologyId = null; // No underlay |
| TeNodeKey supportTeNodeId = null; // No supporting |
| |
| CommonNodeData common = new CommonNodeData(srcNode.name(), srcNode.adminStatus(), |
| srcNode.opStatus(), srcNode.flags()); // No change |
| Map<Long, ConnectivityMatrix> connMatrices = srcNode.connectivityMatrices(); |
| List<Long> teLinkIds = srcNode.teLinkIds(); // No change |
| Map<Long, TunnelTerminationPoint> ttps = srcNode.tunnelTerminationPoints(); |
| List<Long> teTpIds = srcNode.teTerminationPointIds(); // No change |
| DefaultTeNode newNode = new DefaultTeNode(mergedTeNodeId, underlayTopologyId, |
| supportTeNodeId, sourceTeNodeId, common, connMatrices, teLinkIds, |
| ttps, teTpIds); |
| teNodes.put(mergedTeNodeId, newNode); |
| if (postEvent) { |
| //Post event for the TE node in the merged topology |
| TeNodeKey globalKey = new TeNodeKey(mergedTopologyKey, mergedTeNodeId); |
| post(new TeTopologyEvent(addNode ? TE_NODE_ADDED : TE_NODE_UPDATED, |
| new TeNodeEventSubject(globalKey, newNode))); |
| post(new TeTopologyEvent(addNode ? NODE_ADDED : NODE_UPDATED, |
| new NetworkNodeEventSubject(networkNodeKey(globalKey), |
| nodeBuilder(KeyId.keyId( |
| Ip4Address.valueOf((int) newNode.teNodeId()).toString()), |
| newNode)))); |
| } |
| } |
| |
| // Merge TE nodes |
| private void mergeNodes(Map<Long, TeNode> nodes, TeTopology topology) { |
| |
| if (!MapUtils.isEmpty(topology.teNodes())) { |
| for (Map.Entry<Long, TeNode> entry : topology.teNodes().entrySet()) { |
| updateSourceTeNode(nodes, topology.teTopologyId(), entry.getValue(), |
| mergedTopology != null); |
| } |
| } |
| } |
| |
| // Returns a new TeLink based on an existing TeLink with new attributes |
| private TeLink updateTeLink(TeLinkTpKey newKey, TeLinkTpKey peerTeLinkKey, |
| TeTopologyKey underlayTopologyId, TeLinkTpGlobalKey supportTeLinkId, |
| TeLinkTpGlobalKey sourceTeLinkId, ExternalLink externalLink, |
| TeLink exLink) { |
| UnderlayPath underlayPath = null; |
| if (underlayTopologyId != null && |
| underlayTopologyId.equals(exLink.underlayTeTopologyId())) { |
| underlayPath = new UnderlayPath(exLink.primaryPath(), |
| exLink.backupPaths(), exLink.tunnelProtectionType(), |
| exLink.sourceTtpId(), exLink.destinationTtpId(), |
| exLink.teTunnelId() |
| ); |
| } |
| |
| TePathAttributes teAttributes = new TePathAttributes(exLink.cost(), |
| exLink.delay(), exLink.srlgs()); |
| LinkBandwidth bandwidth = new LinkBandwidth(exLink.maxBandwidth(), |
| exLink.availBandwidth(), |
| exLink.maxAvailLspBandwidth(), |
| exLink.minAvailLspBandwidth(), |
| exLink.oduResource()); |
| CommonLinkData common = new CommonLinkData(exLink.adminStatus(), exLink.opStatus(), |
| exLink.flags(), exLink.switchingLayer(), exLink.encodingLayer(), |
| externalLink, underlayPath, teAttributes, |
| exLink.administrativeGroup(), exLink.interLayerLocks(), |
| bandwidth); |
| return new DefaultTeLink(newKey, peerTeLinkKey, underlayTopologyId, |
| supportTeLinkId, sourceTeLinkId, common); |
| } |
| |
| private class LinkKeyPair { |
| private TeLinkTpKey firstKey; |
| private TeLinkTpKey secondKey; |
| |
| public LinkKeyPair(TeLinkTpKey firstKey) { |
| this.firstKey = firstKey; |
| } |
| |
| public TeLinkTpKey firstKey() { |
| return firstKey; |
| } |
| |
| public void setFirstKey(TeLinkTpKey firstKey) { |
| this.firstKey = firstKey; |
| } |
| |
| public TeLinkTpKey secondKey() { |
| return secondKey; |
| } |
| |
| public void setSecondKey(TeLinkTpKey secondKey) { |
| this.secondKey = secondKey; |
| } |
| |
| public boolean isFirstKey(TeLinkTpKey linkKey) { |
| return firstKey == null ? false : firstKey.equals(linkKey); |
| } |
| |
| public boolean isSecondKey(TeLinkTpKey linkKey) { |
| return secondKey == null ? false : secondKey.equals(linkKey); |
| } |
| |
| public boolean isEmpty() { |
| return firstKey == null && secondKey == null; |
| } |
| |
| @Override |
| public String toString() { |
| return MoreObjects.toStringHelper(this) |
| .add("firstKey", firstKey) |
| .add("secondKey", secondKey) |
| .toString(); |
| } |
| } |
| |
| private void removeSourceTeLink(Map<TeLinkTpKey, TeLink> teLinks, TeLinkTpGlobalKey teLinkKey, |
| boolean postEvent) { |
| TeNodeKey sourceTeNodeKey = teLinkKey.teNodeKey(); |
| Long newTeNodeId = sourceNewTeNodeIdMap.get(sourceTeNodeKey); |
| if (newTeNodeId == null) { |
| return; |
| } |
| TeLinkTpKey newLinkKey = new TeLinkTpKey(newTeNodeId, teLinkKey.teLinkTpId()); |
| TeLink teLink = teLinks.remove(newLinkKey); |
| if (teLink == null) { |
| return; |
| } |
| //Post event |
| if (postEvent) { |
| TeLinkTpGlobalKey globalKey = new TeLinkTpGlobalKey(mergedTopologyKey, |
| newLinkKey); |
| post(new TeTopologyEvent(TE_LINK_REMOVED, |
| new TeLinkEventSubject(globalKey, null))); |
| post(new TeTopologyEvent(LINK_REMOVED, |
| new NetworkLinkEventSubject(networkLinkKey(globalKey), |
| null))); |
| } |
| |
| if (teLink.externalLink() != null && teLink.externalLink().plugId() != null) { |
| // Update the LinkKeyPair in externalLinkMap |
| LinkKeyPair pair = externalLinkMap.get(teLink.externalLink().plugId()); |
| if (pair.isFirstKey(newLinkKey)) { |
| pair.setFirstKey(null); |
| } else if (pair.isSecondKey(newLinkKey)) { |
| pair.setSecondKey(null); |
| } |
| if (pair.isEmpty()) { |
| externalLinkMap.remove(teLink.externalLink().plugId()); |
| } |
| } |
| TeLinkTpKey peerTeLinkKey = teLink.peerTeLinkKey(); |
| if (peerTeLinkKey != null) { |
| // Update peerLink's peerTeLinkKey to null |
| TeLink peerLink = teLinks.get(peerTeLinkKey); |
| if (peerLink == null || peerLink.peerTeLinkKey() == null) { |
| return; |
| } |
| TeLink newPeerLink = updateTeLink(peerTeLinkKey, null, |
| peerLink.underlayTeTopologyId(), peerLink.supportingTeLinkId(), |
| peerLink.sourceTeLinkId(), peerLink.externalLink(), peerLink); |
| teLinks.put(peerTeLinkKey, newPeerLink); |
| if (postEvent) { |
| TeLinkTpGlobalKey globalKey = new TeLinkTpGlobalKey(mergedTopologyKey, |
| peerTeLinkKey); |
| post(new TeTopologyEvent(TE_LINK_UPDATED, |
| new TeLinkEventSubject(globalKey, |
| newPeerLink))); |
| post(new TeTopologyEvent(LINK_UPDATED, |
| new NetworkLinkEventSubject(networkLinkKey(globalKey), |
| linkBuilder(toNetworkLinkId(peerTeLinkKey), |
| newPeerLink)))); |
| } |
| } |
| } |
| |
| private void updateSourceTeLink(Map<TeLinkTpKey, TeLink> teLinks, TeTopologyKey srcTopoKey, |
| TeLink srcLink, boolean postEvent) { |
| TeNodeKey sourceTeNodeId = new TeNodeKey(srcTopoKey, |
| srcLink.teLinkKey().teNodeId()); |
| TeLinkTpKey newKey = new TeLinkTpKey( |
| sourceNewTeNodeIdMap.get(sourceTeNodeId), |
| srcLink.teLinkKey().teLinkTpId()); |
| TeLinkTpKey peerTeLinkKey = null; |
| if (srcLink.peerTeLinkKey() != null) { |
| TeNodeKey sourcePeerNode = new TeNodeKey(srcTopoKey, |
| srcLink.peerTeLinkKey().teNodeId()); |
| peerTeLinkKey = new TeLinkTpKey( |
| sourceNewTeNodeIdMap.get(sourcePeerNode), |
| srcLink.peerTeLinkKey().teLinkTpId()); |
| } |
| |
| if (srcLink.externalLink() != null && |
| srcLink.externalLink().plugId() != null) { |
| // externalLinkKey doesn't have topology Id. |
| // using plugId for now |
| LinkKeyPair pair = externalLinkMap.get(srcLink.externalLink().plugId()); |
| if (pair == null) { |
| // Store it in the map |
| externalLinkMap.put(srcLink.externalLink().plugId(), |
| new LinkKeyPair(newKey)); |
| } else { |
| if (newKey.equals(pair.firstKey())) { |
| peerTeLinkKey = pair.secondKey(); |
| } else if (newKey.equals(pair.secondKey())) { |
| peerTeLinkKey = pair.firstKey(); |
| } else if (pair.firstKey() == null) { |
| peerTeLinkKey = pair.secondKey(); |
| pair.setFirstKey(newKey); |
| } else if (pair.secondKey() == null) { |
| peerTeLinkKey = pair.firstKey(); |
| pair.setSecondKey(newKey); |
| } |
| |
| if (peerTeLinkKey != null) { |
| TeLink peerLink = teLinks.get(peerTeLinkKey); |
| if (peerLink != null && (peerLink.peerTeLinkKey() == null |
| || !peerLink.peerTeLinkKey().equals(newKey))) { |
| // Update peer Link with local link key |
| TeLink newPeerLink = updateTeLink(peerTeLinkKey, newKey, |
| peerLink.underlayTeTopologyId(), |
| peerLink.supportingTeLinkId(), |
| peerLink.sourceTeLinkId(), |
| peerLink.externalLink(), |
| peerLink); |
| teLinks.put(peerTeLinkKey, newPeerLink); |
| if (postEvent) { |
| TeLinkTpGlobalKey globalKey = new TeLinkTpGlobalKey(mergedTopologyKey, |
| peerTeLinkKey); |
| post(new TeTopologyEvent(TE_LINK_UPDATED, |
| new TeLinkEventSubject(globalKey, |
| newPeerLink))); |
| post(new TeTopologyEvent(LINK_UPDATED, |
| new NetworkLinkEventSubject( |
| networkLinkKey(globalKey), |
| linkBuilder(toNetworkLinkId(peerTeLinkKey), |
| newPeerLink)))); |
| } |
| } |
| } |
| } |
| } |
| |
| TeTopologyKey underlayTopologyId = null; // No underlay |
| TeLinkTpGlobalKey supportTeLinkId = null; // No support |
| // Source link for the new updated link |
| TeLinkTpGlobalKey sourceTeLinkId = new TeLinkTpGlobalKey(srcTopoKey, srcLink.teLinkKey()); |
| TeLink updatedLink = updateTeLink(newKey, peerTeLinkKey, underlayTopologyId, |
| supportTeLinkId, sourceTeLinkId, |
| srcLink.externalLink(), srcLink); |
| TeLinkTpGlobalKey newGlobalKey = new TeLinkTpGlobalKey(mergedTopologyKey, newKey); |
| boolean newLink = teLinks.get(newKey) == null ? true : false; |
| teLinks.put(newKey, updatedLink); |
| if (postEvent) { |
| //Post event |
| post(new TeTopologyEvent(newLink ? TE_LINK_ADDED : TE_LINK_UPDATED, |
| new TeLinkEventSubject(newGlobalKey, updatedLink))); |
| post(new TeTopologyEvent(newLink ? LINK_ADDED : LINK_UPDATED, |
| new NetworkLinkEventSubject(networkLinkKey(newGlobalKey), |
| linkBuilder(toNetworkLinkId(updatedLink.teLinkKey()), |
| updatedLink)))); |
| } |
| } |
| |
| // Merge TE links |
| private void mergeLinks(Map<TeLinkTpKey, TeLink> teLinks, TeTopology topology) { |
| if (!MapUtils.isEmpty(topology.teLinks())) { |
| for (Map.Entry<TeLinkTpKey, TeLink> entry : topology.teLinks().entrySet()) { |
| TeLink srcLink = entry.getValue(); |
| updateSourceTeLink(teLinks, topology.teTopologyId(), srcLink, |
| mergedTopology != null); |
| } |
| } |
| } |
| |
| // Update the merged topology with new TE nodes and links |
| private void updateMergedTopology(Map<Long, TeNode> teNodes, Map<TeLinkTpKey, TeLink> teLinks) { |
| boolean newTopology = mergedTopology == null; |
| BitSet flags = newTopology ? new BitSet(TeConstants.FLAG_MAX_BITS) : mergedTopology.flags(); |
| flags.set(BIT_MERGED); |
| CommonTopologyData commonData = new CommonTopologyData(newTopology ? |
| toNetworkId(mergedTopologyKey) : |
| mergedTopology.networkId(), |
| NOT_OPTIMIZED, |
| flags, DeviceId.deviceId("localHost")); |
| mergedTopology = new DefaultTeTopology(mergedTopologyKey, teNodes, teLinks, |
| Long.toString(mergedTopologyKey.topologyId()), commonData); |
| mergedNetwork = networkBuilder(mergedTopology); |
| log.info("Nodes# {}, Links# {}", mergedTopology.teNodes().size(), mergedTopology.teLinks().size()); |
| } |
| |
| // Merge the new learned topology |
| private void mergeTopology(TeTopology topology) { |
| boolean newTopology = mergedTopology == null; |
| mergedTopologyKey = newTopology ? |
| new TeTopologyKey(providerId, DEFAULT_CLIENT_ID, |
| store.nextTeTopologyId()) : |
| mergedTopology.teTopologyId(); |
| |
| Map<Long, TeNode> teNodes = newTopology || mergedTopology.teNodes() == null ? |
| Maps.newHashMap() : Maps.newHashMap(mergedTopology.teNodes()); |
| mergeNodes(teNodes, topology); |
| Map<TeLinkTpKey, TeLink> teLinks = newTopology || mergedTopology.teLinks() == null ? |
| Maps.newHashMap() : Maps.newHashMap(mergedTopology.teLinks()); |
| mergeLinks(teLinks, topology); |
| updateMergedTopology(teNodes, teLinks); |
| log.debug("mergedTopology {}", mergedTopology); |
| |
| if (newTopology) { |
| // Post events for the merged network topology; |
| post(new TeTopologyEvent(TE_TOPOLOGY_ADDED, mergedTopology)); |
| post(new TeTopologyEvent(NETWORK_ADDED, mergedNetwork)); |
| } |
| } |
| |
| private TeTopologyKey newTeTopologyKey(TeTopology teTopology) { |
| TeTopologyKey key = teTopology.teTopologyId(); |
| if (key == null || teTopology.teTopologyIdStringValue() == null) { |
| log.error("Ignoring the non-TE topology"); |
| throw new ApplicationException("Missing TE topology ID"); |
| } |
| // Get the topologyId numeric value |
| long idValue = key.topologyId(); |
| if (idValue == TeConstants.NIL_LONG_VALUE) { |
| if (teTopology.teTopologyIdStringValue() != null) { |
| try { |
| idValue = Long.parseLong(teTopology.teTopologyIdStringValue()); |
| } catch (NumberFormatException e) { |
| // Can't get the long value from the string. |
| // Use an assigned id value from local id pool, |
| idValue = store.nextTeTopologyId(); |
| } |
| return new TeTopologyKey(key.providerId(), key.clientId(), idValue); |
| } |
| } |
| return null; |
| } |
| |
| private class InternalConfigListener implements NetworkConfigListener { |
| |
| @Override |
| public void event(NetworkConfigEvent event) { |
| try { |
| providerId = cfgService.getConfig(appId, TeTopologyConfig.class) |
| .providerId(); |
| store.setProviderId(providerId); |
| teNodeIpStart = cfgService.getConfig(appId, TeTopologyConfig.class) |
| .teNodeIpStart(); |
| teNodeIpEnd = cfgService.getConfig(appId, TeTopologyConfig.class) |
| .teNodeIpEnd(); |
| mdsc = cfgService.getConfig(appId, TeTopologyConfig.class) |
| .mdsc().equalsIgnoreCase(MDSC_MODE); |
| nextTeNodeId = teNodeIpStart.toInt(); |
| } catch (ConfigException e) { |
| log.error("Configuration error {}", e); |
| } |
| } |
| |
| |
| @Override |
| public boolean isRelevant(NetworkConfigEvent event) { |
| return event.configClass().equals(TeTopologyConfig.class) && |
| (event.type() == CONFIG_ADDED || |
| event.type() == CONFIG_UPDATED); |
| } |
| } |
| |
| @Override |
| public TeTopologies teTopologies() { |
| Map<TeTopologyKey, TeTopology> map; |
| if (MapUtils.isNotEmpty(store.teTopologies().teTopologies())) { |
| map = Maps.newHashMap(store.teTopologies().teTopologies()); |
| } else { |
| map = Maps.newHashMap(); |
| } |
| if (mergedTopology != null) { |
| map.put(mergedTopologyKey, mergedTopology); |
| } |
| return new DefaultTeTopologies(store.teTopologies().name(), map); |
| } |
| |
| @Override |
| public TeTopology teTopology(TeTopologyKey topologyId) { |
| if (mergedTopology != null && |
| topologyId.equals(mergedTopologyKey)) { |
| return mergedTopology; |
| } |
| return store.teTopology(topologyId); |
| } |
| |
| @Override |
| public TeTopology mergedTopology() { |
| return mergedTopology; |
| } |
| |
| @Override |
| public void updateTeTopology(TeTopology teTopology) { |
| TeTopologyKey newKey = null; |
| try { |
| newKey = newTeTopologyKey(teTopology); |
| } catch (ApplicationException e) { |
| log.error("Ignoring the non-TE topology"); |
| return; |
| } |
| |
| // TE topology is updated here from other APP or NBI, the flag |
| // BIT_CUSTOMIZED or BIT_MERGED should be set. |
| BitSet flags = teTopology.flags(); |
| if (flags == null || |
| !(flags.get(BIT_CUSTOMIZED) || flags.get(BIT_MERGED))) { |
| log.error("TE topology flags {} are not set properly", flags); |
| return; |
| } |
| |
| if (newKey != null) { |
| DefaultTeTopology newTopology = new DefaultTeTopology( |
| newKey == null ? teTopology.teTopologyId() : newKey, |
| teTopology.teNodes(), teTopology.teLinks(), |
| teTopology.teTopologyIdStringValue(), new CommonTopologyData(teTopology)); |
| // Update with new data |
| store.updateTeTopology(newTopology); |
| } else { |
| store.updateTeTopology(teTopology); |
| } |
| } |
| |
| @Override |
| public void removeTeTopology(TeTopologyKey topologyId) { |
| store.removeTeTopology(topologyId); |
| } |
| |
| @Override |
| public Networks networks() { |
| List<Network> networks; |
| if (CollectionUtils.isNotEmpty(store.networks())) { |
| networks = Lists.newArrayList(store.networks()); |
| } else { |
| networks = Lists.newArrayList(); |
| } |
| if (mergedNetwork != null) { |
| networks.add(mergedNetwork); |
| } |
| return new DefaultNetworks(networks); |
| } |
| |
| @Override |
| public Network network(KeyId networkId) { |
| if (mergedNetwork != null && |
| mergedNetwork.networkId().equals(networkId)) { |
| return mergedNetwork; |
| } |
| return store.network(networkId); |
| } |
| |
| @Override |
| public void updateNetwork(Network network) { |
| // TODO: This will be implemented if required. |
| } |
| |
| @Override |
| public void removeNetwork(KeyId networkId) { |
| // TODO: This will be implemented if required. |
| } |
| |
| @Override |
| public TeNode teNode(TeNodeKey nodeId) { |
| return nodeId.teTopologyKey().equals(mergedTopologyKey) ? |
| mergedTopology.teNode(nodeId.teNodeId()) : |
| store.teNode(nodeId); |
| } |
| |
| @Override |
| public TeLink teLink(TeLinkTpGlobalKey linkId) { |
| return linkId.teTopologyKey().equals(mergedTopologyKey) ? |
| mergedTopology.teLink(linkId.teLinkTpKey()) : |
| store.teLink(linkId); |
| } |
| |
| @Override |
| public TunnelTerminationPoint tunnelTerminationPoint(TtpKey ttpId) { |
| return ttpId.teTopologyKey().equals(mergedTopologyKey) ? |
| mergedTopology.teNode(ttpId.teNodeId()).tunnelTerminationPoint(ttpId.ttpId()) : |
| store.tunnelTerminationPoint(ttpId); |
| } |
| |
| @Override |
| public KeyId networkId(TeTopologyKey teTopologyKey) { |
| return teTopologyKey.equals(mergedTopologyKey) ? |
| mergedNetwork.networkId() : |
| store.networkId(teTopologyKey); |
| } |
| |
| @Override |
| public NetworkNodeKey nodeKey(TeNodeKey teNodeKey) { |
| return teNodeKey.teTopologyKey().equals(mergedTopologyKey) ? |
| networkNodeKey(teNodeKey) : |
| store.nodeKey(teNodeKey); |
| } |
| |
| @Override |
| public NetworkLinkKey linkKey(TeLinkTpGlobalKey teLinkKey) { |
| return teLinkKey.teTopologyKey().equals(mergedTopologyKey) ? |
| networkLinkKey(teLinkKey) : |
| store.linkKey(teLinkKey); |
| } |
| |
| @Override |
| public TerminationPointKey terminationPointKey(TeLinkTpGlobalKey teTpKey) { |
| return teTpKey.teTopologyKey().equals(mergedTopologyKey) ? |
| new TerminationPointKey(networkNodeKey(teTpKey.teNodeKey()), |
| KeyId.keyId(Long.toString(teTpKey.teLinkTpId()))) : |
| store.terminationPointKey(teTpKey); |
| } |
| } |