blob: efbaf9141f2a8e09a9fcaba4f66c9b6ab62c4153 [file] [log] [blame]
/*
* 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.incubator.net.virtual.impl;
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.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
import org.onosproject.incubator.net.virtual.VirtualNetworkProviderRegistry;
import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
import org.onosproject.net.link.LinkEvent;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyCluster;
import org.onosproject.net.topology.TopologyEvent;
import org.onosproject.net.topology.TopologyListener;
import org.onosproject.net.topology.TopologyService;
import org.slf4j.Logger;
import java.util.HashSet;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Virtual network topology provider.
*/
@Component(immediate = true)
@Service
public class VirtualNetworkTopologyProvider extends AbstractProvider implements VirtualNetworkProvider {
private final Logger log = getLogger(VirtualNetworkTopologyProvider.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected VirtualNetworkProviderRegistry providerRegistry;
private VirtualNetworkProviderService providerService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
protected TopologyListener topologyListener = new InternalTopologyListener();
/**
* Default constructor.
*/
public VirtualNetworkTopologyProvider() {
super(DefaultVirtualLink.PID);
}
@Activate
public void activate() {
providerService = providerRegistry.register(this);
topologyService.addListener(topologyListener);
log.info("Started");
}
@Deactivate
public void deactivate() {
topologyService.removeListener(topologyListener);
providerRegistry.unregister(this);
providerService = null;
log.info("Stopped");
}
@Override
public boolean isTraversable(ConnectPoint src, ConnectPoint dst) {
final boolean[] foundSrc = new boolean[1];
final boolean[] foundDst = new boolean[1];
Topology topology = topologyService.currentTopology();
Set<Path> paths = topologyService.getPaths(topology, src.deviceId(), dst.deviceId());
paths.forEach(path -> {
foundDst[0] = false;
foundSrc[0] = false;
// Traverse the links in each path to determine if both the src and dst connection
// point are in the path, if so then this src/dst pair are traversable.
path.links().forEach(link -> {
if (link.src().equals(src)) {
foundSrc[0] = true;
}
if (link.dst().equals(dst)) {
foundDst[0] = true;
}
});
if (foundSrc[0] && foundDst[0]) {
return;
}
});
return foundSrc[0] && foundDst[0];
}
@Override
public TunnelId createTunnel(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
return null;
}
@Override
public void destroyTunnel(NetworkId networkId, TunnelId tunnelId) {
}
/**
* Returns a set of set of interconnected connect points in the default topology.
* The inner set represents the interconnected connect points, and the outerset
* represents separate clusters.
*
* @param topology the default topology
* @return set of set of interconnected connect points.
*/
protected Set<Set<ConnectPoint>> getConnectPoints(Topology topology) {
Set<Set<ConnectPoint>> clusters = new HashSet<>();
Set<TopologyCluster> topologyClusters = topologyService.getClusters(topology);
topologyClusters.forEach(topologyCluster -> {
Set<ConnectPoint> connectPointSet = new HashSet<>();
Set<Link> clusterLinks = topologyService.getClusterLinks(topology, topologyCluster);
clusterLinks.forEach(link -> {
connectPointSet.add(link.src());
connectPointSet.add(link.dst());
});
if (!connectPointSet.isEmpty()) {
clusters.add(connectPointSet);
}
});
return clusters;
}
/**
* Topology event listener.
*/
private class InternalTopologyListener implements TopologyListener {
@Override
public void event(TopologyEvent event) {
if (!isRelevant(event)) {
return;
}
Topology topology = event.subject();
providerService.topologyChanged(getConnectPoints(topology));
}
@Override
public boolean isRelevant(TopologyEvent event) {
final boolean[] relevant = {false};
if (event.type().equals(TopologyEvent.Type.TOPOLOGY_CHANGED)) {
event.reasons().forEach(event1 -> {
// Only LinkEvents are relevant events, ie: DeviceEvents and others are ignored.
if (event1 instanceof LinkEvent) {
relevant[0] = true;
return;
}
});
}
return relevant[0];
}
}
}