| /* |
| * Copyright 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.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.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.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") |
| 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 = 5; |
| @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 || !newTopoShape.equals(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 (!newMastership.equals(mastership)) { |
| mastership = newMastership; |
| reassignMastership(); |
| } |
| |
| log.info(FORMAT, enabled, topoShape, deviceCount, hostCount, |
| packetRate, mutationRate); |
| } |
| |
| /** |
| * 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); |
| } |
| } |
| |
| // 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); |
| simulator.setUpTopology(); |
| flowRuleProvider.start(flowRuleProviderService); |
| packetProvider.start(packetRate, hostService, deviceService, |
| packetProviderService); |
| topologyMutationDriver.start(mutationRate, linkService, deviceService, |
| linkProviderService); |
| } |
| |
| // 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 { |
| 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("configured") || |
| (simulator != null && simulator.contains(deviceId)); |
| } |
| |
| @Override |
| public void triggerProbe(DeviceId deviceId) { |
| } |
| } |
| |
| // 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 { |
| } |
| |
| } |