X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=applications%2Ftopology-lldp-discovery%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fapplications%2Ftopology%2Flldp%2FLLDPLinkAger.java;h=2c2a181bbe54604986539cdb269b884216072b62;hb=777c94332871b8c34f56f7f2010de1536cb759ba;hp=4d54328dd6f14a00e49cbe023a76eefec69102ac;hpb=8277a6525b364d667be7a16b6b75589d33b7e2e1;p=openflowplugin.git diff --git a/applications/topology-lldp-discovery/src/main/java/org/opendaylight/openflowplugin/applications/topology/lldp/LLDPLinkAger.java b/applications/topology-lldp-discovery/src/main/java/org/opendaylight/openflowplugin/applications/topology/lldp/LLDPLinkAger.java index 4d54328dd6..2c2a181bbe 100644 --- a/applications/topology-lldp-discovery/src/main/java/org/opendaylight/openflowplugin/applications/topology/lldp/LLDPLinkAger.java +++ b/applications/topology-lldp-discovery/src/main/java/org/opendaylight/openflowplugin/applications/topology/lldp/LLDPLinkAger.java @@ -8,56 +8,84 @@ package org.opendaylight.openflowplugin.applications.topology.lldp; import com.google.common.annotations.VisibleForTesting; +import java.util.Collection; import java.util.Date; -import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; -import javax.annotation.Nonnull; +import java.util.concurrent.ConcurrentMap; import javax.annotation.PreDestroy; import javax.inject.Inject; import javax.inject.Singleton; -import org.apache.aries.blueprint.annotation.service.Reference; -import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.DataObjectModification; +import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; +import org.opendaylight.mdsal.binding.api.DataTreeModification; +import org.opendaylight.mdsal.binding.api.NotificationPublishService; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService; import org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationListener; import org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationService; import org.opendaylight.openflowplugin.applications.topology.lldp.utils.LLDPDiscoveryUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscovered; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemovedBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.lldp.discovery.config.rev160511.TopologyLldpDiscoveryConfig; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton -public class LLDPLinkAger implements ConfigurationListener, AutoCloseable { +public final class LLDPLinkAger implements ConfigurationListener, ClusteredDataTreeChangeListener, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(LLDPLinkAger.class); + static final String TOPOLOGY_ID = "flow:1"; + static final InstanceIdentifier II_TO_LINK = InstanceIdentifier.create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID))).child(Link.class); + private final long linkExpirationTime; - private final Map linkToDate; - private final Timer timer; - private final NotificationProviderService notificationService; + // FIXME: use Instant instead of Date + private final ConcurrentMap linkToDate = new ConcurrentHashMap<>(); + private final Timer timer = new Timer(); + private final NotificationPublishService notificationService; private final AutoCloseable configurationServiceRegistration; private final EntityOwnershipService eos; + private ListenerRegistration listenerRegistration; /** * default ctor - start timer. */ @Inject + @SuppressWarnings("checkstyle:IllegalCatch") public LLDPLinkAger(final TopologyLldpDiscoveryConfig topologyLldpDiscoveryConfig, - @Reference final NotificationProviderService notificationService, - @Reference final ConfigurationService configurationService, - @Reference final EntityOwnershipService entityOwnershipService) { - this.linkExpirationTime = topologyLldpDiscoveryConfig.getTopologyLldpExpirationInterval().getValue(); + final NotificationPublishService notificationService, + final ConfigurationService configurationService, + final EntityOwnershipService entityOwnershipService, + final DataBroker dataBroker) { + linkExpirationTime = topologyLldpDiscoveryConfig.getTopologyLldpExpirationInterval().getValue().toJava(); this.notificationService = notificationService; - this.configurationServiceRegistration = configurationService.registerListener(this); - this.eos = entityOwnershipService; - linkToDate = new ConcurrentHashMap<>(); - timer = new Timer(); - timer.schedule(new LLDPAgingTask(), 0, topologyLldpDiscoveryConfig.getTopologyLldpInterval().getValue()); + configurationServiceRegistration = configurationService.registerListener(this); + eos = entityOwnershipService; + final DataTreeIdentifier dtiToNodeConnector = DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, + II_TO_LINK); + try { + listenerRegistration = dataBroker.registerDataTreeChangeListener(dtiToNodeConnector, LLDPLinkAger.this); + } catch (Exception e) { + LOG.error("DataTreeChangeListeners registration failed:", e); + throw new IllegalStateException("LLDPLinkAger startup failed!", e); + } + timer.schedule(new LLDPAgingTask(), 0, + topologyLldpDiscoveryConfig.getTopologyLldpInterval().getValue().toJava()); } public void put(LinkDiscovered link) { @@ -69,13 +97,68 @@ public class LLDPLinkAger implements ConfigurationListener, AutoCloseable { @Override @PreDestroy public void close() throws Exception { + if (listenerRegistration != null) { + listenerRegistration.close(); + listenerRegistration = null; + } timer.cancel(); linkToDate.clear(); configurationServiceRegistration.close(); } - private class LLDPAgingTask extends TimerTask { + @Override + public void onDataTreeChanged(@NonNull Collection> changes) { + for (DataTreeModification modification : changes) { + switch (modification.getRootNode().getModificationType()) { + case WRITE: + break; + case SUBTREE_MODIFIED: + // NOOP + break; + case DELETE: + processLinkDeleted(modification.getRootNode()); + break; + default: + LOG.error("Unhandled modification type: {}", modification.getRootNode().getModificationType()); + } + } + } + + @VisibleForTesting + public boolean isLinkToDateEmpty() { + return linkToDate.isEmpty(); + } + @Override + public void onPropertyChanged(@NonNull final String propertyName, @NonNull final String propertyValue) { + final TopologyLLDPDiscoveryProperty lldpDiscoveryProperty = TopologyLLDPDiscoveryProperty.forValue( + propertyName); + if (lldpDiscoveryProperty != null) { + switch (lldpDiscoveryProperty) { + case LLDP_SECURE_KEY: + case TOPOLOGY_LLDP_INTERVAL: + case TOPOLOGY_LLDP_EXPIRATION_INTERVAL: + LOG.warn("Runtime update not supported for property {}", lldpDiscoveryProperty); + break; + default: + LOG.warn("No topology lldp discovery property found."); + break; + } + } + } + + protected boolean isLinkPresent(final LinkDiscovered linkDiscovered) { + return linkToDate.containsKey(linkDiscovered); + } + + private void processLinkDeleted(DataObjectModification rootNode) { + Link link = rootNode.getDataBefore(); + LOG.trace("Removing link {} from linkToDate cache", link); + LinkDiscovered linkDiscovered = LLDPDiscoveryUtils.toLLDPLinkDiscovered(link); + linkToDate.remove(linkDiscovered); + } + + private class LLDPAgingTask extends TimerTask { @Override public void run() { for (Entry entry : linkToDate.entrySet()) { @@ -85,14 +168,18 @@ public class LLDPLinkAger implements ConfigurationListener, AutoCloseable { if (now.after(expires)) { if (notificationService != null) { LinkRemovedBuilder lrb = new LinkRemovedBuilder(link); - NodeKey nodeKey = link.getDestination().getValue().firstKeyOf(Node.class); LOG.info("No update received for link {} from last {} milliseconds. Removing link from cache.", link, linkExpirationTime); linkToDate.remove(link); if (nodeKey != null && LLDPDiscoveryUtils.isEntityOwned(eos, nodeKey.getId().getValue())) { LOG.info("Publish Link Remove event for the link {}", link); - notificationService.publish(lrb.build()); + final LinkRemoved lr = lrb.build(); + try { + notificationService.putNotification(lr); + } catch (InterruptedException e) { + LOG.warn("Interrupted while publishing notification {}", lr, e); + } } else { LOG.trace("Skip publishing Link Remove event for the link {} because link destination " + "node is not owned by the controller", link); @@ -102,29 +189,4 @@ public class LLDPLinkAger implements ConfigurationListener, AutoCloseable { } } } - - @VisibleForTesting - public boolean isLinkToDateEmpty() { - return linkToDate.isEmpty(); - } - - @Override - public void onPropertyChanged(@Nonnull final String propertyName, @Nonnull final String propertyValue) { - Optional.ofNullable(TopologyLLDPDiscoveryProperty.forValue(propertyName)).ifPresent(lldpDiscoveryProperty -> { - switch (lldpDiscoveryProperty) { - case LLDP_SECURE_KEY: - LOG.warn("Runtime update not supported for property {}", lldpDiscoveryProperty); - break; - case TOPOLOGY_LLDP_INTERVAL: - LOG.warn("Runtime update not supported for property {}", lldpDiscoveryProperty); - break; - case TOPOLOGY_LLDP_EXPIRATION_INTERVAL: - LOG.warn("Runtime update not supported for property {}", lldpDiscoveryProperty); - break; - default: - LOG.warn("No topology lldp discovery property found."); - break; - } - }); - } }