diff options
Diffstat (limited to 'framework/src/onos/providers/lldp')
5 files changed, 12 insertions, 1275 deletions
diff --git a/framework/src/onos/providers/lldp/pom.xml b/framework/src/onos/providers/lldp/pom.xml index e47d26c7..7bf92ed2 100644 --- a/framework/src/onos/providers/lldp/pom.xml +++ b/framework/src/onos/providers/lldp/pom.xml @@ -30,7 +30,11 @@ <artifactId>onos-lldp-provider</artifactId> <packaging>bundle</packaging> - <description>ONOS LLDP Link Discovery</description> + <properties> + <onos.app.name>org.onosproject.lldpprovider</onos.app.name> + </properties> + + <description>ONOS LLDP link provider</description> <dependencies> <dependency> diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/DiscoveryContext.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/DiscoveryContext.java index 0cd19242..a9da92ab 100644 --- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/DiscoveryContext.java +++ b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/DiscoveryContext.java @@ -58,7 +58,7 @@ interface DiscoveryContext { * * @return true to emit BDDP */ - boolean useBDDP(); + boolean useBddp(); /** * Touches the link identified by the given key to indicate that it's active. diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java deleted file mode 100644 index 98442033..00000000 --- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Copyright 2014-2015 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.provider.lldp.impl; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; -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.Modified; -import org.apache.felix.scr.annotations.Property; -import org.apache.felix.scr.annotations.Reference; -import org.apache.felix.scr.annotations.ReferenceCardinality; -import org.onlab.packet.Ethernet; -import org.onosproject.cfg.ComponentConfigService; -import org.onosproject.cluster.ClusterService; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.mastership.MastershipEvent; -import org.onosproject.mastership.MastershipListener; -import org.onosproject.mastership.MastershipService; -import org.onosproject.net.ConnectPoint; -import org.onosproject.net.Device; -import org.onosproject.net.DeviceId; -import org.onosproject.net.LinkKey; -import org.onosproject.net.Port; -import org.onosproject.net.config.NetworkConfigRegistry; -import org.onosproject.net.device.DeviceEvent; -import org.onosproject.net.device.DeviceListener; -import org.onosproject.net.device.DeviceService; -import org.onosproject.net.flow.DefaultTrafficSelector; -import org.onosproject.net.flow.TrafficSelector; -import org.onosproject.net.link.DefaultLinkDescription; -import org.onosproject.net.link.LinkProvider; -import org.onosproject.net.link.LinkProviderRegistry; -import org.onosproject.net.link.LinkProviderService; -import org.onosproject.net.link.LinkService; -import org.onosproject.net.packet.PacketContext; -import org.onosproject.net.packet.PacketPriority; -import org.onosproject.net.packet.PacketProcessor; -import org.onosproject.net.packet.PacketService; -import org.onosproject.net.provider.AbstractProvider; -import org.onosproject.net.provider.ProviderId; -import org.osgi.service.component.ComponentContext; -import org.slf4j.Logger; - -import java.io.IOException; -import java.util.Dictionary; -import java.util.EnumSet; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.onlab.packet.Ethernet.TYPE_BSN; -import static org.onlab.packet.Ethernet.TYPE_LLDP; -import static org.onlab.util.Tools.get; -import static org.onlab.util.Tools.groupedThreads; -import static org.onosproject.net.Link.Type.DIRECT; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Provider which uses LLDP and BDDP packets to detect network infrastructure links. - */ -@Component(immediate = true) -public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { - - private static final String PROVIDER_NAME = "org.onosproject.provider.lldp"; - - private static final String FORMAT = - "Settings: enabled={}, useBDDP={}, probeRate={}, " + - "staleLinkAge={}, lldpSuppression={}"; - - // When a Device/Port has this annotation, do not send out LLDP/BDDP - public static final String NO_LLDP = "no-lldp"; - - - private final Logger log = getLogger(getClass()); - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected CoreService coreService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkProviderRegistry providerRegistry; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected DeviceService deviceService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkService linkService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected PacketService packetService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected MastershipService masterService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ComponentConfigService cfgService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected ClusterService clusterService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected NetworkConfigRegistry cfgRegistry; - - private LinkProviderService providerService; - - private ScheduledExecutorService executor; - - // TODO: Add sanity checking for the configurable params based on the delays - private static final long DEVICE_SYNC_DELAY = 5; - private static final long LINK_PRUNER_DELAY = 3; - - private static final String PROP_ENABLED = "enabled"; - @Property(name = PROP_ENABLED, boolValue = true, - label = "If false, link discovery is disabled") - private boolean enabled = false; - - private static final String PROP_USE_BDDP = "useBDDP"; - @Property(name = PROP_USE_BDDP, boolValue = true, - label = "Use BDDP for link discovery") - private boolean useBDDP = true; - - private static final String PROP_PROBE_RATE = "probeRate"; - private static final int DEFAULT_PROBE_RATE = 3_000; - @Property(name = PROP_PROBE_RATE, intValue = DEFAULT_PROBE_RATE, - label = "LLDP and BDDP probe rate specified in millis") - private int probeRate = DEFAULT_PROBE_RATE; - - private static final String PROP_STALE_LINK_AGE = "staleLinkAge"; - private static final int DEFAULT_STALE_LINK_AGE = 10_000; - @Property(name = PROP_STALE_LINK_AGE, intValue = DEFAULT_STALE_LINK_AGE, - label = "Number of millis beyond which links will be considered stale") - private int staleLinkAge = DEFAULT_STALE_LINK_AGE; - - // FIXME: convert to use network config subsystem instead - private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression"; - private static final String DEFAULT_LLDP_SUPPRESSION_CONFIG = "../config/lldp_suppression.json"; - @Property(name = PROP_LLDP_SUPPRESSION, value = DEFAULT_LLDP_SUPPRESSION_CONFIG, - label = "Path to LLDP suppression configuration file") - private String lldpSuppression = DEFAULT_LLDP_SUPPRESSION_CONFIG; - - private final DiscoveryContext context = new InternalDiscoveryContext(); - private final InternalRoleListener roleListener = new InternalRoleListener(); - private final InternalDeviceListener deviceListener = new InternalDeviceListener(); - private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor(); - - // Device link discovery helpers. - protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>(); - - // Most recent time a tracked link was seen; links are tracked if their - // destination connection point is mastered by this controller instance. - private final Map<LinkKey, Long> linkTimes = Maps.newConcurrentMap(); - - private SuppressionRules rules; - private ApplicationId appId; - - /** - * Creates an OpenFlow link provider. - */ - public LLDPLinkProvider() { - super(new ProviderId("lldp", PROVIDER_NAME)); - } - - @Activate - public void activate(ComponentContext context) { - cfgService.registerProperties(getClass()); - appId = coreService.registerApplication(PROVIDER_NAME); - modified(context); - log.info("Started"); - } - - @Deactivate - public void deactivate() { - cfgService.unregisterProperties(getClass(), false); - disable(); - log.info("Stopped"); - } - - @Modified - public void modified(ComponentContext context) { - Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties(); - - boolean newEnabled, newUseBddp; - int newProbeRate, newStaleLinkAge; - String newLldpSuppression; - try { - String s = get(properties, PROP_ENABLED); - newEnabled = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim()); - - s = get(properties, PROP_USE_BDDP); - newUseBddp = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim()); - - s = get(properties, PROP_PROBE_RATE); - newProbeRate = isNullOrEmpty(s) ? probeRate : Integer.parseInt(s.trim()); - - s = get(properties, PROP_STALE_LINK_AGE); - newStaleLinkAge = isNullOrEmpty(s) ? staleLinkAge : Integer.parseInt(s.trim()); - - s = get(properties, PROP_LLDP_SUPPRESSION); - newLldpSuppression = isNullOrEmpty(s) ? DEFAULT_LLDP_SUPPRESSION_CONFIG : s; - - } catch (NumberFormatException e) { - log.warn("Component configuration had invalid values", e); - newEnabled = enabled; - newUseBddp = useBDDP; - newProbeRate = probeRate; - newStaleLinkAge = staleLinkAge; - newLldpSuppression = lldpSuppression; - } - - boolean wasEnabled = enabled; - - enabled = newEnabled; - useBDDP = newUseBddp; - probeRate = newProbeRate; - staleLinkAge = newStaleLinkAge; - lldpSuppression = newLldpSuppression; - - if (!wasEnabled && enabled) { - enable(); - } else if (wasEnabled && !enabled) { - disable(); - } else { - // reflect changes in suppression rules to discovery helpers - // FIXME: After migrating to Network Configuration Subsystem, - // it should be possible to update only changed subset - if (enabled) { - // update all discovery helper state - loadDevices(); - } - } - - log.info(FORMAT, enabled, useBDDP, probeRate, staleLinkAge, lldpSuppression); - } - - /** - * Enables link discovery processing. - */ - private void enable() { - providerService = providerRegistry.register(this); - masterService.addListener(roleListener); - deviceService.addListener(deviceListener); - packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0)); - - loadSuppressionRules(); - loadDevices(); - - executor = newSingleThreadScheduledExecutor(groupedThreads("onos/link", "discovery-%d")); - executor.scheduleAtFixedRate(new SyncDeviceInfoTask(), - DEVICE_SYNC_DELAY, DEVICE_SYNC_DELAY, SECONDS); - executor.scheduleAtFixedRate(new LinkPrunerTask(), - LINK_PRUNER_DELAY, LINK_PRUNER_DELAY, SECONDS); - - requestIntercepts(); - } - - /** - * Disables link discovery processing. - */ - private void disable() { - withdrawIntercepts(); - - providerRegistry.unregister(this); - masterService.removeListener(roleListener); - deviceService.removeListener(deviceListener); - packetService.removeProcessor(packetProcessor); - - if (executor != null) { - executor.shutdownNow(); - } - discoverers.values().forEach(LinkDiscovery::stop); - discoverers.clear(); - - providerService = null; - } - - /** - * Loads available devices and registers their ports to be probed. - */ - private void loadDevices() { - deviceService.getAvailableDevices() - .forEach(d -> updateDevice(d) - .ifPresent(ld -> updatePorts(ld, d.id()))); - } - - /** - * Updates discovery helper for specified device. - * - * Adds and starts a discovery helper for specified device if enabled, - * calls {@link #removeDevice(DeviceId)} otherwise. - * - * @param device device to add - * @return discovery helper if discovery is enabled for the device - */ - private Optional<LinkDiscovery> updateDevice(Device device) { - if (rules.isSuppressed(device)) { - log.trace("LinkDiscovery from {} disabled by configuration", device.id()); - removeDevice(device.id()); - return Optional.empty(); - } - LinkDiscovery ld = discoverers.computeIfAbsent(device.id(), - did -> new LinkDiscovery(device, context)); - if (ld.isStopped()) { - ld.start(); - } - return Optional.of(ld); - } - - /** - * Removes after stopping discovery helper for specified device. - * @param deviceId device to remove - */ - private void removeDevice(final DeviceId deviceId) { - discoverers.computeIfPresent(deviceId, (did, ld) -> { - ld.stop(); - providerService.linksVanished(deviceId); - return null; - }); - - } - - /** - * Updates ports of the specified device to the specified discovery helper. - */ - private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) { - deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p)); - } - - /** - * Updates discovery helper state of the specified port. - * - * Adds a port to the discovery helper if up and discovery is enabled, - * or calls {@link #removePort(Port)} otherwise. - */ - private void updatePort(LinkDiscovery discoverer, Port port) { - if (rules.isSuppressed(port)) { - log.trace("LinkDiscovery from {} disabled by configuration", port); - removePort(port); - return; - } - - // check if enabled and turn off discovery? - if (!port.isEnabled()) { - removePort(port); - return; - } - - if (!port.number().isLogical()) { - discoverer.addPort(port); - } - } - - /** - * Removes a port from the specified discovery helper. - * @param port the port - */ - private void removePort(Port port) { - if (port.element() instanceof Device) { - Device d = (Device) port.element(); - LinkDiscovery ld = discoverers.get(d.id()); - if (ld != null) { - ld.removePort(port.number()); - } - - ConnectPoint point = new ConnectPoint(d.id(), port.number()); - providerService.linksVanished(point); - } else { - log.warn("Attempted to remove non-Device port", port); - } - } - - /** - * Loads LLDP suppression rules. - */ - private void loadSuppressionRules() { - // FIXME: convert to use network configuration - SuppressionRulesStore store = new SuppressionRulesStore(lldpSuppression); - try { - log.info("Reading suppression rules from {}", lldpSuppression); - rules = store.read(); - } catch (IOException e) { - log.info("Failed to load {}, using built-in rules", lldpSuppression); - // default rule to suppress ROADM to maintain compatibility - rules = new SuppressionRules(ImmutableSet.of(), - EnumSet.of(Device.Type.ROADM), - ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE)); - } - - // should refresh discoverers when we need dynamic reconfiguration - } - - /** - * Requests packet intercepts. - */ - private void requestIntercepts() { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchEthType(TYPE_LLDP); - packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId); - - selector.matchEthType(TYPE_BSN); - if (useBDDP) { - packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId); - } else { - packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId); - } - } - - /** - * Withdraws packet intercepts. - */ - private void withdrawIntercepts() { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchEthType(TYPE_LLDP); - packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId); - selector.matchEthType(TYPE_BSN); - packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId); - } - - /** - * Processes device mastership role changes. - */ - private class InternalRoleListener implements MastershipListener { - @Override - public void event(MastershipEvent event) { - if (MastershipEvent.Type.BACKUPS_CHANGED.equals(event.type())) { - // only need new master events - return; - } - - DeviceId deviceId = event.subject(); - Device device = deviceService.getDevice(deviceId); - if (device == null) { - log.debug("Device {} doesn't exist, or isn't there yet", deviceId); - return; - } - if (clusterService.getLocalNode().id().equals(event.roleInfo().master())) { - updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id())); - } - } - - } - - /** - * Processes device events. - */ - private class InternalDeviceListener implements DeviceListener { - @Override - public void event(DeviceEvent event) { - Device device = event.subject(); - Port port = event.port(); - if (device == null) { - log.error("Device is null."); - return; - } - log.trace("{} {} {}", event.type(), event.subject(), event); - final DeviceId deviceId = device.id(); - switch (event.type()) { - case DEVICE_ADDED: - case DEVICE_UPDATED: - updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId)); - break; - case PORT_ADDED: - case PORT_UPDATED: - if (port.isEnabled()) { - updateDevice(device).ifPresent(ld -> updatePort(ld, port)); - } else { - log.debug("Port down {}", port); - removePort(port); - } - break; - case PORT_REMOVED: - log.debug("Port removed {}", port); - removePort(port); - break; - case DEVICE_REMOVED: - case DEVICE_SUSPENDED: - log.debug("Device removed {}", deviceId); - removeDevice(deviceId); - break; - case DEVICE_AVAILABILITY_CHANGED: - if (deviceService.isAvailable(deviceId)) { - log.debug("Device up {}", deviceId); - updateDevice(device); - } else { - log.debug("Device down {}", deviceId); - removeDevice(deviceId); - } - break; - case PORT_STATS_UPDATED: - break; - default: - log.debug("Unknown event {}", event); - } - } - } - - /** - * Processes incoming packets. - */ - private class InternalPacketProcessor implements PacketProcessor { - @Override - public void process(PacketContext context) { - if (context == null || context.isHandled()) { - return; - } - - Ethernet eth = context.inPacket().parsed(); - if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) { - return; - } - - LinkDiscovery ld = discoverers.get(context.inPacket().receivedFrom().deviceId()); - if (ld == null) { - return; - } - - if (ld.handleLLDP(context)) { - context.block(); - } - } - } - - /** - * Auxiliary task to keep device ports up to date. - */ - private final class SyncDeviceInfoTask implements Runnable { - @Override - public void run() { - if (Thread.currentThread().isInterrupted()) { - log.info("Interrupted, quitting"); - return; - } - // check what deviceService sees, to see if we are missing anything - try { - loadDevices(); - } catch (Exception e) { - // Catch all exceptions to avoid task being suppressed - log.error("Exception thrown during synchronization process", e); - } - } - } - - /** - * Auxiliary task for pruning stale links. - */ - private class LinkPrunerTask implements Runnable { - @Override - public void run() { - if (Thread.currentThread().isInterrupted()) { - log.info("Interrupted, quitting"); - return; - } - - try { - // TODO: There is still a slight possibility of mastership - // change occurring right with link going stale. This will - // result in the stale link not being pruned. - Maps.filterEntries(linkTimes, e -> { - if (!masterService.isLocalMaster(e.getKey().dst().deviceId())) { - return true; - } - if (isStale(e.getValue())) { - providerService.linkVanished(new DefaultLinkDescription(e.getKey().src(), - e.getKey().dst(), - DIRECT)); - return true; - } - return false; - }).clear(); - - } catch (Exception e) { - // Catch all exceptions to avoid task being suppressed - log.error("Exception thrown during link pruning process", e); - } - } - - private boolean isStale(long lastSeen) { - return lastSeen < System.currentTimeMillis() - staleLinkAge; - } - } - - /** - * Provides processing context for the device link discovery helpers. - */ - private class InternalDiscoveryContext implements DiscoveryContext { - @Override - public MastershipService mastershipService() { - return masterService; - } - - @Override - public LinkProviderService providerService() { - return providerService; - } - - @Override - public PacketService packetService() { - return packetService; - } - - @Override - public long probeRate() { - return probeRate; - } - - @Override - public boolean useBDDP() { - return useBDDP; - } - - @Override - public void touchLink(LinkKey key) { - linkTimes.put(key, System.currentTimeMillis()); - } - } - -} diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java index 7dc9aed0..4b962ae5 100644 --- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java +++ b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java @@ -155,7 +155,7 @@ class LinkDiscovery implements TimerTask { * @param packetContext packet context * @return true if handled */ - boolean handleLLDP(PacketContext packetContext) { + boolean handleLldp(PacketContext packetContext) { Ethernet eth = packetContext.inPacket().parsed(); if (eth == null) { return false; @@ -216,7 +216,7 @@ class LinkDiscovery implements TimerTask { * @param port the port * @return Packet_out message with LLDP data */ - private OutboundPacket createOutBoundLLDP(Long port) { + private OutboundPacket createOutBoundLldp(Long port) { if (port == null) { return null; } @@ -233,7 +233,7 @@ class LinkDiscovery implements TimerTask { * @param port the port * @return Packet_out message with LLDP data */ - private OutboundPacket createOutBoundBDDP(Long port) { + private OutboundPacket createOutBoundBddp(Long port) { if (port == null) { return null; } @@ -246,10 +246,10 @@ class LinkDiscovery implements TimerTask { private void sendProbes(Long portNumber) { log.trace("Sending probes out to {}@{}", portNumber, device.id()); - OutboundPacket pkt = createOutBoundLLDP(portNumber); + OutboundPacket pkt = createOutBoundLldp(portNumber); context.packetService().emit(pkt); - if (context.useBDDP()) { - OutboundPacket bpkt = createOutBoundBDDP(portNumber); + if (context.useBddp()) { + OutboundPacket bpkt = createOutBoundBddp(portNumber); context.packetService().emit(bpkt); } } diff --git a/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java b/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java deleted file mode 100644 index 6070b857..00000000 --- a/framework/src/onos/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Copyright 2014-2015 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.provider.lldp.impl; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.onlab.packet.ChassisId; -import org.onlab.packet.Ethernet; -import org.onlab.packet.ONOSLLDP; -import org.onosproject.cfg.ComponentConfigAdapter; -import org.onosproject.cluster.NodeId; -import org.onosproject.cluster.RoleInfo; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.core.DefaultApplicationId; -import org.onosproject.mastership.MastershipListener; -import org.onosproject.mastership.MastershipService; -import org.onosproject.net.Annotations; -import org.onosproject.net.ConnectPoint; -import org.onosproject.net.DefaultAnnotations; -import org.onosproject.net.DefaultDevice; -import org.onosproject.net.DefaultPort; -import org.onosproject.net.Device; -import org.onosproject.net.DeviceId; -import org.onosproject.net.MastershipRole; -import org.onosproject.net.Port; -import org.onosproject.net.PortNumber; -import org.onosproject.net.device.DeviceEvent; -import org.onosproject.net.device.DeviceListener; -import org.onosproject.net.device.DeviceServiceAdapter; -import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.link.LinkDescription; -import org.onosproject.net.link.LinkProvider; -import org.onosproject.net.link.LinkProviderRegistry; -import org.onosproject.net.link.LinkProviderService; -import org.onosproject.net.link.LinkServiceAdapter; -import org.onosproject.net.packet.DefaultInboundPacket; -import org.onosproject.net.packet.InboundPacket; -import org.onosproject.net.packet.OutboundPacket; -import org.onosproject.net.packet.PacketContext; -import org.onosproject.net.packet.PacketProcessor; -import org.onosproject.net.packet.PacketServiceAdapter; -import org.onosproject.net.provider.AbstractProviderService; -import org.onosproject.net.provider.ProviderId; - -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -import static org.easymock.EasyMock.*; -import static org.junit.Assert.*; - -public class LLDPLinkProviderTest { - - private static final DeviceId DID1 = DeviceId.deviceId("of:0000000000000001"); - private static final DeviceId DID2 = DeviceId.deviceId("of:0000000000000002"); - private static final DeviceId DID3 = DeviceId.deviceId("of:0000000000000003"); - - private static Port pd1; - private static Port pd2; - private static Port pd3; - private static Port pd4; - - private final LLDPLinkProvider provider = new LLDPLinkProvider(); - private final TestLinkRegistry linkRegistry = new TestLinkRegistry(); - private final TestLinkService linkService = new TestLinkService(); - private final TestPacketService packetService = new TestPacketService(); - private final TestDeviceService deviceService = new TestDeviceService(); - private final TestMasterShipService masterService = new TestMasterShipService(); - - private CoreService coreService; - private TestLinkProviderService providerService; - - private PacketProcessor testProcessor; - private DeviceListener deviceListener; - - private ApplicationId appId = - new DefaultApplicationId(100, "org.onosproject.provider.lldp"); - - @Before - public void setUp() { - coreService = createMock(CoreService.class); - expect(coreService.registerApplication(appId.name())) - .andReturn(appId).anyTimes(); - replay(coreService); - - provider.cfgService = new ComponentConfigAdapter(); - provider.coreService = coreService; - - provider.deviceService = deviceService; - provider.linkService = linkService; - provider.packetService = packetService; - provider.providerRegistry = linkRegistry; - provider.masterService = masterService; - - provider.activate(null); - } - - @Test - public void basics() { - assertNotNull("registration expected", providerService); - assertEquals("incorrect provider", provider, providerService.provider()); - } - - @Test - public void switchAdd() { - DeviceEvent de = deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1); - deviceListener.event(de); - - assertFalse("Device not added", provider.discoverers.isEmpty()); - } - - @Test - public void switchRemove() { - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_REMOVED, DID1)); - - final LinkDiscovery linkDiscovery = provider.discoverers.get(DID1); - if (linkDiscovery != null) { - // If LinkDiscovery helper is there after DEVICE_REMOVED, - // it should be stopped - assertTrue("Discoverer is not stopped", linkDiscovery.isStopped()); - } - assertTrue("Device is not gone.", vanishedDpid(DID1)); - } - - /** - * Checks that links on a reconfigured switch are properly removed. - */ - @Test - public void switchSuppressed() { - // add device to stub DeviceService - deviceService.putDevice(device(DID3)); - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); - - assertFalse("Device not added", provider.discoverers.isEmpty()); - - // update device in stub DeviceService with suppression config - deviceService.putDevice(device(DID3, DefaultAnnotations.builder() - .set(LLDPLinkProvider.NO_LLDP, "true") - .build())); - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3)); - - assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3)); - } - - @Test - public void portUp() { - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 3, true))); - - assertTrue("Port not added to discoverer", - provider.discoverers.get(DID1).containsPort(3L)); - } - - @Test - public void portDown() { - - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 1, false))); - - assertFalse("Port added to discoverer", - provider.discoverers.get(DID1).containsPort(1L)); - assertTrue("Port is not gone.", vanishedPort(1L)); - } - - @Test - public void portRemoved() { - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 3, true))); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_REMOVED, DID1, port(DID1, 3, true))); - - assertTrue("Port is not gone.", vanishedPort(3L)); - assertFalse("Port was not removed from discoverer", - provider.discoverers.get(DID1).containsPort(3L)); - } - - /** - * Checks that discovery on reconfigured switch are properly restarted. - */ - @Test - public void portSuppressedByDeviceConfig() { - - /// When Device is configured with suppression:ON, Port also is same - - // add device in stub DeviceService with suppression configured - deviceService.putDevice(device(DID3, DefaultAnnotations.builder() - .set(LLDPLinkProvider.NO_LLDP, "true") - .build())); - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); - - // non-suppressed port added to suppressed device - final long portno3 = 3L; - deviceService.putPorts(DID3, port(DID3, portno3, true)); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, portno3, true))); - - // discovery on device is expected to be stopped - LinkDiscovery linkDiscovery = provider.discoverers.get(DID3); - if (linkDiscovery != null) { - assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped()); - } - - /// When Device is reconfigured without suppression:OFF, - /// Port should be included for discovery - - // update device in stub DeviceService without suppression configured - deviceService.putDevice(device(DID3)); - // update the Port in stub DeviceService. (Port has reference to Device) - deviceService.putPorts(DID3, port(DID3, portno3, true)); - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3)); - - // discovery should come back on - assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped()); - assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID3).containsPort(portno3)); - } - - /** - * Checks that discovery on reconfigured port are properly restarted. - */ - @Test - public void portSuppressedByPortConfig() { - // add device in stub DeviceService without suppression configured - deviceService.putDevice(device(DID3)); - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); - - // suppressed port added to non-suppressed device - final long portno3 = 3L; - final Port port3 = port(DID3, portno3, true, - DefaultAnnotations.builder() - .set(LLDPLinkProvider.NO_LLDP, "true") - .build()); - deviceService.putPorts(DID3, port3); - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port3)); - - // discovery helper should be there turned on - assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped()); - assertFalse("Discoverer should not contain the port there", - provider.discoverers.get(DID3).containsPort(portno3)); - } - - @Test - public void portUnknown() { - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - // Note: DID3 hasn't been added to TestDeviceService, but only port is added - deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, 1, false))); - - - assertNull("DeviceId exists", - provider.discoverers.get(DID3)); - } - - @Test - public void unknownPktCtx() { - - // Note: DID3 hasn't been added to TestDeviceService - PacketContext pktCtx = new TestPacketContext(device(DID3)); - - testProcessor.process(pktCtx); - assertFalse("Context should still be free", pktCtx.isHandled()); - } - - @Test - public void knownPktCtx() { - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1)); - deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID2)); - PacketContext pktCtx = new TestPacketContext(deviceService.getDevice(DID2)); - - - testProcessor.process(pktCtx); - - assertTrue("Link not detected", detectedLink(DID1, DID2)); - - } - - - @After - public void tearDown() { - provider.deactivate(); - provider.coreService = null; - provider.providerRegistry = null; - provider.deviceService = null; - provider.packetService = null; - } - - private DeviceEvent deviceEvent(DeviceEvent.Type type, DeviceId did) { - return new DeviceEvent(type, deviceService.getDevice(did)); - - } - - private DefaultDevice device(DeviceId did) { - return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH, - "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); - } - - private DefaultDevice device(DeviceId did, Annotations annotations) { - return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH, - "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations); - } - - @SuppressWarnings(value = { "unused" }) - private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, PortNumber port) { - return new DeviceEvent(type, deviceService.getDevice(did), - deviceService.getPort(did, port)); - } - - private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, Port port) { - return new DeviceEvent(type, deviceService.getDevice(did), port); - } - - private Port port(DeviceId did, long port, boolean enabled) { - return new DefaultPort(deviceService.getDevice(did), - PortNumber.portNumber(port), enabled); - } - - private Port port(DeviceId did, long port, boolean enabled, Annotations annotations) { - return new DefaultPort(deviceService.getDevice(did), - PortNumber.portNumber(port), enabled, annotations); - } - - private boolean vanishedDpid(DeviceId... dids) { - for (int i = 0; i < dids.length; i++) { - if (!providerService.vanishedDpid.contains(dids[i])) { - return false; - } - } - return true; - } - - private boolean vanishedPort(Long... ports) { - for (int i = 0; i < ports.length; i++) { - if (!providerService.vanishedPort.contains(ports[i])) { - return false; - } - } - return true; - } - - private boolean detectedLink(DeviceId src, DeviceId dst) { - for (DeviceId key : providerService.discoveredLinks.keySet()) { - if (key.equals(src)) { - return providerService.discoveredLinks.get(src).equals(dst); - } - } - return false; - } - - - private class TestLinkRegistry implements LinkProviderRegistry { - - @Override - public LinkProviderService register(LinkProvider provider) { - providerService = new TestLinkProviderService(provider); - return providerService; - } - - @Override - public void unregister(LinkProvider provider) { - } - - @Override - public Set<ProviderId> getProviders() { - return null; - } - - } - - private class TestLinkProviderService - extends AbstractProviderService<LinkProvider> - implements LinkProviderService { - - List<DeviceId> vanishedDpid = Lists.newLinkedList(); - List<Long> vanishedPort = Lists.newLinkedList(); - Map<DeviceId, DeviceId> discoveredLinks = Maps.newHashMap(); - - protected TestLinkProviderService(LinkProvider provider) { - super(provider); - } - - @Override - public void linkDetected(LinkDescription linkDescription) { - DeviceId sDid = linkDescription.src().deviceId(); - DeviceId dDid = linkDescription.dst().deviceId(); - discoveredLinks.put(sDid, dDid); - } - - @Override - public void linkVanished(LinkDescription linkDescription) { - } - - @Override - public void linksVanished(ConnectPoint connectPoint) { - vanishedPort.add(connectPoint.port().toLong()); - - } - - @Override - public void linksVanished(DeviceId deviceId) { - vanishedDpid.add(deviceId); - } - - - } - - - - private class TestPacketContext implements PacketContext { - - protected Device device; - protected boolean blocked = false; - - public TestPacketContext(Device dev) { - device = dev; - } - - @Override - public long time() { - return 0; - } - - @Override - public InboundPacket inPacket() { - ONOSLLDP lldp = new ONOSLLDP(); - lldp.setChassisId(device.chassisId()); - lldp.setPortId((int) pd1.number().toLong()); - lldp.setDevice(deviceService.getDevice(DID1).id().toString()); - - - Ethernet ethPacket = new Ethernet(); - ethPacket.setEtherType(Ethernet.TYPE_LLDP); - ethPacket.setDestinationMACAddress(ONOSLLDP.LLDP_NICIRA); - ethPacket.setPayload(lldp); - ethPacket.setPad(true); - - - - ethPacket.setSourceMACAddress("DE:AD:BE:EF:BA:11"); - - ConnectPoint cp = new ConnectPoint(device.id(), pd3.number()); - - return new DefaultInboundPacket(cp, ethPacket, - ByteBuffer.wrap(ethPacket.serialize())); - - } - - @Override - public OutboundPacket outPacket() { - return null; - } - - @Override - public TrafficTreatment.Builder treatmentBuilder() { - return null; - } - - @Override - public void send() { - - } - - @Override - public boolean block() { - blocked = true; - return blocked; - } - - @Override - public boolean isHandled() { - return blocked; - } - - } - - private class TestPacketService extends PacketServiceAdapter { - @Override - public void addProcessor(PacketProcessor processor, int priority) { - testProcessor = processor; - } - } - - private class TestDeviceService extends DeviceServiceAdapter { - - private final Map<DeviceId, Device> devices = new HashMap<>(); - private final ArrayListMultimap<DeviceId, Port> ports = - ArrayListMultimap.create(); - public TestDeviceService() { - Device d1 = new DefaultDevice(ProviderId.NONE, DID1, Device.Type.SWITCH, - "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); - Device d2 = new DefaultDevice(ProviderId.NONE, DID2, Device.Type.SWITCH, - "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); - devices.put(DID1, d1); - devices.put(DID2, d2); - pd1 = new DefaultPort(d1, PortNumber.portNumber(1), true); - pd2 = new DefaultPort(d1, PortNumber.portNumber(2), true); - pd3 = new DefaultPort(d2, PortNumber.portNumber(1), true); - pd4 = new DefaultPort(d2, PortNumber.portNumber(2), true); - - ports.putAll(DID1, Lists.newArrayList(pd1, pd2)); - ports.putAll(DID2, Lists.newArrayList(pd3, pd4)); - } - - private void putDevice(Device device) { - DeviceId deviceId = device.id(); - devices.put(deviceId, device); - } - - private void putPorts(DeviceId did, Port...ports) { - this.ports.putAll(did, Lists.newArrayList(ports)); - } - - @Override - public int getDeviceCount() { - return devices.values().size(); - } - - @Override - public Iterable<Device> getDevices() { - return ImmutableList.copyOf(devices.values()); - } - - @Override - public Device getDevice(DeviceId deviceId) { - return devices.get(deviceId); - } - - @Override - public MastershipRole getRole(DeviceId deviceId) { - return MastershipRole.MASTER; - } - - @Override - public List<Port> getPorts(DeviceId deviceId) { - return ports.get(deviceId); - } - - @Override - public Port getPort(DeviceId deviceId, PortNumber portNumber) { - for (Port p : ports.get(deviceId)) { - if (p.number().equals(portNumber)) { - return p; - } - } - return null; - } - - @Override - public boolean isAvailable(DeviceId deviceId) { - return true; - } - - @Override - public void addListener(DeviceListener listener) { - deviceListener = listener; - - } - - @Override - public void removeListener(DeviceListener listener) { - - } - } - - private final class TestMasterShipService implements MastershipService { - - @Override - public MastershipRole getLocalRole(DeviceId deviceId) { - return MastershipRole.MASTER; - } - - @Override - public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) { - return CompletableFuture.completedFuture(null); - } - - @Override - public CompletableFuture<Void> relinquishMastership(DeviceId deviceId) { - return null; - } - - @Override - public NodeId getMasterFor(DeviceId deviceId) { - return null; - } - - @Override - public Set<DeviceId> getDevicesOf(NodeId nodeId) { - return null; - } - - @Override - public void addListener(MastershipListener listener) { - - } - - @Override - public void removeListener(MastershipListener listener) { - - } - - @Override - public RoleInfo getNodesFor(DeviceId deviceId) { - return new RoleInfo(new NodeId("foo"), Collections.<NodeId>emptyList()); - } - } - - - private class TestLinkService extends LinkServiceAdapter { - } -} |