mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 12:16:13 +02:00
[Emu] FlowAnalyzer app code and tests
Change-Id: I8b6f83f7d2e76a4e8cf770d9b0018be283e91bf3
This commit is contained in:
parent
5fb20a5318
commit
d6734f654b
@ -40,6 +40,38 @@
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.compendium</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onlab-junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-api</artifactId>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.scr.annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-cli</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf.shell</groupId>
|
||||
<artifactId>org.apache.karaf.shell.console</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.flowanalyzer;
|
||||
|
||||
import org.apache.karaf.shell.commands.Command;
|
||||
import org.onosproject.cli.AbstractShellCommand;
|
||||
|
||||
/**
|
||||
* Analyzes flows for cycles and black holes.
|
||||
*/
|
||||
@Command(scope = "onos", name = "flow-analysis",
|
||||
description = "Analyzes flows for cycles and black holes")
|
||||
public class FlowAnalysisCommand extends AbstractShellCommand {
|
||||
|
||||
@Override
|
||||
protected void execute() {
|
||||
FlowAnalyzer service = get(FlowAnalyzer.class);
|
||||
print(service.analyze());
|
||||
}
|
||||
}
|
||||
@ -21,12 +21,31 @@ 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.net.ConnectPoint;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.flow.FlowEntry;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.net.host.HostService;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.HostId;
|
||||
import org.onosproject.net.flow.criteria.Criteria;
|
||||
import org.onosproject.net.flow.criteria.Criterion;
|
||||
import org.onosproject.net.flow.criteria.PortCriterion;
|
||||
import org.onosproject.net.flow.instructions.Instruction;
|
||||
import org.onosproject.net.flow.instructions.Instructions;
|
||||
import org.onosproject.net.topology.TopologyService;
|
||||
import org.onosproject.net.topology.TopologyGraph;
|
||||
import org.onosproject.net.link.LinkService;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.topology.TopologyVertex;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
/**
|
||||
@ -42,11 +61,10 @@ public class FlowAnalyzer {
|
||||
protected FlowRuleService flowRuleService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected LinkService linkService;
|
||||
protected TopologyService topologyService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected HostService hostService;
|
||||
|
||||
protected LinkService linkService;
|
||||
|
||||
@Activate
|
||||
public void activate(ComponentContext context) {
|
||||
@ -58,12 +76,193 @@ public class FlowAnalyzer {
|
||||
log.info("Stopped");
|
||||
}
|
||||
|
||||
TopologyGraph graph;
|
||||
Map<FlowEntry, String> label = new HashMap<>();
|
||||
Set<FlowEntry> ignoredFlows = new HashSet<>();
|
||||
|
||||
/**
|
||||
* ...
|
||||
* Analyzes and prints out a report on the status of every flow entry inside
|
||||
* the network. The possible states are: Cleared (implying that the entry leads to
|
||||
* a host), Cycle (implying that it is part of cycle), and Black Hole (implying
|
||||
* that the entry does not lead to a single host).
|
||||
*/
|
||||
public void analyze() {
|
||||
// TODO: implement this
|
||||
public String analyze() {
|
||||
graph = topologyService.getGraph(topologyService.currentTopology());
|
||||
for (TopologyVertex v: graph.getVertexes()) {
|
||||
DeviceId srcDevice = v.deviceId();
|
||||
Iterable<FlowEntry> flowTable = flowRuleService.getFlowEntries(srcDevice);
|
||||
for (FlowEntry flow: flowTable) {
|
||||
dfs(flow);
|
||||
}
|
||||
}
|
||||
|
||||
//analyze the cycles to look for "critical flows" that can be removed
|
||||
//to break the cycle
|
||||
Set<FlowEntry> critpts = new HashSet<>();
|
||||
for (FlowEntry flow: label.keySet()) {
|
||||
if ("Cycle".equals(label.get(flow))) {
|
||||
Map<FlowEntry, String> labelSaved = label;
|
||||
label = new HashMap<FlowEntry, String>();
|
||||
ignoredFlows.add(flow);
|
||||
for (TopologyVertex v: graph.getVertexes()) {
|
||||
DeviceId srcDevice = v.deviceId();
|
||||
Iterable<FlowEntry> flowTable = flowRuleService.getFlowEntries(srcDevice);
|
||||
for (FlowEntry flow1: flowTable) {
|
||||
dfs(flow1);
|
||||
}
|
||||
}
|
||||
|
||||
boolean replacable = true;
|
||||
for (FlowEntry flow2: label.keySet()) {
|
||||
if ("Cleared".equals(labelSaved.get(flow2)) && !("Cleared".equals(label.get(flow2)))) {
|
||||
replacable = false;
|
||||
}
|
||||
}
|
||||
if (replacable) {
|
||||
critpts.add(flow);
|
||||
}
|
||||
label = labelSaved;
|
||||
}
|
||||
}
|
||||
|
||||
for (FlowEntry flow: critpts) {
|
||||
label.put(flow, "Cycle Critical Point");
|
||||
}
|
||||
|
||||
String s = "\n";
|
||||
for (FlowEntry flow: label.keySet()) {
|
||||
s += ("Flow Rule: " + flowEntryRepresentation(flow) + "\n");
|
||||
s += ("Analysis: " + label.get(flow) + "!\n\n");
|
||||
}
|
||||
s += ("Analyzed " + label.keySet().size() + " flows.");
|
||||
//log.info(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public Map<FlowEntry, String> calcLabels() {
|
||||
analyze();
|
||||
return label;
|
||||
}
|
||||
public String analysisOutput() {
|
||||
analyze();
|
||||
String s = "\n";
|
||||
for (FlowEntry flow: label.keySet()) {
|
||||
s += ("Flow Rule: " + flowEntryRepresentation(flow) + "\n");
|
||||
s += ("Analysis: " + label.get(flow) + "!\n\n");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private boolean dfs(FlowEntry flow) {
|
||||
if (ignoredFlows.contains(flow)) {
|
||||
return false;
|
||||
}
|
||||
if ("Cycle".equals(label.get(flow)) ||
|
||||
"Black Hole".equals(label.get(flow)) ||
|
||||
"Cleared".equals(label.get(flow)) ||
|
||||
"NA".equals(label.get(flow)) ||
|
||||
"Cycle Critical Point".equals(label.get(flow))) {
|
||||
|
||||
// This flow has already been analyzed and there is no need to analyze it further
|
||||
return !"Black Hole".equals(label.get(flow));
|
||||
}
|
||||
|
||||
if ("Visiting".equals(label.get(flow))) {
|
||||
//you've detected a cycle because you reached the same entry again during your dfs
|
||||
//let it continue so you can label the whole cycle
|
||||
label.put(flow, "Cycle");
|
||||
} else {
|
||||
//otherwise, mark off the current flow entry as currently being visited
|
||||
label.put(flow, "Visiting");
|
||||
}
|
||||
|
||||
boolean pointsToLiveEntry = false;
|
||||
|
||||
List<Instruction> instructions = flow.treatment().allInstructions();
|
||||
for (Instruction i: instructions) {
|
||||
if (i instanceof Instructions.OutputInstruction) {
|
||||
pointsToLiveEntry |= analyzeInstruction(i, flow);
|
||||
}
|
||||
if ("NA".equals(label.get(flow))) {
|
||||
return pointsToLiveEntry;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pointsToLiveEntry) {
|
||||
//this entry does not point to any "live" entries thus must be a black hole
|
||||
label.put(flow, "Black Hole");
|
||||
} else if ("Visiting".equals(label.get(flow))) {
|
||||
//the flow is not in a cycle or in a black hole
|
||||
label.put(flow, "Cleared");
|
||||
}
|
||||
return pointsToLiveEntry;
|
||||
}
|
||||
|
||||
private boolean analyzeInstruction(Instruction i, FlowEntry flow) {
|
||||
boolean pointsToLiveEntry = false;
|
||||
Instructions.OutputInstruction output = (Instructions.OutputInstruction) i;
|
||||
PortNumber port = output.port();
|
||||
PortNumber outPort = null;
|
||||
|
||||
DeviceId egress = null;
|
||||
boolean hasHost = false;
|
||||
|
||||
ConnectPoint portPt = new ConnectPoint(flow.deviceId(), port);
|
||||
for (Link l: linkService.getEgressLinks(portPt)) {
|
||||
if (l.dst().elementId() instanceof DeviceId) {
|
||||
egress = l.dst().deviceId();
|
||||
outPort = l.dst().port();
|
||||
} else if (l.dst().elementId() instanceof HostId) {
|
||||
//the port leads to a host: therefore it is not a dead link
|
||||
pointsToLiveEntry = true;
|
||||
hasHost = true;
|
||||
}
|
||||
}
|
||||
if (!topologyService.isInfrastructure(topologyService.currentTopology(), portPt) && egress == null) {
|
||||
pointsToLiveEntry = true;
|
||||
hasHost = true;
|
||||
}
|
||||
if (hasHost) {
|
||||
return pointsToLiveEntry;
|
||||
}
|
||||
if (egress == null) {
|
||||
//the port that the flow instructions tells you to send the packet
|
||||
//to doesn't exist or is a controller port
|
||||
label.put(flow, "NA");
|
||||
return pointsToLiveEntry;
|
||||
}
|
||||
|
||||
Iterable<FlowEntry> dstFlowTable = flowRuleService.getFlowEntries(egress);
|
||||
|
||||
Set<Criterion> flowCriteria = flow.selector().criteria();
|
||||
|
||||
//filter the criteria in order to remove port dependency
|
||||
Set<Criterion> filteredCriteria = new HashSet<>();
|
||||
for (Criterion criterion : flowCriteria) {
|
||||
if (!(criterion instanceof PortCriterion)) {
|
||||
filteredCriteria.add(criterion);
|
||||
}
|
||||
}
|
||||
|
||||
//ensure that the in port is equal to the port that it is coming in from
|
||||
filteredCriteria.add(Criteria.matchInPort(outPort));
|
||||
|
||||
for (FlowEntry entry: dstFlowTable) {
|
||||
if (ignoredFlows.contains(entry)) {
|
||||
continue;
|
||||
}
|
||||
if (filteredCriteria.containsAll(entry.selector().criteria())) {
|
||||
dfs(entry);
|
||||
|
||||
if (!"Black Hole".equals(label.get(entry))) {
|
||||
//this entry is "live" i.e not a black hole
|
||||
pointsToLiveEntry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pointsToLiveEntry;
|
||||
}
|
||||
public String flowEntryRepresentation(FlowEntry flow) {
|
||||
return "Device: " + flow.deviceId() + ", " + flow.selector().criteria() + ", " + flow.treatment().immediate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
|
||||
<command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
|
||||
<command>
|
||||
<action class="org.onosproject.flowanalyzer.FlowAnalysisCommand"/>
|
||||
</command>
|
||||
|
||||
</command-bundle>
|
||||
</blueprint>
|
||||
@ -0,0 +1,28 @@
|
||||
package org.onosproject.flowanalyzer;
|
||||
|
||||
import org.onlab.graph.MutableAdjacencyListsGraph;
|
||||
import org.onosproject.net.topology.TopologyEdge;
|
||||
import org.onosproject.net.topology.TopologyGraph;
|
||||
import org.onosproject.net.topology.TopologyVertex;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default implementation of an immutable topology graph based on a generic
|
||||
* implementation of adjacency lists graph.
|
||||
*/
|
||||
public class DefaultMutableTopologyGraph
|
||||
extends MutableAdjacencyListsGraph<TopologyVertex, TopologyEdge>
|
||||
implements TopologyGraph {
|
||||
|
||||
/**
|
||||
* Creates a topology graph comprising of the specified vertexes and edges.
|
||||
*
|
||||
* @param vertexes set of graph vertexes
|
||||
* @param edges set of graph edges
|
||||
*/
|
||||
public DefaultMutableTopologyGraph(Set<TopologyVertex> vertexes, Set<TopologyEdge> edges) {
|
||||
super(vertexes, edges);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.flowanalyzer;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.onosproject.core.DefaultApplicationId;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.flow.DefaultFlowRule;
|
||||
import org.onosproject.net.flow.DefaultTrafficSelector;
|
||||
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
||||
import org.onosproject.net.flow.FlowRule;
|
||||
import org.onosproject.net.flow.FlowRuleExtPayLoad;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.net.flow.TrafficSelector;
|
||||
import org.onosproject.net.flow.TrafficTreatment;
|
||||
import org.onosproject.net.flow.instructions.Instructions;
|
||||
import org.onosproject.net.topology.TopologyService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
* Created by nikcheerla on 7/20/15.
|
||||
*/
|
||||
public class FlowAnalyzerTest {
|
||||
|
||||
FlowRuleService flowRuleService = new MockFlowRuleService();
|
||||
TopologyService topologyService;
|
||||
MockLinkService linkService = new MockLinkService();
|
||||
|
||||
@Test
|
||||
@Ignore("This needs to be reworked to be more robust")
|
||||
public void basic() {
|
||||
flowRuleService = new MockFlowRuleService();
|
||||
flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 90));
|
||||
flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 100));
|
||||
flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 150));
|
||||
flowRuleService.applyFlowRules(genFlow("ATL-002", 80, 70));
|
||||
flowRuleService.applyFlowRules(genFlow("ATL-003", 120, 130));
|
||||
flowRuleService.applyFlowRules(genFlow("ATL-004", 50));
|
||||
flowRuleService.applyFlowRules(genFlow("ATL-005", 140, 10));
|
||||
|
||||
linkService.addLink("H00:00:00:00:00:0660", 160, "ATL-005", 140);
|
||||
linkService.addLink("ATL-005", 10, "ATL-004", 40);
|
||||
linkService.addLink("ATL-004", 50, "ATL-002", 80);
|
||||
linkService.addLink("ATL-002", 70, "ATL-001", 110);
|
||||
linkService.addLink("ATL-001", 150, "H00:00:00:00:00:0770", 170);
|
||||
linkService.addLink("ATL-001", 90, "ATL-004", 30);
|
||||
linkService.addLink("ATL-001", 100, "ATL-003", 120);
|
||||
linkService.addLink("ATL-003", 130, "ATL-005", 20);
|
||||
|
||||
topologyService = new MockTopologyService(linkService.createdGraph);
|
||||
|
||||
FlowAnalyzer flowAnalyzer = new FlowAnalyzer();
|
||||
flowAnalyzer.flowRuleService = flowRuleService;
|
||||
flowAnalyzer.linkService = linkService;
|
||||
flowAnalyzer.topologyService = topologyService;
|
||||
|
||||
String labels = flowAnalyzer.analysisOutput();
|
||||
String correctOutput = "Flow Rule: Device: atl-005, [IN_PORT{port=140}], [OUTPUT{port=10}]\n" +
|
||||
"Analysis: Cleared!\n" +
|
||||
"\n" +
|
||||
"Flow Rule: Device: atl-003, [IN_PORT{port=120}], [OUTPUT{port=130}]\n" +
|
||||
"Analysis: Black Hole!\n" +
|
||||
"\n" +
|
||||
"Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=90}]\n" +
|
||||
"Analysis: Cycle Critical Point!\n" +
|
||||
"\n" +
|
||||
"Flow Rule: Device: atl-004, [], [OUTPUT{port=50}]\n" +
|
||||
"Analysis: Cycle!\n" +
|
||||
"\n" +
|
||||
"Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=150}]\n" +
|
||||
"Analysis: Cleared!\n" +
|
||||
"\n" +
|
||||
"Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=100}]\n" +
|
||||
"Analysis: Black Hole!\n" +
|
||||
"\n" +
|
||||
"Flow Rule: Device: atl-002, [IN_PORT{port=80}], [OUTPUT{port=70}]\n" +
|
||||
"Analysis: Cycle!\n";
|
||||
assertEquals("Wrong labels", new TreeSet(Arrays.asList(labels.replaceAll("\\s+", "").split("!"))),
|
||||
new TreeSet(Arrays.asList(correctOutput.replaceAll("\\s+", "").split("!"))));
|
||||
}
|
||||
|
||||
public FlowRule genFlow(String d, long inPort, long outPort) {
|
||||
DeviceId device = DeviceId.deviceId(d);
|
||||
TrafficSelector ts = DefaultTrafficSelector.builder().matchInPort(PortNumber.portNumber(inPort)).build();
|
||||
TrafficTreatment tt = DefaultTrafficTreatment.builder()
|
||||
.add(Instructions.createOutput(PortNumber.portNumber(outPort))).build();
|
||||
return new DefaultFlowRule(device, ts, tt, 1, new DefaultApplicationId(5000, "of"),
|
||||
50000, true, FlowRuleExtPayLoad.flowRuleExtPayLoad(new byte[5]));
|
||||
}
|
||||
public FlowRule genFlow(String d, long outPort) {
|
||||
DeviceId device = DeviceId.deviceId(d);
|
||||
TrafficSelector ts = DefaultTrafficSelector.builder().build();
|
||||
TrafficTreatment tt = DefaultTrafficTreatment.builder()
|
||||
.add(Instructions.createOutput(PortNumber.portNumber(outPort))).build();
|
||||
return new DefaultFlowRule(device, ts, tt, 1, new DefaultApplicationId(5000, "of"),
|
||||
50000, true, FlowRuleExtPayLoad.flowRuleExtPayLoad(new byte[5]));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
package org.onosproject.flowanalyzer;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.flow.DefaultFlowEntry;
|
||||
import org.onosproject.net.flow.FlowEntry;
|
||||
import org.onosproject.net.flow.FlowRule;
|
||||
import org.onosproject.net.flow.FlowRuleOperations;
|
||||
import org.onosproject.net.flow.FlowRuleServiceAdapter;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Created by nikcheerla on 7/20/15.
|
||||
*/
|
||||
|
||||
public class MockFlowRuleService extends FlowRuleServiceAdapter {
|
||||
|
||||
final Set<FlowRule> flows = Sets.newHashSet();
|
||||
boolean success;
|
||||
|
||||
int errorFlow = -1;
|
||||
public void setErrorFlow(int errorFlow) {
|
||||
this.errorFlow = errorFlow;
|
||||
}
|
||||
|
||||
public void setFuture(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(FlowRuleOperations ops) {
|
||||
AtomicBoolean thisSuccess = new AtomicBoolean(success);
|
||||
ops.stages().forEach(stage -> stage.forEach(flow -> {
|
||||
if (errorFlow == flow.rule().id().value()) {
|
||||
thisSuccess.set(false);
|
||||
} else {
|
||||
switch (flow.type()) {
|
||||
case ADD:
|
||||
case MODIFY: //TODO is this the right behavior for modify?
|
||||
flows.add(flow.rule());
|
||||
break;
|
||||
case REMOVE:
|
||||
flows.remove(flow.rule());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}));
|
||||
if (thisSuccess.get()) {
|
||||
ops.callback().onSuccess(ops);
|
||||
} else {
|
||||
ops.callback().onError(ops);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFlowRuleCount() {
|
||||
return flows.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
|
||||
return flows.stream()
|
||||
.filter(flow -> flow.deviceId().equals(deviceId))
|
||||
.map(DefaultFlowEntry::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFlowRules(FlowRule... flowRules) {
|
||||
for (FlowRule flow : flowRules) {
|
||||
flows.add(flow);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFlowRules(FlowRule... flowRules) {
|
||||
for (FlowRule flow : flowRules) {
|
||||
flows.remove(flow);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
|
||||
return flows.stream()
|
||||
.filter(flow -> flow.appId() == id.id())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<FlowRule> getFlowRulesByGroupId(ApplicationId appId, short groupId) {
|
||||
return flows.stream()
|
||||
.filter(flow -> flow.appId() == appId.id() && flow.groupId().id() == groupId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,183 @@
|
||||
package org.onosproject.flowanalyzer;
|
||||
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.link.LinkServiceAdapter;
|
||||
import org.onosproject.net.topology.TopologyEdge;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.ElementId;
|
||||
import org.onosproject.net.HostId;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.Annotations;
|
||||
import org.onosproject.net.provider.ProviderId;
|
||||
import org.onosproject.net.topology.TopologyVertex;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.onosproject.net.Link.State.ACTIVE;
|
||||
|
||||
|
||||
/**
|
||||
* Created by nikcheerla on 7/21/15.
|
||||
*/
|
||||
public class MockLinkService extends LinkServiceAdapter {
|
||||
DefaultMutableTopologyGraph createdGraph = new DefaultMutableTopologyGraph(new HashSet<>(), new HashSet<>());
|
||||
List<Link> links = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public int getLinkCount() {
|
||||
return links.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Link> getDeviceLinks(DeviceId deviceId) {
|
||||
Set<Link> egress = getDeviceEgressLinks(deviceId);
|
||||
egress.addAll(getDeviceIngressLinks(deviceId));
|
||||
return egress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
|
||||
Set<Link> setL = new HashSet<>();
|
||||
for (Link l: links) {
|
||||
if (l.src().elementId() instanceof DeviceId && l.src().deviceId().equals(deviceId)) {
|
||||
setL.add(l);
|
||||
}
|
||||
}
|
||||
return setL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
|
||||
Set<Link> setL = new HashSet<>();
|
||||
for (Link l: links) {
|
||||
if (l.dst().elementId() instanceof DeviceId && l.dst().deviceId().equals(deviceId)) {
|
||||
setL.add(l);
|
||||
}
|
||||
}
|
||||
return setL;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<Link> getEgressLinks(ConnectPoint pt) {
|
||||
Set<Link> setL = new HashSet<>();
|
||||
for (Link l: links) {
|
||||
if (l.src().equals(pt)) {
|
||||
setL.add(l);
|
||||
}
|
||||
}
|
||||
return setL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Link> getIngressLinks(ConnectPoint pt) {
|
||||
Set<Link> setL = new HashSet<>();
|
||||
for (Link l: links) {
|
||||
if (l.dst().equals(pt)) {
|
||||
setL.add(l);
|
||||
}
|
||||
}
|
||||
return setL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Link> getLinks(ConnectPoint pt) {
|
||||
Set<Link> setL = new HashSet<>();
|
||||
for (Link l: links) {
|
||||
if (l.src().equals(pt) || l.dst().equals(pt)) {
|
||||
setL.add(l);
|
||||
}
|
||||
}
|
||||
return setL;
|
||||
}
|
||||
|
||||
public void addLink(String device, long port, String device2, long port2) {
|
||||
ElementId d1;
|
||||
if (device.charAt(0) == 'H') {
|
||||
device = device.substring(1, device.length());
|
||||
d1 = HostId.hostId(device);
|
||||
} else {
|
||||
d1 = DeviceId.deviceId(device);
|
||||
}
|
||||
|
||||
ElementId d2;
|
||||
if (device2.charAt(0) == 'H') {
|
||||
d2 = HostId.hostId(device2.substring(1, device2.length()));
|
||||
} else {
|
||||
d2 = DeviceId.deviceId(device2);
|
||||
}
|
||||
|
||||
ConnectPoint src = new ConnectPoint(d1, PortNumber.portNumber(port));
|
||||
ConnectPoint dst = new ConnectPoint(d2, PortNumber.portNumber(port2));
|
||||
Link curLink;
|
||||
curLink = new Link() {
|
||||
@Override
|
||||
public ConnectPoint src() {
|
||||
return src;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectPoint dst() {
|
||||
return dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDurable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotations annotations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderId providerId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State state() {
|
||||
return ACTIVE;
|
||||
}
|
||||
};
|
||||
links.add(curLink);
|
||||
if (d1 instanceof DeviceId && d2 instanceof DeviceId) {
|
||||
TopologyVertex v1 = () -> (DeviceId) d1, v2 = () -> (DeviceId) d2;
|
||||
createdGraph.addVertex(v1);
|
||||
createdGraph.addVertex(v2);
|
||||
createdGraph.addEdge(new TopologyEdge() {
|
||||
@Override
|
||||
public Link link() {
|
||||
return curLink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopologyVertex src() {
|
||||
return v1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopologyVertex dst() {
|
||||
return v2;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package org.onosproject.flowanalyzer;
|
||||
import org.onosproject.net.topology.Topology;
|
||||
import org.onosproject.net.topology.TopologyGraph;
|
||||
import org.onosproject.net.topology.TopologyServiceAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* Created by nikcheerla on 7/20/15.
|
||||
*/
|
||||
public class MockTopologyService extends TopologyServiceAdapter {
|
||||
TopologyGraph cur;
|
||||
|
||||
public MockTopologyService(TopologyGraph g) {
|
||||
cur = g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopologyGraph getGraph(Topology topology) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user