Thomas Vachuska
Committed by Gerrit Code Review

Adding a grid topology simulator to the null provider.

Change-Id: Ie655840febc11d3986f1c8ec5c8ef2374014794c
......@@ -20,9 +20,7 @@ package org.onosproject.provider.nil;
*/
public class CentipedeTopologySimulator extends LinearTopologySimulator {
/**
* Creates simulated hosts.
*/
@Override
protected void createHosts() {
deviceIds.forEach(id -> createHosts(id, infrastructurePorts));
}
......
/*
* Copyright 2016 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 static com.google.common.base.Preconditions.checkArgument;
/**
* Rectangular grid topology with hosts at each device.
*/
public class GridTopologySimulator extends TopologySimulator {
private int cols;
private int rows;
@Override
protected void processTopoShape(String shape) {
super.processTopoShape(shape);
rows = topoShape.length > 1 ? Integer.parseInt(topoShape[1]) : 10;
cols = topoShape.length > 2 ? Integer.parseInt(topoShape[2]) : rows;
hostCount = topoShape.length > 3 ? Integer.parseInt(topoShape[3]) : 1;
infrastructurePorts = 4;
deviceCount = rows * cols;
}
@Override
public void setUpTopology() {
checkArgument(rows > 1, "There must be at least 2 rows");
checkArgument(cols > 1, "There must be at least 2 columns");
super.setUpTopology();
}
@Override
protected void createLinks() {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int i = r * cols + c;
if (c < cols - 1) {
createLink(i, i + 1, 3, 1);
}
if (r < rows - 1) {
createLink(i, (r + 1) * cols + c, 4, 2);
}
}
}
}
@Override
protected void createHosts() {
deviceIds.forEach(id -> createHosts(id, infrastructurePorts));
}
}
......@@ -54,6 +54,7 @@ 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;
......@@ -116,7 +117,6 @@ public class NullProviders {
@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();
......@@ -138,7 +138,7 @@ public class NullProviders {
private static final String DEFAULT_TOPO_SHAPE = "configured";
@Property(name = "topoShape", value = DEFAULT_TOPO_SHAPE,
label = "Topology shape: configured, linear, reroute, tree, spineleaf, mesh")
label = "Topology shape: configured, linear, reroute, tree, spineleaf, mesh, grid")
private String topoShape = DEFAULT_TOPO_SHAPE;
private static final int DEFAULT_DEVICE_COUNT = 10;
......@@ -238,7 +238,7 @@ public class NullProviders {
}
// Any change in the following parameters implies hard restart
if (newEnabled != enabled || !newTopoShape.equals(topoShape) ||
if (newEnabled != enabled || !Objects.equals(newTopoShape, topoShape) ||
newDeviceCount != deviceCount || newHostCount != hostCount) {
enabled = newEnabled;
topoShape = newTopoShape;
......@@ -257,7 +257,7 @@ public class NullProviders {
}
// Any change in mastership implies just reassignments.
if (!newMastership.equals(mastership)) {
if (!Objects.equals(newMastership, mastership)) {
mastership = newMastership;
reassignMastership();
}
......@@ -290,6 +290,29 @@ public class NullProviders {
}
}
/**
* 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();
......@@ -310,7 +333,8 @@ public class NullProviders {
packetProvider.start(packetRate, hostService, deviceService,
packetProviderService);
topologyMutationDriver.start(mutationRate, linkService, deviceService,
linkProviderService);
linkProviderService, deviceProviderService,
simulator);
}
// Selects the simulator based on the specified name.
......@@ -329,6 +353,8 @@ public class NullProviders {
return new SpineLeafTopologySimulator();
} else if (topoShape.matches("mesh([,].*|$)")) {
return new MeshTopologySimulator();
} else if (topoShape.matches("grid([,].*|$)")) {
return new GridTopologySimulator();
} else {
return new ConfiguredTopologySimulator();
}
......@@ -398,7 +424,8 @@ public class NullProviders {
@Override
public boolean isReachable(DeviceId deviceId) {
return topoShape.equals("configured") ||
(simulator != null && simulator.contains(deviceId));
(simulator != null && simulator.contains(deviceId) &&
topologyMutationDriver.isReachable(deviceId));
}
@Override
......
......@@ -16,7 +16,11 @@
package org.onosproject.provider.nil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.link.DefaultLinkDescription;
import org.onosproject.net.link.LinkDescription;
......@@ -26,7 +30,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
......@@ -57,6 +63,8 @@ class TopologyMutationDriver implements Runnable {
private LinkService linkService;
private DeviceService deviceService;
private LinkProviderService linkProviderService;
private DeviceProviderService deviceProviderService;
private TopologySimulator simulator;
private List<LinkDescription> activeLinks;
private List<LinkDescription> inactiveLinks;
......@@ -64,6 +72,8 @@ class TopologyMutationDriver implements Runnable {
private final ExecutorService executor =
newSingleThreadScheduledExecutor(groupedThreads("onos/null", "topo-mutator"));
private Map<DeviceId, Set<Link>> savedLinks = Maps.newConcurrentMap();
/**
* Starts the mutation process.
*
......@@ -71,14 +81,21 @@ class TopologyMutationDriver implements Runnable {
* @param linkService link service
* @param deviceService device service
* @param linkProviderService link provider service
* @param deviceProviderService device provider service
* @param simulator topology simulator
*/
void start(double mutationRate,
LinkService linkService, DeviceService deviceService,
LinkProviderService linkProviderService) {
LinkProviderService linkProviderService,
DeviceProviderService deviceProviderService,
TopologySimulator simulator) {
savedLinks.clear();
stopped = false;
this.linkService = linkService;
this.deviceService = deviceService;
this.linkProviderService = linkProviderService;
this.deviceProviderService = deviceProviderService;
this.simulator = simulator;
activeLinks = reduceLinks();
inactiveLinks = Lists.newArrayList();
adjustRate(mutationRate);
......@@ -134,6 +151,41 @@ class TopologyMutationDriver implements Runnable {
linkProviderService.linkDetected(reverse(link));
}
/**
* Fails the specified device.
*
* @param deviceId device identifier
*/
void failDevice(DeviceId deviceId) {
savedLinks.put(deviceId, linkService.getDeviceLinks(deviceId));
deviceProviderService.deviceDisconnected(deviceId);
}
/**
* Repairs the specified device.
*
* @param deviceId device identifier
*/
void repairDevice(DeviceId deviceId) {
int chassisId = Integer.parseInt(deviceId.uri().getSchemeSpecificPart());
simulator.createDevice(deviceId, chassisId);
Set<Link> links = savedLinks.remove(deviceId);
if (links != null) {
links.forEach(l -> linkProviderService
.linkDetected(new DefaultLinkDescription(l.src(), l.dst(), DIRECT)));
}
}
/**
* Returns whether the given device is considered reachable or not.
*
* @param deviceId device identifier
* @return true if device is reachable
*/
boolean isReachable(DeviceId deviceId) {
return !savedLinks.containsKey(deviceId);
}
@Override
public void run() {
delay(WAIT_DELAY);
......
......@@ -172,31 +172,31 @@ public abstract class TopologySimulator {
protected abstract void createHosts();
/**
* Creates simulated device.
* Creates simulated device and adds its id to the list of devices ids.
*
* @param i index of the device id in the list.
*/
protected void createDevice(int i) {
DeviceId id = DeviceId.deviceId(SCHEME + ":" + toHex(i));
deviceIds.add(id);
createDevice(id, i);
}
/**
* Creates simulated device.
*
* @param id device identifier
* @param chassisId chassis identifier number
*/
protected void createDevice(DeviceId id, int chassisId) {
DeviceDescription desc =
new DefaultDeviceDescription(id.uri(), Device.Type.SWITCH,
"ON.Lab", "0.1", "0.1", "1234",
new ChassisId(i));
deviceIds.add(id);
new ChassisId(chassisId));
deviceProviderService.deviceConnected(id, desc);
deviceProviderService.updatePorts(id, buildPorts(hostCount + infrastructurePorts));
}
// /**
// * Creates simulated link between two devices on port 1 and port 2.
// *
// * @param i index of one simulated device
// * @param j index of another simulated device
// */
// protected void createLink(int i, int j) {
// createLink(i, j, 1, 2);
// }
/**
* Creates simulated link between two devices.
*
......@@ -208,6 +208,16 @@ public abstract class TopologySimulator {
protected void createLink(int i, int j, int pi, int pj) {
ConnectPoint one = new ConnectPoint(deviceIds.get(i), PortNumber.portNumber(pi));
ConnectPoint two = new ConnectPoint(deviceIds.get(j), PortNumber.portNumber(pj));
createLink(one, two);
}
/**
* Creates simulated link between two connection points.
*
* @param one one connection point
* @param two another connection point
*/
protected void createLink(ConnectPoint one, ConnectPoint two) {
linkProviderService.linkDetected(new DefaultLinkDescription(one, two, DIRECT));
linkProviderService.linkDetected(new DefaultLinkDescription(two, one, DIRECT));
}
......@@ -359,7 +369,7 @@ public abstract class TopologySimulator {
}
/**
* Indicates whether or not the simulation knows of this device.
* Indicates whether or not the simulation deeps the device as available.
*
* @param deviceId device identifier
* @return true if device is known
......
......@@ -55,6 +55,7 @@ public class TreeTopologySimulator extends TopologySimulator {
@Override
protected void createLinks() {
int portOffset = 1;
for (int t = 1; t < tierOffset.length; t++) {
int child = tierOffset[t];
......
/*
* Copyright 2016 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.cli;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.DeviceId;
import org.onosproject.provider.nil.NullProviders;
import static org.onosproject.cli.UpDownCompleter.DOWN;
import static org.onosproject.cli.UpDownCompleter.UP;
/**
* Servers or repairs a simulated link.
*/
@Command(scope = "onos", name = "null-device",
description = "Severs or repairs a simulated link")
public class NullDeviceCommand extends AbstractShellCommand {
@Argument(index = 0, name = "id", description = "Device identifier",
required = true, multiValued = false)
String id = null;
@Argument(index = 1, name = "cmd", description = "up/down",
required = true, multiValued = false)
String cmd = null;
@Override
protected void execute() {
NullProviders service = get(NullProviders.class);
DeviceId deviceId = DeviceId.deviceId(id);
if (cmd.equals(UP)) {
service.repairDevice(deviceId);
} else if (cmd.equals(DOWN)) {
service.failDevice(deviceId);
} else {
error("Illegal command %s; must be up or down", cmd);
}
}
}
......@@ -50,7 +50,6 @@ public class NullLinkCommand extends AbstractShellCommand {
try {
ConnectPoint onePoint = ConnectPoint.deviceConnectPoint(one);
ConnectPoint twoPoint = ConnectPoint.deviceConnectPoint(two);
if (cmd.equals(UP)) {
......
......@@ -27,6 +27,6 @@ public class TopologyShapeCompleter extends AbstractChoicesCompleter {
@Override
public List<String> choices() {
return ImmutableList.of("configured", "linear", "reroute", "centipede",
"tree", "spineleaf", "mesh");
"tree", "spineleaf", "mesh", "grid");
}
}
......
......@@ -33,6 +33,14 @@
<null/>
</completers>
</command>
<command>
<action class="org.onosproject.provider.nil.cli.NullDeviceCommand"/>
<completers>
<ref component-id="deviceIdCompleter"/>
<ref component-id="upDownCompleter"/>
<null/>
</completers>
</command>
</command-bundle>
<bean id="startStopCompleter" class="org.onosproject.cli.StartStopCompleter"/>
......@@ -40,5 +48,6 @@
<bean id="topoShapeCompleter" class="org.onosproject.provider.nil.cli.TopologyShapeCompleter"/>
<bean id="linkSrcCompleter" class="org.onosproject.cli.net.LinkSrcCompleter"/>
<bean id="linkDstCompleter" class="org.onosproject.cli.net.LinkDstCompleter"/>
<bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
</blueprint>
......