Search in sources :

Example 1 with TRANSIT

use of org.onosproject.segmentrouting.mcast.McastRole.TRANSIT in project trellis-control by opennetworkinglab.

the class McastHandler method recoverFailure.

/**
 * General failure recovery procedure.
 *
 * @param mcastIp the group to recover
 * @param failedElement the failed element
 */
private void recoverFailure(IpAddress mcastIp, Object failedElement) {
    // Do not proceed if we are not the leaders
    if (!mcastUtils.isLeader(mcastIp)) {
        log.debug("Skip {} due to lack of leadership", mcastIp);
        return;
    }
    // Skip if it is not an infra failure
    Set<DeviceId> transitDevices = getDevice(mcastIp, TRANSIT);
    if (!mcastUtils.isInfraFailure(transitDevices, failedElement)) {
        log.debug("Skip {} not an infrastructure failure", mcastIp);
        return;
    }
    // Do not proceed if the sources of this group are missing
    Set<ConnectPoint> sources = getSources(mcastIp);
    if (sources.isEmpty()) {
        log.warn("Missing sources for group {}", mcastIp);
        return;
    }
    // Get all the paths, affected paths, good links and good devices
    Set<List<Link>> storedPaths = getStoredPaths(mcastIp);
    Set<List<Link>> affectedPaths = mcastUtils.getAffectedPaths(storedPaths, failedElement);
    Set<Link> goodLinks = Sets.newHashSet();
    Map<DeviceId, Set<DeviceId>> goodDevicesBySource = Maps.newHashMap();
    Map<DeviceId, Set<ConnectPoint>> processedSourcesByEgress = Maps.newHashMap();
    Sets.difference(storedPaths, affectedPaths).forEach(goodPath -> {
        goodLinks.addAll(goodPath);
        DeviceId srcDevice = goodPath.get(0).src().deviceId();
        Set<DeviceId> goodDevices = Sets.newHashSet();
        goodPath.forEach(link -> goodDevices.add(link.src().deviceId()));
        goodDevicesBySource.compute(srcDevice, (k, v) -> {
            v = v == null ? Sets.newHashSet() : v;
            v.addAll(goodDevices);
            return v;
        });
    });
    affectedPaths.forEach(affectedPath -> {
        // TODO remove
        log.info("Good links {}", goodLinks);
        // TODO remove
        log.info("Good devices {}", goodDevicesBySource);
        // TODO trace
        log.info("Healing the path {}", affectedPath);
        DeviceId srcDevice = affectedPath.get(0).src().deviceId();
        DeviceId dstDevice = affectedPath.get(affectedPath.size() - 1).dst().deviceId();
        // Fix in one shot multiple sources
        Set<ConnectPoint> affectedSources = sources.stream().filter(device -> device.deviceId().equals(srcDevice)).collect(Collectors.toSet());
        Set<ConnectPoint> processedSources = processedSourcesByEgress.getOrDefault(dstDevice, Collections.emptySet());
        Optional<Path> alternativePath = getPath(srcDevice, dstDevice, mcastIp, null);
        // If an alternative is possible go ahead
        if (alternativePath.isPresent()) {
            // TODO trace
            log.info("Alternative path {}", alternativePath.get().links());
        } else {
            // Otherwise try to come up with an alternative
            // TODO trace
            log.info("No alternative path");
            Set<ConnectPoint> notAffectedSources = Sets.difference(sources, affectedSources);
            Set<ConnectPoint> remainingSources = Sets.difference(notAffectedSources, processedSources);
            alternativePath = recoverSinks(dstDevice, mcastIp, affectedSources, remainingSources);
            processedSourcesByEgress.compute(dstDevice, (k, v) -> {
                v = v == null ? Sets.newHashSet() : v;
                v.addAll(affectedSources);
                return v;
            });
        }
        // Recover from the failure if possible
        Optional<Path> finalPath = alternativePath;
        affectedSources.forEach(affectedSource -> {
            // Update the mcastPath store
            McastPathStoreKey mcastPathStoreKey = new McastPathStoreKey(mcastIp, affectedSource);
            // Verify if there are local sinks
            Set<DeviceId> localSinks = getSinks(mcastIp, srcDevice, affectedSource).stream().map(ConnectPoint::deviceId).collect(Collectors.toSet());
            Set<DeviceId> goodDevices = goodDevicesBySource.compute(affectedSource.deviceId(), (k, v) -> {
                v = v == null ? Sets.newHashSet() : v;
                v.addAll(localSinks);
                return v;
            });
            // TODO remove
            log.info("Good devices {}", goodDevicesBySource);
            Collection<? extends List<Link>> storedPathsBySource = Versioned.valueOrElse(mcastPathStore.get(mcastPathStoreKey), Lists.newArrayList());
            Optional<? extends List<Link>> storedPath = storedPathsBySource.stream().filter(path -> path.equals(affectedPath)).findFirst();
            // Remove bad links
            affectedPath.forEach(affectedLink -> {
                DeviceId affectedDevice = affectedLink.src().deviceId();
                // If there is overlap with good paths - skip it
                if (!goodLinks.contains(affectedLink)) {
                    removePortFromDevice(affectedDevice, affectedLink.src().port(), mcastIp, mcastUtils.assignedVlan(affectedDevice.equals(affectedSource.deviceId()) ? affectedSource : null));
                }
                // Remove role on the affected links if last
                if (!goodDevices.contains(affectedDevice)) {
                    mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, affectedDevice, affectedSource));
                }
            });
            // trying with the original object as workaround
            if (storedPath.isPresent()) {
                mcastPathStore.remove(mcastPathStoreKey, storedPath.get());
            } else {
                log.warn("Unable to find the corresponding path - trying removeal");
                mcastPathStore.remove(mcastPathStoreKey, affectedPath);
            }
            // Program new links
            if (finalPath.isPresent()) {
                List<Link> links = finalPath.get().links();
                installPath(mcastIp, affectedSource, links);
                mcastPathStore.put(mcastPathStoreKey, links);
                links.forEach(link -> goodDevices.add(link.src().deviceId()));
                goodDevicesBySource.compute(srcDevice, (k, v) -> {
                    v = v == null ? Sets.newHashSet() : v;
                    v.addAll(goodDevices);
                    return v;
                });
                goodLinks.addAll(finalPath.get().links());
            }
        });
    });
}
Also used : ConsistentMap(org.onosproject.store.service.ConsistentMap) CoreService(org.onosproject.core.CoreService) PortNumber(org.onosproject.net.PortNumber) LoggerFactory(org.slf4j.LoggerFactory) Tools.groupedThreads(org.onlab.util.Tools.groupedThreads) ForwardingObjective(org.onosproject.net.flowobjective.ForwardingObjective) ConsistentMultimap(org.onosproject.store.service.ConsistentMultimap) Link(org.onosproject.net.Link) SINKS_REMOVED(org.onosproject.mcast.api.McastEvent.Type.SINKS_REMOVED) ConnectPoint(org.onosproject.net.ConnectPoint) HashMultimap(com.google.common.collect.HashMultimap) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Executors.newScheduledThreadPool(java.util.concurrent.Executors.newScheduledThreadPool) McastEvent(org.onosproject.mcast.api.McastEvent) Port(org.onosproject.net.Port) Map(java.util.Map) ApplicationId(org.onosproject.core.ApplicationId) NextObjective(org.onosproject.net.flowobjective.NextObjective) SOURCES_ADDED(org.onosproject.mcast.api.McastEvent.Type.SOURCES_ADDED) INGRESS(org.onosproject.segmentrouting.mcast.McastRole.INGRESS) KryoNamespaces(org.onosproject.store.serializers.KryoNamespaces) SOURCES_REMOVED(org.onosproject.mcast.api.McastEvent.Type.SOURCES_REMOVED) Objects(com.google.common.base.Objects) ROUTE_ADDED(org.onosproject.mcast.api.McastEvent.Type.ROUTE_ADDED) NodeId(org.onosproject.cluster.NodeId) Serializer(org.onosproject.store.service.Serializer) ImmutableSet(com.google.common.collect.ImmutableSet) Device(org.onosproject.net.Device) Collection(java.util.Collection) Set(java.util.Set) Instant(java.time.Instant) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) SINKS_ADDED(org.onosproject.mcast.api.McastEvent.Type.SINKS_ADDED) Versioned(org.onosproject.store.service.Versioned) List(java.util.List) ObjectiveContext(org.onosproject.net.flowobjective.ObjectiveContext) Entry(java.util.Map.Entry) Optional(java.util.Optional) Path(org.onosproject.net.Path) DeviceId(org.onosproject.net.DeviceId) McastRouteUpdate(org.onosproject.mcast.api.McastRouteUpdate) ROUTE_REMOVED(org.onosproject.mcast.api.McastEvent.Type.ROUTE_REMOVED) Multimap(com.google.common.collect.Multimap) KryoNamespace(org.onlab.util.KryoNamespace) AtomicReference(java.util.concurrent.atomic.AtomicReference) Lists(com.google.common.collect.Lists) TRANSIT(org.onosproject.segmentrouting.mcast.McastRole.TRANSIT) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) HostId(org.onosproject.net.HostId) DefaultObjectiveContext(org.onosproject.net.flowobjective.DefaultObjectiveContext) IpAddress(org.onlab.packet.IpAddress) SegmentRoutingManager(org.onosproject.segmentrouting.SegmentRoutingManager) McastRouteData(org.onosproject.mcast.api.McastRouteData) Logger(org.slf4j.Logger) EGRESS(org.onosproject.segmentrouting.mcast.McastRole.EGRESS) Iterator(java.util.Iterator) VlanId(org.onlab.packet.VlanId) Maps(com.google.common.collect.Maps) McastRoute(org.onosproject.mcast.api.McastRoute) TimeUnit(java.util.concurrent.TimeUnit) DistributedSet(org.onosproject.store.service.DistributedSet) Comparator(java.util.Comparator) Collections(java.util.Collections) Path(org.onosproject.net.Path) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) DistributedSet(org.onosproject.store.service.DistributedSet) DeviceId(org.onosproject.net.DeviceId) ConnectPoint(org.onosproject.net.ConnectPoint) List(java.util.List) Link(org.onosproject.net.Link)

Example 2 with TRANSIT

use of org.onosproject.segmentrouting.mcast.McastRole.TRANSIT in project trellis-control by opennetworkinglab.

the class McastHandler method processSourcesRemovedInternal.

/**
 * Process the SOURCES_REMOVED event.
 *
 * @param sourcesToBeRemoved the source connect points to be removed
 * @param remainingSources the remainig source connect points
 * @param mcastIp the group address
 * @param sinks the sinks connect points
 */
private void processSourcesRemovedInternal(Set<ConnectPoint> sourcesToBeRemoved, Set<ConnectPoint> remainingSources, IpAddress mcastIp, Map<HostId, Set<ConnectPoint>> sinks) {
    lastMcastChange.set(Instant.now());
    log.info("Processing sources removed {} for group {}", sourcesToBeRemoved, mcastIp);
    if (!mcastUtils.isLeader(mcastIp)) {
        log.debug("Skip {} due to lack of leadership", mcastIp);
        return;
    }
    if (remainingSources.isEmpty()) {
        log.debug("There are no more sources for {}", mcastIp);
        processRouteRemovedInternal(sourcesToBeRemoved, mcastIp);
        return;
    }
    // Let's heal the trees
    Set<Link> notAffectedLinks = Sets.newHashSet();
    Map<ConnectPoint, Set<Link>> affectedLinks = Maps.newHashMap();
    Map<ConnectPoint, Set<ConnectPoint>> candidateSinks = Maps.newHashMap();
    Set<ConnectPoint> totalSources = Sets.newHashSet(sourcesToBeRemoved);
    totalSources.addAll(remainingSources);
    // Calculate all the links used by the sources and the current sinks
    totalSources.forEach(source -> {
        Set<ConnectPoint> currentSinks = sinks.values().stream().flatMap(Collection::stream).filter(sink -> isSinkForSource(mcastIp, sink, source)).collect(Collectors.toSet());
        candidateSinks.put(source, currentSinks);
        McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
        Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(mcastPathStore.get(pathStoreKey), Lists.newArrayList());
        currentSinks.forEach(currentSink -> {
            Optional<? extends List<Link>> currentPath = mcastUtils.getStoredPath(currentSink.deviceId(), storedPaths);
            if (currentPath.isPresent()) {
                if (!sourcesToBeRemoved.contains(source)) {
                    notAffectedLinks.addAll(currentPath.get());
                } else {
                    affectedLinks.compute(source, (k, v) -> {
                        v = v == null ? Sets.newHashSet() : v;
                        v.addAll(currentPath.get());
                        return v;
                    });
                }
            }
        });
    });
    // Clean transit links
    affectedLinks.forEach((source, currentCandidateLinks) -> {
        Set<Link> linksToBeRemoved = Sets.difference(currentCandidateLinks, notAffectedLinks).immutableCopy();
        if (!linksToBeRemoved.isEmpty()) {
            currentCandidateLinks.forEach(link -> {
                DeviceId srcLink = link.src().deviceId();
                // Remove ports only on links to be removed
                if (linksToBeRemoved.contains(link)) {
                    removePortFromDevice(link.src().deviceId(), link.src().port(), mcastIp, mcastUtils.assignedVlan(srcLink.equals(source.deviceId()) ? source : null));
                }
                // Remove role on the candidate links
                mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, srcLink, source));
            });
        }
    });
    // Clean ingress and egress
    sourcesToBeRemoved.forEach(source -> {
        Set<ConnectPoint> currentSinks = candidateSinks.get(source);
        McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
        currentSinks.forEach(currentSink -> {
            VlanId assignedVlan = mcastUtils.assignedVlan(source.deviceId().equals(currentSink.deviceId()) ? source : null);
            // Sinks co-located with the source
            if (source.deviceId().equals(currentSink.deviceId())) {
                if (source.port().equals(currentSink.port())) {
                    log.warn("Skip {} since sink {} is on the same port of source {}. Abort", mcastIp, currentSink, source);
                    return;
                }
                // We need to check against the other sources and if it is
                // necessary remove the port from the device - no overlap
                Set<VlanId> otherVlans = remainingSources.stream().filter(remainingSource -> remainingSource.deviceId().equals(source.deviceId()) && candidateSinks.get(remainingSource).contains(currentSink)).map(remainingSource -> mcastUtils.assignedVlan(remainingSource.deviceId().equals(currentSink.deviceId()) ? remainingSource : null)).collect(Collectors.toSet());
                if (!otherVlans.contains(assignedVlan)) {
                    removePortFromDevice(currentSink.deviceId(), currentSink.port(), mcastIp, assignedVlan);
                }
                mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, currentSink.deviceId(), source));
                return;
            }
            Set<VlanId> otherVlans = remainingSources.stream().filter(remainingSource -> candidateSinks.get(remainingSource).contains(currentSink)).map(remainingSource -> mcastUtils.assignedVlan(remainingSource.deviceId().equals(currentSink.deviceId()) ? remainingSource : null)).collect(Collectors.toSet());
            // Sinks on other leaves
            if (!otherVlans.contains(assignedVlan)) {
                removePortFromDevice(currentSink.deviceId(), currentSink.port(), mcastIp, assignedVlan);
            }
            mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, currentSink.deviceId(), source));
        });
        // Clean the mcast paths
        mcastPathStore.removeAll(pathStoreKey);
    });
}
Also used : ConsistentMap(org.onosproject.store.service.ConsistentMap) CoreService(org.onosproject.core.CoreService) PortNumber(org.onosproject.net.PortNumber) LoggerFactory(org.slf4j.LoggerFactory) Tools.groupedThreads(org.onlab.util.Tools.groupedThreads) ForwardingObjective(org.onosproject.net.flowobjective.ForwardingObjective) ConsistentMultimap(org.onosproject.store.service.ConsistentMultimap) Link(org.onosproject.net.Link) SINKS_REMOVED(org.onosproject.mcast.api.McastEvent.Type.SINKS_REMOVED) ConnectPoint(org.onosproject.net.ConnectPoint) HashMultimap(com.google.common.collect.HashMultimap) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Executors.newScheduledThreadPool(java.util.concurrent.Executors.newScheduledThreadPool) McastEvent(org.onosproject.mcast.api.McastEvent) Port(org.onosproject.net.Port) Map(java.util.Map) ApplicationId(org.onosproject.core.ApplicationId) NextObjective(org.onosproject.net.flowobjective.NextObjective) SOURCES_ADDED(org.onosproject.mcast.api.McastEvent.Type.SOURCES_ADDED) INGRESS(org.onosproject.segmentrouting.mcast.McastRole.INGRESS) KryoNamespaces(org.onosproject.store.serializers.KryoNamespaces) SOURCES_REMOVED(org.onosproject.mcast.api.McastEvent.Type.SOURCES_REMOVED) Objects(com.google.common.base.Objects) ROUTE_ADDED(org.onosproject.mcast.api.McastEvent.Type.ROUTE_ADDED) NodeId(org.onosproject.cluster.NodeId) Serializer(org.onosproject.store.service.Serializer) ImmutableSet(com.google.common.collect.ImmutableSet) Device(org.onosproject.net.Device) Collection(java.util.Collection) Set(java.util.Set) Instant(java.time.Instant) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) SINKS_ADDED(org.onosproject.mcast.api.McastEvent.Type.SINKS_ADDED) Versioned(org.onosproject.store.service.Versioned) List(java.util.List) ObjectiveContext(org.onosproject.net.flowobjective.ObjectiveContext) Entry(java.util.Map.Entry) Optional(java.util.Optional) Path(org.onosproject.net.Path) DeviceId(org.onosproject.net.DeviceId) McastRouteUpdate(org.onosproject.mcast.api.McastRouteUpdate) ROUTE_REMOVED(org.onosproject.mcast.api.McastEvent.Type.ROUTE_REMOVED) Multimap(com.google.common.collect.Multimap) KryoNamespace(org.onlab.util.KryoNamespace) AtomicReference(java.util.concurrent.atomic.AtomicReference) Lists(com.google.common.collect.Lists) TRANSIT(org.onosproject.segmentrouting.mcast.McastRole.TRANSIT) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) HostId(org.onosproject.net.HostId) DefaultObjectiveContext(org.onosproject.net.flowobjective.DefaultObjectiveContext) IpAddress(org.onlab.packet.IpAddress) SegmentRoutingManager(org.onosproject.segmentrouting.SegmentRoutingManager) McastRouteData(org.onosproject.mcast.api.McastRouteData) Logger(org.slf4j.Logger) EGRESS(org.onosproject.segmentrouting.mcast.McastRole.EGRESS) Iterator(java.util.Iterator) VlanId(org.onlab.packet.VlanId) Maps(com.google.common.collect.Maps) McastRoute(org.onosproject.mcast.api.McastRoute) TimeUnit(java.util.concurrent.TimeUnit) DistributedSet(org.onosproject.store.service.DistributedSet) Comparator(java.util.Comparator) Collections(java.util.Collections) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) DistributedSet(org.onosproject.store.service.DistributedSet) DeviceId(org.onosproject.net.DeviceId) ConnectPoint(org.onosproject.net.ConnectPoint) Collection(java.util.Collection) Link(org.onosproject.net.Link) VlanId(org.onlab.packet.VlanId)

Aggregations

Objects (com.google.common.base.Objects)2 HashMultimap (com.google.common.collect.HashMultimap)2 ImmutableSet (com.google.common.collect.ImmutableSet)2 Lists (com.google.common.collect.Lists)2 Maps (com.google.common.collect.Maps)2 Multimap (com.google.common.collect.Multimap)2 Sets (com.google.common.collect.Sets)2 Instant (java.time.Instant)2 Collection (java.util.Collection)2 Collections (java.util.Collections)2 Comparator (java.util.Comparator)2 Iterator (java.util.Iterator)2 List (java.util.List)2 Map (java.util.Map)2 Entry (java.util.Map.Entry)2 Optional (java.util.Optional)2 Set (java.util.Set)2 Executors.newScheduledThreadPool (java.util.concurrent.Executors.newScheduledThreadPool)2 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)2 TimeUnit (java.util.concurrent.TimeUnit)2