Search in sources :

Example 56 with Path

use of org.onosproject.net.Path in project trellis-control by opennetworkinglab.

the class McastHandler method recoverSinks.

/**
 * Try to recover sinks using alternative locations.
 *
 * @param notRecovered the device not recovered
 * @param mcastIp the group address
 * @param affectedSources affected sources
 * @param goodSources sources not affected
 */
private Optional<Path> recoverSinks(DeviceId notRecovered, IpAddress mcastIp, Set<ConnectPoint> affectedSources, Set<ConnectPoint> goodSources) {
    log.debug("Processing recover sinks on {} for group {}", notRecovered, mcastIp);
    Map<ConnectPoint, Set<ConnectPoint>> affectedSinksBySource = Maps.newHashMap();
    Map<ConnectPoint, Set<ConnectPoint>> sinksBySource = Maps.newHashMap();
    Set<ConnectPoint> sources = Sets.union(affectedSources, goodSources);
    // Hosts influenced by the failure
    Map<HostId, Set<ConnectPoint>> hostIdSetMap = mcastUtils.getAffectedSinks(notRecovered, mcastIp);
    // Locations influenced by the failure
    Set<ConnectPoint> affectedSinks = hostIdSetMap.values().stream().flatMap(Collection::stream).filter(connectPoint -> connectPoint.deviceId().equals(notRecovered)).collect(Collectors.toSet());
    // All locations
    Set<ConnectPoint> sinks = hostIdSetMap.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
    // Maps sinks with the sources
    sources.forEach(source -> {
        Set<ConnectPoint> currentSinks = affectedSinks.stream().filter(sink -> isSinkForSource(mcastIp, sink, source)).collect(Collectors.toSet());
        affectedSinksBySource.put(source, currentSinks);
    });
    // Remove sinks one by one if they are not used by other sources
    affectedSources.forEach(affectedSource -> {
        Set<ConnectPoint> currentSinks = affectedSinksBySource.get(affectedSource);
        log.info("Current sinks {} for source {}", currentSinks, affectedSource);
        currentSinks.forEach(currentSink -> {
            VlanId assignedVlan = mcastUtils.assignedVlan(affectedSource.deviceId().equals(currentSink.deviceId()) ? affectedSource : null);
            log.info("Assigned vlan {}", assignedVlan);
            Set<VlanId> otherVlans = goodSources.stream().filter(remainingSource -> affectedSinksBySource.get(remainingSource).contains(currentSink)).map(remainingSource -> mcastUtils.assignedVlan(remainingSource.deviceId().equals(currentSink.deviceId()) ? remainingSource : null)).collect(Collectors.toSet());
            log.info("Other vlans {}", otherVlans);
            // Sinks on other leaves
            if (!otherVlans.contains(assignedVlan)) {
                removePortFromDevice(currentSink.deviceId(), currentSink.port(), mcastIp, assignedVlan);
            }
            mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, currentSink.deviceId(), affectedSource));
        });
    });
    // Get the sinks to be added and the new egress
    Set<DeviceId> newEgress = Sets.newHashSet();
    affectedSources.forEach(affectedSource -> {
        Set<ConnectPoint> currentSinks = affectedSinksBySource.get(affectedSource);
        Set<ConnectPoint> newSinks = Sets.difference(sinks, currentSinks);
        sinksBySource.put(affectedSource, newSinks);
        newSinks.stream().map(ConnectPoint::deviceId).forEach(newEgress::add);
    });
    log.info("newEgress {}", newEgress);
    // If there are more than one new egresses, return the problem
    if (newEgress.size() != 1) {
        log.warn("There are {} new egress, wrong configuration. Abort.", newEgress.size());
        return Optional.empty();
    }
    DeviceId egress = newEgress.stream().findFirst().orElse(null);
    DeviceId ingress = affectedSources.stream().map(ConnectPoint::deviceId).findFirst().orElse(null);
    log.info("Ingress {}", ingress);
    if (ingress == null) {
        log.warn("No new ingress, wrong configuration. Abort.");
        return Optional.empty();
    }
    // Get an alternative path
    Optional<Path> alternativePath = getPath(ingress, egress, mcastIp, null);
    // If there are new path install sinks and return path
    if (alternativePath.isPresent()) {
        log.info("Alternative path {}", alternativePath.get().links());
        affectedSources.forEach(affectedSource -> {
            Set<ConnectPoint> newSinks = sinksBySource.get(affectedSource);
            newSinks.forEach(newSink -> {
                addPortToDevice(newSink.deviceId(), newSink.port(), mcastIp, mcastUtils.assignedVlan(null));
                mcastRoleStore.put(new McastRoleStoreKey(mcastIp, newSink.deviceId(), affectedSource), EGRESS);
            });
        });
        return alternativePath;
    }
    // No new path but sinks co-located with sources install sinks and return empty
    if (ingress.equals(egress)) {
        log.info("No Alternative path but sinks co-located");
        affectedSources.forEach(affectedSource -> {
            Set<ConnectPoint> newSinks = sinksBySource.get(affectedSource);
            newSinks.forEach(newSink -> {
                if (affectedSource.port().equals(newSink.port())) {
                    log.warn("Skip {} since sink {} is on the same port of source {}. Abort", mcastIp, newSink, affectedSource);
                    return;
                }
                addPortToDevice(newSink.deviceId(), newSink.port(), mcastIp, mcastUtils.assignedVlan(affectedSource));
                mcastRoleStore.put(new McastRoleStoreKey(mcastIp, newSink.deviceId(), affectedSource), INGRESS);
            });
        });
    }
    return Optional.empty();
}
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) HostId(org.onosproject.net.HostId) ConnectPoint(org.onosproject.net.ConnectPoint) Collection(java.util.Collection) VlanId(org.onlab.packet.VlanId)

Example 57 with Path

use of org.onosproject.net.Path in project trellis-control by opennetworkinglab.

the class McastHandler method getPath.

/**
 * Gets a path from src to dst.
 * If a path was allocated before, returns the allocated path.
 * Otherwise, randomly pick one from available paths.
 *
 * @param src source device ID
 * @param dst destination device ID
 * @param mcastIp multicast group
 * @param allPaths paths list
 *
 * @return an optional path from src to dst
 */
private Optional<Path> getPath(DeviceId src, DeviceId dst, IpAddress mcastIp, List<Path> allPaths) {
    if (allPaths == null) {
        allPaths = mcastUtils.getPaths(src, dst, Collections.emptySet());
    }
    if (allPaths.isEmpty()) {
        return Optional.empty();
    }
    // Create a map index of suitability-to-list of paths. For example
    // a path in the list associated to the index 1 shares only one link
    // and it is less suitable of a path belonging to the index 2
    Map<Integer, List<Path>> eligiblePaths = Maps.newHashMap();
    int score;
    // Let's build the multicast tree
    Set<List<Link>> storedPaths = getStoredPaths(mcastIp);
    Set<Link> storedTree = storedPaths.stream().flatMap(Collection::stream).collect(Collectors.toSet());
    log.trace("Stored tree {}", storedTree);
    Set<Link> pathLinks;
    for (Path path : allPaths) {
        if (!src.equals(path.links().get(0).src().deviceId())) {
            continue;
        }
        pathLinks = Sets.newHashSet(path.links());
        score = Sets.intersection(pathLinks, storedTree).size();
        // score defines the index
        if (score > 0) {
            eligiblePaths.compute(score, (index, paths) -> {
                paths = paths == null ? Lists.newArrayList() : paths;
                paths.add(path);
                return paths;
            });
        }
    }
    if (eligiblePaths.isEmpty()) {
        log.trace("No eligiblePath(s) found from {} to {}", src, dst);
        Collections.shuffle(allPaths);
        return allPaths.stream().findFirst();
    }
    // Let's take the best ones
    Integer bestIndex = eligiblePaths.keySet().stream().sorted(Comparator.reverseOrder()).findFirst().orElse(null);
    List<Path> bestPaths = eligiblePaths.get(bestIndex);
    log.trace("{} eligiblePath(s) found from {} to {}", bestPaths.size(), src, dst);
    Collections.shuffle(bestPaths);
    return bestPaths.stream().findFirst();
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Path(org.onosproject.net.Path) List(java.util.List) ConnectPoint(org.onosproject.net.ConnectPoint) Link(org.onosproject.net.Link)

Example 58 with Path

use of org.onosproject.net.Path in project trellis-control by opennetworkinglab.

the class DefaultL2TunnelHandler method getPath.

/**
 * Returns the path betwwen two connect points.
 *
 * @param srcCp source connect point
 * @param dstCp destination connect point
 * @return the path
 */
private List<Link> getPath(ConnectPoint srcCp, ConnectPoint dstCp) {
    // use SRLinkWeigher to avoid pair links, and also
    // avoid going from the spine to the leaf and to the
    // spine again, we need to have the leaf as CP1 here.
    LinkWeigher srLw = new SRLinkWeigher(srManager, srcCp.deviceId(), new HashSet<Link>());
    Set<Path> paths = srManager.topologyService.getPaths(srManager.topologyService.currentTopology(), srcCp.deviceId(), dstCp.deviceId(), srLw);
    log.debug("Paths obtained from topology service {}", paths);
    // We randomly pick a path.
    if (paths.isEmpty()) {
        return null;
    }
    int size = paths.size();
    int index = RandomUtils.nextInt(0, size);
    List<Link> result = Iterables.get(paths, index).links();
    log.debug("Randomly picked a path {}", result);
    return result;
}
Also used : Path(org.onosproject.net.Path) SRLinkWeigher(org.onosproject.segmentrouting.SRLinkWeigher) LinkWeigher(org.onosproject.net.topology.LinkWeigher) SRLinkWeigher(org.onosproject.segmentrouting.SRLinkWeigher) Link(org.onosproject.net.Link) DefaultLink(org.onosproject.net.DefaultLink) ConnectPoint(org.onosproject.net.ConnectPoint)

Example 59 with Path

use of org.onosproject.net.Path in project trellis-control by opennetworkinglab.

the class McastUtils method exploreMcastTree.

/**
 * Go through all the paths, looking for shared links to be used
 * in the final path computation.
 *
 * @param egresses egress devices
 * @param availablePaths all the available paths towards the egress
 * @return shared links between egress devices
 */
private Set<Link> exploreMcastTree(Set<DeviceId> egresses, Map<DeviceId, List<Path>> availablePaths) {
    int minLength = Integer.MAX_VALUE;
    int length;
    List<Path> currentPaths;
    // Verify the source can still reach all the egresses
    for (DeviceId egress : egresses) {
        // From the source we cannot reach all the sinks
        // just continue and let's figure out after
        currentPaths = availablePaths.get(egress);
        if (currentPaths.isEmpty()) {
            continue;
        }
        // Get the length of the first one available, update the min length
        length = currentPaths.get(0).links().size();
        if (length < minLength) {
            minLength = length;
        }
    }
    // If there are no paths
    if (minLength == Integer.MAX_VALUE) {
        return Collections.emptySet();
    }
    int index = 0;
    Set<Link> sharedLinks = Sets.newHashSet();
    Set<Link> currentSharedLinks;
    Set<Link> currentLinks;
    DeviceId egressToRemove = null;
    // Let's find out the shared links
    while (index < minLength) {
        // Initialize the intersection with the paths related to the first egress
        currentPaths = availablePaths.get(egresses.stream().findFirst().orElse(null));
        currentSharedLinks = Sets.newHashSet();
        // Iterate over the paths and take the "index" links
        for (Path path : currentPaths) {
            currentSharedLinks.add(path.links().get(index));
        }
        // Iterate over the remaining egress
        for (DeviceId egress : egresses) {
            // Iterate over the paths and take the "index" links
            currentLinks = Sets.newHashSet();
            for (Path path : availablePaths.get(egress)) {
                currentLinks.add(path.links().get(index));
            }
            // Do intersection
            currentSharedLinks = Sets.intersection(currentSharedLinks, currentLinks);
            // we have to retry with a subset of sinks
            if (currentSharedLinks.isEmpty()) {
                egressToRemove = egress;
                index = minLength;
                break;
            }
        }
        sharedLinks.addAll(currentSharedLinks);
        index++;
    }
    // we can still build optimal subtrees
    if (sharedLinks.isEmpty() && egresses.size() > 1 && egressToRemove != null) {
        egresses.remove(egressToRemove);
        sharedLinks = exploreMcastTree(egresses, availablePaths);
    }
    return sharedLinks;
}
Also used : Path(org.onosproject.net.Path) DeviceId(org.onosproject.net.DeviceId) ConnectPoint(org.onosproject.net.ConnectPoint) Link(org.onosproject.net.Link)

Example 60 with Path

use of org.onosproject.net.Path in project trellis-control by opennetworkinglab.

the class McastUtils method getPaths.

/**
 * Gets path from src to dst computed using the custom link weigher.
 *
 * @param src source device ID
 * @param dst destination device ID
 * @param linksToEnforce links to be enforced
 * @return list of paths from src to dst
 */
List<Path> getPaths(DeviceId src, DeviceId dst, Set<Link> linksToEnforce) {
    final Topology currentTopology = topologyService.currentTopology();
    final LinkWeigher linkWeigher = new SRLinkWeigher(srManager, src, linksToEnforce);
    List<Path> allPaths = Lists.newArrayList(topologyService.getPaths(currentTopology, src, dst, linkWeigher));
    log.trace("{} path(s) found from {} to {}", allPaths.size(), src, dst);
    return allPaths;
}
Also used : Path(org.onosproject.net.Path) SRLinkWeigher(org.onosproject.segmentrouting.SRLinkWeigher) LinkWeigher(org.onosproject.net.topology.LinkWeigher) Topology(org.onosproject.net.topology.Topology) SRLinkWeigher(org.onosproject.segmentrouting.SRLinkWeigher)

Aggregations

Path (org.onosproject.net.Path)60 DeviceId (org.onosproject.net.DeviceId)27 DefaultPath (org.onosproject.net.DefaultPath)24 Link (org.onosproject.net.Link)23 DisjointPath (org.onosproject.net.DisjointPath)22 ConnectPoint (org.onosproject.net.ConnectPoint)18 Test (org.junit.Test)16 ImmutableSet (com.google.common.collect.ImmutableSet)12 ArrayList (java.util.ArrayList)11 List (java.util.List)11 Set (java.util.Set)11 Collectors (java.util.stream.Collectors)10 DefaultLink (org.onosproject.net.DefaultLink)10 Intent (org.onosproject.net.intent.Intent)10 Collections (java.util.Collections)9 Topology (org.onosproject.net.topology.Topology)8 Logger (org.slf4j.Logger)8 Stream (java.util.stream.Stream)7 ScalarWeight (org.onlab.graph.ScalarWeight)7 HostId (org.onosproject.net.HostId)7