blob: 5d65caf6dfcb463196860cd50ee7e173f2b8cecb [file] [log] [blame]
/*
* Copyright 2015-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.provider.nil;
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.apache.felix.scr.annotations.Service;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.NodeId;
import org.onosproject.mastership.MastershipAdminService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceAdminService;
import org.onosproject.net.device.DeviceProvider;
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.flow.FlowRuleProviderRegistry;
import org.onosproject.net.flow.FlowRuleProviderService;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.HostProviderRegistry;
import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.host.HostService;
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.PacketProviderRegistry;
import org.onosproject.net.packet.PacketProviderService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.util.Dictionary;
import java.util.Objects;
import java.util.Properties;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onlab.util.Tools.delay;
import static org.onlab.util.Tools.get;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.MastershipRole.MASTER;
import static org.onosproject.net.MastershipRole.NONE;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider of a fake network environment, i.e. devices, links, hosts, etc.
* To be used for benchmarking only.
*/
@Component(immediate = true)
@Service(value = NullProviders.class)
public class NullProviders {
private static final Logger log = getLogger(NullProviders.class);
static final String SCHEME = "null";
static final String PROVIDER_ID = "org.onosproject.provider.nil";
private static final String FORMAT =
"Settings: enabled={}, topoShape={}, deviceCount={}, " +
"hostCount={}, packetRate={}, mutationRate={}";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipAdminService mastershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService cfgService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceAdminService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkService linkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceProviderRegistry deviceProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostProviderRegistry hostProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkProviderRegistry linkProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleProviderRegistry flowRuleProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketProviderRegistry packetProviderRegistry;
private final NullDeviceProvider deviceProvider = new NullDeviceProvider();
private final NullLinkProvider linkProvider = new NullLinkProvider();
private final NullHostProvider hostProvider = new NullHostProvider();
private final NullFlowRuleProvider flowRuleProvider = new NullFlowRuleProvider();
private final NullPacketProvider packetProvider = new NullPacketProvider();
private final TopologyMutationDriver topologyMutationDriver = new TopologyMutationDriver();
private DeviceProviderService deviceProviderService;
private HostProviderService hostProviderService;
private LinkProviderService linkProviderService;
private FlowRuleProviderService flowRuleProviderService;
private PacketProviderService packetProviderService;
private TopologySimulator simulator;
@Property(name = "enabled", boolValue = false,
label = "Enables or disables the provider")
private boolean enabled = false;
private static final String DEFAULT_TOPO_SHAPE = "configured";
@Property(name = "topoShape", value = DEFAULT_TOPO_SHAPE,
label = "Topology shape: configured, linear, reroute, tree, spineleaf, mesh, grid")
private String topoShape = DEFAULT_TOPO_SHAPE;
private static final int DEFAULT_DEVICE_COUNT = 10;
@Property(name = "deviceCount", intValue = DEFAULT_DEVICE_COUNT,
label = "Number of devices to generate")
private int deviceCount = DEFAULT_DEVICE_COUNT;
private static final int DEFAULT_HOST_COUNT = 5;
@Property(name = "hostCount", intValue = DEFAULT_HOST_COUNT,
label = "Number of host to generate per device")
private int hostCount = DEFAULT_HOST_COUNT;
private static final int DEFAULT_PACKET_RATE = 0;
@Property(name = "packetRate", intValue = DEFAULT_PACKET_RATE,
label = "Packet-in/s rate; 0 for no packets")
private int packetRate = DEFAULT_PACKET_RATE;
private static final double DEFAULT_MUTATION_RATE = 0;
@Property(name = "mutationRate", doubleValue = DEFAULT_MUTATION_RATE,
label = "Link event/s topology mutation rate; 0 for no mutations")
private double mutationRate = DEFAULT_MUTATION_RATE;
private static final String DEFAULT_MASTERSHIP = "random";
@Property(name = "mastership", value = DEFAULT_MASTERSHIP,
label = "Mastership given as 'random' or 'node1=dpid,dpid/node2=dpid,...'")
private String mastership = DEFAULT_MASTERSHIP;
@Activate
public void activate() {
cfgService.registerProperties(getClass());
deviceProviderService = deviceProviderRegistry.register(deviceProvider);
hostProviderService = hostProviderRegistry.register(hostProvider);
linkProviderService = linkProviderRegistry.register(linkProvider);
flowRuleProviderService = flowRuleProviderRegistry.register(flowRuleProvider);
packetProviderService = packetProviderRegistry.register(packetProvider);
log.info("Started");
}
@Deactivate
public void deactivate() {
cfgService.unregisterProperties(getClass(), false);
tearDown();
deviceProviderRegistry.unregister(deviceProvider);
hostProviderRegistry.unregister(hostProvider);
linkProviderRegistry.unregister(linkProvider);
flowRuleProviderRegistry.unregister(flowRuleProvider);
packetProviderRegistry.unregister(packetProvider);
deviceProviderService = null;
hostProviderService = null;
linkProviderService = null;
flowRuleProviderService = null;
packetProviderService = null;
log.info("Stopped");
}
@Modified
public void modified(ComponentContext context) {
Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
boolean newEnabled;
int newDeviceCount, newHostCount, newPacketRate;
double newMutationRate;
String newTopoShape, newMastership;
try {
String s = get(properties, "enabled");
newEnabled = isNullOrEmpty(s) ? enabled : Boolean.parseBoolean(s.trim());
newTopoShape = get(properties, "topoShape");
newMastership = get(properties, "mastership");
s = get(properties, "deviceCount");
newDeviceCount = isNullOrEmpty(s) ? deviceCount : Integer.parseInt(s.trim());
s = get(properties, "hostCount");
newHostCount = isNullOrEmpty(s) ? hostCount : Integer.parseInt(s.trim());
s = get(properties, "packetRate");
newPacketRate = isNullOrEmpty(s) ? packetRate : Integer.parseInt(s.trim());
s = get(properties, "mutationRate");
newMutationRate = isNullOrEmpty(s) ? mutationRate : Double.parseDouble(s.trim());
} catch (NumberFormatException e) {
log.warn(e.getMessage());
newEnabled = enabled;
newTopoShape = topoShape;
newDeviceCount = deviceCount;
newHostCount = hostCount;
newPacketRate = packetRate;
newMutationRate = mutationRate;
newMastership = mastership;
}
// Any change in the following parameters implies hard restart
if (newEnabled != enabled || !Objects.equals(newTopoShape, topoShape) ||
newDeviceCount != deviceCount || newHostCount != hostCount) {
enabled = newEnabled;
topoShape = newTopoShape;
deviceCount = newDeviceCount;
hostCount = newHostCount;
packetRate = newPacketRate;
mutationRate = newMutationRate;
restartSimulation();
}
// Any change in the following parameters implies just a rate change
if (newPacketRate != packetRate || newMutationRate != mutationRate) {
packetRate = newPacketRate;
mutationRate = newMutationRate;
adjustRates();
}
// Any change in mastership implies just reassignments.
if (!Objects.equals(newMastership, mastership)) {
mastership = newMastership;
reassignMastership();
}
log.info(FORMAT, enabled, topoShape, deviceCount, hostCount,
packetRate, mutationRate);
}
/**
* Returns the currently active topology simulator.
*
* @return current simulator; null if none is active
*/
public TopologySimulator currentSimulator() {
return simulator;
}
/**
* Severs the link between the specified end-points in both directions.
*
* @param one link endpoint
* @param two link endpoint
*/
public void severLink(ConnectPoint one, ConnectPoint two) {
if (enabled) {
topologyMutationDriver.severLink(one, two);
}
}
/**
* Severs the link between the specified end-points in both directions.
*
* @param one link endpoint
* @param two link endpoint
*/
public void repairLink(ConnectPoint one, ConnectPoint two) {
if (enabled) {
topologyMutationDriver.repairLink(one, two);
}
}
/**
* Fails the specified device.
*
* @param deviceId device identifier
*/
public void failDevice(DeviceId deviceId) {
if (enabled) {
topologyMutationDriver.failDevice(deviceId);
}
}
/**
* Repairs the specified device.
*
* @param deviceId device identifier
*/
public void repairDevice(DeviceId deviceId) {
if (enabled) {
topologyMutationDriver.repairDevice(deviceId);
}
}
// Resets simulation based on the current configuration parameters.
private void restartSimulation() {
tearDown();
if (enabled) {
setUp();
}
}
// Sets up the topology simulation and all providers.
private void setUp() {
simulator = selectSimulator(topoShape);
simulator.init(topoShape, deviceCount, hostCount,
new DefaultServiceDirectory(),
deviceProviderService, hostProviderService,
linkProviderService);
flowRuleProvider.start(flowRuleProviderService);
packetProvider.start(packetRate, hostService, deviceService,
packetProviderService);
simulator.setUpTopology();
topologyMutationDriver.start(mutationRate, linkService, deviceService,
linkProviderService, deviceProviderService,
simulator);
}
// Selects the simulator based on the specified name.
private TopologySimulator selectSimulator(String topoShape) {
if (topoShape.matches("linear([,].*|$)")) {
return new LinearTopologySimulator();
} else if (topoShape.matches("centipede([,].*|$)")) {
return new CentipedeTopologySimulator();
} else if (topoShape.matches("reroute([,].*|$)")) {
return new RerouteTopologySimulator();
} else if (topoShape.matches("tree([,].*|$)")) {
return new TreeTopologySimulator();
} else if (topoShape.matches("agglink([,].*|$)")) {
return new AggLinkTopologySimulator();
} else if (topoShape.matches("spineleaf([,].*|$)")) {
return new SpineLeafTopologySimulator();
} else if (topoShape.matches("mesh([,].*|$)")) {
return new MeshTopologySimulator();
} else if (topoShape.matches("grid([,].*|$)")) {
return new GridTopologySimulator();
} else if (topoShape.matches("fattree([,].*|$)")) {
return new FatTreeTopologySimulator();
} else if (topoShape.matches("custom([,].*|$)")) {
return new CustomTopologySimulator();
} else {
return new ConfiguredTopologySimulator();
}
}
// Shuts down the topology simulator and all providers.
private void tearDown() {
if (simulator != null) {
topologyMutationDriver.stop();
packetProvider.stop();
flowRuleProvider.stop();
delay(500);
simulator.tearDownTopology();
simulator = null;
}
}
// Changes packet and mutation rates.
private void adjustRates() {
packetProvider.adjustRate(packetRate);
topologyMutationDriver.adjustRate(mutationRate);
}
// Re-assigns mastership roles.
private void reassignMastership() {
if (mastership.equals(DEFAULT_MASTERSHIP)) {
mastershipService.balanceRoles();
} else {
NodeId localNode = clusterService.getLocalNode().id();
rejectMastership();
String[] nodeSpecs = mastership.split("/");
for (int i = 0; i < nodeSpecs.length; i++) {
String[] specs = nodeSpecs[i].split("=");
if (specs[0].equals(localNode.toString())) {
String[] ids = specs[1].split(",");
for (String id : ids) {
mastershipService.setRole(localNode, deviceId(id), MASTER);
}
break;
}
}
}
}
// Rejects mastership of all devices.
private void rejectMastership() {
NodeId localNode = clusterService.getLocalNode().id();
deviceService.getDevices()
.forEach(device -> mastershipService.setRole(localNode, device.id(),
NONE));
}
// Null provider base class.
abstract static class AbstractNullProvider extends AbstractProvider {
protected AbstractNullProvider() {
super(new ProviderId(SCHEME, PROVIDER_ID));
}
}
// Device provider facade.
private class NullDeviceProvider extends AbstractNullProvider implements DeviceProvider {
@Override
public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
deviceProviderService.receivedRoleReply(deviceId, newRole, newRole);
}
@Override
public boolean isReachable(DeviceId deviceId) {
return topoShape.equals("custom") ||
(simulator != null && simulator.contains(deviceId) &&
topologyMutationDriver.isReachable(deviceId));
}
@Override
public void triggerProbe(DeviceId deviceId) {
}
@Override
public void changePortState(DeviceId deviceId, PortNumber portNumber,
boolean enable) {
// TODO maybe required
}
}
// Host provider facade.
private class NullHostProvider extends AbstractNullProvider implements HostProvider {
@Override
public void triggerProbe(Host host) {
}
}
// Host provider facade.
private class NullLinkProvider extends AbstractNullProvider implements LinkProvider {
}
}