Nikhil Cheerla
Committed by Thomas Vachuska

[Emu] FlowAnalyzer app code and tests

Change-Id: I8b6f83f7d2e76a4e8cf770d9b0018be283e91bf3
...@@ -40,6 +40,38 @@ ...@@ -40,6 +40,38 @@
40 <groupId>org.osgi</groupId> 40 <groupId>org.osgi</groupId>
41 <artifactId>org.osgi.compendium</artifactId> 41 <artifactId>org.osgi.compendium</artifactId>
42 </dependency> 42 </dependency>
43 + <dependency>
44 + <groupId>org.onosproject</groupId>
45 + <artifactId>onlab-junit</artifactId>
46 + <scope>test</scope>
47 + </dependency>
48 +
49 + <dependency>
50 + <groupId>org.onosproject</groupId>
51 + <artifactId>onos-api</artifactId>
52 + <classifier>tests</classifier>
53 + <scope>test</scope>
54 + </dependency>
55 + <dependency>
56 + <groupId>org.apache.felix</groupId>
57 + <artifactId>org.apache.felix.scr.annotations</artifactId>
58 + </dependency>
59 +
60 + <dependency>
61 + <groupId>org.onosproject</groupId>
62 + <artifactId>onos-cli</artifactId>
63 + <version>${project.version}</version>
64 + </dependency>
65 + <dependency>
66 + <groupId>org.osgi</groupId>
67 + <artifactId>org.osgi.core</artifactId>
68 + </dependency>
69 +
70 + <dependency>
71 + <groupId>org.apache.karaf.shell</groupId>
72 + <artifactId>org.apache.karaf.shell.console</artifactId>
73 + </dependency>
74 +
43 </dependencies> 75 </dependencies>
44 76
45 </project> 77 </project>
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.flowanalyzer;
17 +
18 +import org.apache.karaf.shell.commands.Command;
19 +import org.onosproject.cli.AbstractShellCommand;
20 +
21 +/**
22 + * Analyzes flows for cycles and black holes.
23 + */
24 +@Command(scope = "onos", name = "flow-analysis",
25 + description = "Analyzes flows for cycles and black holes")
26 +public class FlowAnalysisCommand extends AbstractShellCommand {
27 +
28 + @Override
29 + protected void execute() {
30 + FlowAnalyzer service = get(FlowAnalyzer.class);
31 + print(service.analyze());
32 + }
33 +}
...@@ -21,12 +21,31 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -21,12 +21,31 @@ import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Reference; 21 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality; 22 import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.apache.felix.scr.annotations.Service; 23 import org.apache.felix.scr.annotations.Service;
24 +import org.onosproject.net.ConnectPoint;
25 +import org.onosproject.net.PortNumber;
26 +import org.onosproject.net.flow.FlowEntry;
24 import org.onosproject.net.flow.FlowRuleService; 27 import org.onosproject.net.flow.FlowRuleService;
25 -import org.onosproject.net.host.HostService; 28 +import org.onosproject.net.DeviceId;
29 +import org.onosproject.net.HostId;
30 +import org.onosproject.net.flow.criteria.Criteria;
31 +import org.onosproject.net.flow.criteria.Criterion;
32 +import org.onosproject.net.flow.criteria.PortCriterion;
33 +import org.onosproject.net.flow.instructions.Instruction;
34 +import org.onosproject.net.flow.instructions.Instructions;
35 +import org.onosproject.net.topology.TopologyService;
36 +import org.onosproject.net.topology.TopologyGraph;
26 import org.onosproject.net.link.LinkService; 37 import org.onosproject.net.link.LinkService;
38 +import org.onosproject.net.Link;
39 +import org.onosproject.net.topology.TopologyVertex;
27 import org.osgi.service.component.ComponentContext; 40 import org.osgi.service.component.ComponentContext;
28 import org.slf4j.Logger; 41 import org.slf4j.Logger;
29 42
43 +import java.util.HashSet;
44 +import java.util.List;
45 +import java.util.HashMap;
46 +import java.util.Map;
47 +import java.util.Set;
48 +
30 import static org.slf4j.LoggerFactory.getLogger; 49 import static org.slf4j.LoggerFactory.getLogger;
31 50
32 /** 51 /**
...@@ -42,11 +61,10 @@ public class FlowAnalyzer { ...@@ -42,11 +61,10 @@ public class FlowAnalyzer {
42 protected FlowRuleService flowRuleService; 61 protected FlowRuleService flowRuleService;
43 62
44 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
45 - protected LinkService linkService; 64 + protected TopologyService topologyService;
46 65
47 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
48 - protected HostService hostService; 67 + protected LinkService linkService;
49 -
50 68
51 @Activate 69 @Activate
52 public void activate(ComponentContext context) { 70 public void activate(ComponentContext context) {
...@@ -58,12 +76,193 @@ public class FlowAnalyzer { ...@@ -58,12 +76,193 @@ public class FlowAnalyzer {
58 log.info("Stopped"); 76 log.info("Stopped");
59 } 77 }
60 78
79 + TopologyGraph graph;
80 + Map<FlowEntry, String> label = new HashMap<>();
81 + Set<FlowEntry> ignoredFlows = new HashSet<>();
61 82
62 /** 83 /**
63 - * ... 84 + * Analyzes and prints out a report on the status of every flow entry inside
85 + * the network. The possible states are: Cleared (implying that the entry leads to
86 + * a host), Cycle (implying that it is part of cycle), and Black Hole (implying
87 + * that the entry does not lead to a single host).
64 */ 88 */
65 - public void analyze() { 89 + public String analyze() {
66 - // TODO: implement this 90 + graph = topologyService.getGraph(topologyService.currentTopology());
91 + for (TopologyVertex v: graph.getVertexes()) {
92 + DeviceId srcDevice = v.deviceId();
93 + Iterable<FlowEntry> flowTable = flowRuleService.getFlowEntries(srcDevice);
94 + for (FlowEntry flow: flowTable) {
95 + dfs(flow);
96 + }
97 + }
98 +
99 + //analyze the cycles to look for "critical flows" that can be removed
100 + //to break the cycle
101 + Set<FlowEntry> critpts = new HashSet<>();
102 + for (FlowEntry flow: label.keySet()) {
103 + if ("Cycle".equals(label.get(flow))) {
104 + Map<FlowEntry, String> labelSaved = label;
105 + label = new HashMap<FlowEntry, String>();
106 + ignoredFlows.add(flow);
107 + for (TopologyVertex v: graph.getVertexes()) {
108 + DeviceId srcDevice = v.deviceId();
109 + Iterable<FlowEntry> flowTable = flowRuleService.getFlowEntries(srcDevice);
110 + for (FlowEntry flow1: flowTable) {
111 + dfs(flow1);
112 + }
113 + }
114 +
115 + boolean replacable = true;
116 + for (FlowEntry flow2: label.keySet()) {
117 + if ("Cleared".equals(labelSaved.get(flow2)) && !("Cleared".equals(label.get(flow2)))) {
118 + replacable = false;
119 + }
120 + }
121 + if (replacable) {
122 + critpts.add(flow);
123 + }
124 + label = labelSaved;
125 + }
126 + }
127 +
128 + for (FlowEntry flow: critpts) {
129 + label.put(flow, "Cycle Critical Point");
130 + }
131 +
132 + String s = "\n";
133 + for (FlowEntry flow: label.keySet()) {
134 + s += ("Flow Rule: " + flowEntryRepresentation(flow) + "\n");
135 + s += ("Analysis: " + label.get(flow) + "!\n\n");
136 + }
137 + s += ("Analyzed " + label.keySet().size() + " flows.");
138 + //log.info(s);
139 + return s;
140 + }
141 +
142 + public Map<FlowEntry, String> calcLabels() {
143 + analyze();
144 + return label;
145 + }
146 + public String analysisOutput() {
147 + analyze();
148 + String s = "\n";
149 + for (FlowEntry flow: label.keySet()) {
150 + s += ("Flow Rule: " + flowEntryRepresentation(flow) + "\n");
151 + s += ("Analysis: " + label.get(flow) + "!\n\n");
152 + }
153 + return s;
154 + }
155 +
156 + private boolean dfs(FlowEntry flow) {
157 + if (ignoredFlows.contains(flow)) {
158 + return false;
159 + }
160 + if ("Cycle".equals(label.get(flow)) ||
161 + "Black Hole".equals(label.get(flow)) ||
162 + "Cleared".equals(label.get(flow)) ||
163 + "NA".equals(label.get(flow)) ||
164 + "Cycle Critical Point".equals(label.get(flow))) {
165 +
166 + // This flow has already been analyzed and there is no need to analyze it further
167 + return !"Black Hole".equals(label.get(flow));
168 + }
169 +
170 + if ("Visiting".equals(label.get(flow))) {
171 + //you've detected a cycle because you reached the same entry again during your dfs
172 + //let it continue so you can label the whole cycle
173 + label.put(flow, "Cycle");
174 + } else {
175 + //otherwise, mark off the current flow entry as currently being visited
176 + label.put(flow, "Visiting");
67 } 177 }
68 178
179 + boolean pointsToLiveEntry = false;
180 +
181 + List<Instruction> instructions = flow.treatment().allInstructions();
182 + for (Instruction i: instructions) {
183 + if (i instanceof Instructions.OutputInstruction) {
184 + pointsToLiveEntry |= analyzeInstruction(i, flow);
185 + }
186 + if ("NA".equals(label.get(flow))) {
187 + return pointsToLiveEntry;
188 + }
189 + }
190 +
191 + if (!pointsToLiveEntry) {
192 + //this entry does not point to any "live" entries thus must be a black hole
193 + label.put(flow, "Black Hole");
194 + } else if ("Visiting".equals(label.get(flow))) {
195 + //the flow is not in a cycle or in a black hole
196 + label.put(flow, "Cleared");
197 + }
198 + return pointsToLiveEntry;
199 + }
200 +
201 + private boolean analyzeInstruction(Instruction i, FlowEntry flow) {
202 + boolean pointsToLiveEntry = false;
203 + Instructions.OutputInstruction output = (Instructions.OutputInstruction) i;
204 + PortNumber port = output.port();
205 + PortNumber outPort = null;
206 +
207 + DeviceId egress = null;
208 + boolean hasHost = false;
209 +
210 + ConnectPoint portPt = new ConnectPoint(flow.deviceId(), port);
211 + for (Link l: linkService.getEgressLinks(portPt)) {
212 + if (l.dst().elementId() instanceof DeviceId) {
213 + egress = l.dst().deviceId();
214 + outPort = l.dst().port();
215 + } else if (l.dst().elementId() instanceof HostId) {
216 + //the port leads to a host: therefore it is not a dead link
217 + pointsToLiveEntry = true;
218 + hasHost = true;
219 + }
220 + }
221 + if (!topologyService.isInfrastructure(topologyService.currentTopology(), portPt) && egress == null) {
222 + pointsToLiveEntry = true;
223 + hasHost = true;
224 + }
225 + if (hasHost) {
226 + return pointsToLiveEntry;
227 + }
228 + if (egress == null) {
229 + //the port that the flow instructions tells you to send the packet
230 + //to doesn't exist or is a controller port
231 + label.put(flow, "NA");
232 + return pointsToLiveEntry;
233 + }
234 +
235 + Iterable<FlowEntry> dstFlowTable = flowRuleService.getFlowEntries(egress);
236 +
237 + Set<Criterion> flowCriteria = flow.selector().criteria();
238 +
239 + //filter the criteria in order to remove port dependency
240 + Set<Criterion> filteredCriteria = new HashSet<>();
241 + for (Criterion criterion : flowCriteria) {
242 + if (!(criterion instanceof PortCriterion)) {
243 + filteredCriteria.add(criterion);
244 + }
245 + }
246 +
247 + //ensure that the in port is equal to the port that it is coming in from
248 + filteredCriteria.add(Criteria.matchInPort(outPort));
249 +
250 + for (FlowEntry entry: dstFlowTable) {
251 + if (ignoredFlows.contains(entry)) {
252 + continue;
253 + }
254 + if (filteredCriteria.containsAll(entry.selector().criteria())) {
255 + dfs(entry);
256 +
257 + if (!"Black Hole".equals(label.get(entry))) {
258 + //this entry is "live" i.e not a black hole
259 + pointsToLiveEntry = true;
260 + }
261 + }
262 + }
263 + return pointsToLiveEntry;
264 + }
265 + public String flowEntryRepresentation(FlowEntry flow) {
266 + return "Device: " + flow.deviceId() + ", " + flow.selector().criteria() + ", " + flow.treatment().immediate();
267 + }
69 } 268 }
......
1 +<!--
2 + ~ Copyright 2015 Open Networking Laboratory
3 + ~
4 + ~ Licensed under the Apache License, Version 2.0 (the "License");
5 + ~ you may not use this file except in compliance with the License.
6 + ~ You may obtain a copy of the License at
7 + ~
8 + ~ http://www.apache.org/licenses/LICENSE-2.0
9 + ~
10 + ~ Unless required by applicable law or agreed to in writing, software
11 + ~ distributed under the License is distributed on an "AS IS" BASIS,
12 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + ~ See the License for the specific language governing permissions and
14 + ~ limitations under the License.
15 + -->
16 +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
17 + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
18 + <command>
19 + <action class="org.onosproject.flowanalyzer.FlowAnalysisCommand"/>
20 + </command>
21 +
22 + </command-bundle>
23 +</blueprint>
1 +package org.onosproject.flowanalyzer;
2 +
3 +import org.onlab.graph.MutableAdjacencyListsGraph;
4 +import org.onosproject.net.topology.TopologyEdge;
5 +import org.onosproject.net.topology.TopologyGraph;
6 +import org.onosproject.net.topology.TopologyVertex;
7 +
8 +import java.util.Set;
9 +
10 +/**
11 + * Default implementation of an immutable topology graph based on a generic
12 + * implementation of adjacency lists graph.
13 + */
14 +public class DefaultMutableTopologyGraph
15 + extends MutableAdjacencyListsGraph<TopologyVertex, TopologyEdge>
16 + implements TopologyGraph {
17 +
18 + /**
19 + * Creates a topology graph comprising of the specified vertexes and edges.
20 + *
21 + * @param vertexes set of graph vertexes
22 + * @param edges set of graph edges
23 + */
24 + public DefaultMutableTopologyGraph(Set<TopologyVertex> vertexes, Set<TopologyEdge> edges) {
25 + super(vertexes, edges);
26 + }
27 +
28 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.flowanalyzer;
17 +
18 +import org.junit.Ignore;
19 +import org.junit.Test;
20 +
21 +import org.onosproject.core.DefaultApplicationId;
22 +import org.onosproject.net.DeviceId;
23 +import org.onosproject.net.PortNumber;
24 +import org.onosproject.net.flow.DefaultFlowRule;
25 +import org.onosproject.net.flow.DefaultTrafficSelector;
26 +import org.onosproject.net.flow.DefaultTrafficTreatment;
27 +import org.onosproject.net.flow.FlowRule;
28 +import org.onosproject.net.flow.FlowRuleExtPayLoad;
29 +import org.onosproject.net.flow.FlowRuleService;
30 +import org.onosproject.net.flow.TrafficSelector;
31 +import org.onosproject.net.flow.TrafficTreatment;
32 +import org.onosproject.net.flow.instructions.Instructions;
33 +import org.onosproject.net.topology.TopologyService;
34 +
35 +import java.util.Arrays;
36 +import java.util.TreeSet;
37 +
38 +import static org.junit.Assert.assertEquals;
39 +
40 +
41 +/**
42 + * Created by nikcheerla on 7/20/15.
43 + */
44 +public class FlowAnalyzerTest {
45 +
46 + FlowRuleService flowRuleService = new MockFlowRuleService();
47 + TopologyService topologyService;
48 + MockLinkService linkService = new MockLinkService();
49 +
50 + @Test
51 + @Ignore("This needs to be reworked to be more robust")
52 + public void basic() {
53 + flowRuleService = new MockFlowRuleService();
54 + flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 90));
55 + flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 100));
56 + flowRuleService.applyFlowRules(genFlow("ATL-001", 110, 150));
57 + flowRuleService.applyFlowRules(genFlow("ATL-002", 80, 70));
58 + flowRuleService.applyFlowRules(genFlow("ATL-003", 120, 130));
59 + flowRuleService.applyFlowRules(genFlow("ATL-004", 50));
60 + flowRuleService.applyFlowRules(genFlow("ATL-005", 140, 10));
61 +
62 + linkService.addLink("H00:00:00:00:00:0660", 160, "ATL-005", 140);
63 + linkService.addLink("ATL-005", 10, "ATL-004", 40);
64 + linkService.addLink("ATL-004", 50, "ATL-002", 80);
65 + linkService.addLink("ATL-002", 70, "ATL-001", 110);
66 + linkService.addLink("ATL-001", 150, "H00:00:00:00:00:0770", 170);
67 + linkService.addLink("ATL-001", 90, "ATL-004", 30);
68 + linkService.addLink("ATL-001", 100, "ATL-003", 120);
69 + linkService.addLink("ATL-003", 130, "ATL-005", 20);
70 +
71 + topologyService = new MockTopologyService(linkService.createdGraph);
72 +
73 + FlowAnalyzer flowAnalyzer = new FlowAnalyzer();
74 + flowAnalyzer.flowRuleService = flowRuleService;
75 + flowAnalyzer.linkService = linkService;
76 + flowAnalyzer.topologyService = topologyService;
77 +
78 + String labels = flowAnalyzer.analysisOutput();
79 + String correctOutput = "Flow Rule: Device: atl-005, [IN_PORT{port=140}], [OUTPUT{port=10}]\n" +
80 + "Analysis: Cleared!\n" +
81 + "\n" +
82 + "Flow Rule: Device: atl-003, [IN_PORT{port=120}], [OUTPUT{port=130}]\n" +
83 + "Analysis: Black Hole!\n" +
84 + "\n" +
85 + "Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=90}]\n" +
86 + "Analysis: Cycle Critical Point!\n" +
87 + "\n" +
88 + "Flow Rule: Device: atl-004, [], [OUTPUT{port=50}]\n" +
89 + "Analysis: Cycle!\n" +
90 + "\n" +
91 + "Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=150}]\n" +
92 + "Analysis: Cleared!\n" +
93 + "\n" +
94 + "Flow Rule: Device: atl-001, [IN_PORT{port=110}], [OUTPUT{port=100}]\n" +
95 + "Analysis: Black Hole!\n" +
96 + "\n" +
97 + "Flow Rule: Device: atl-002, [IN_PORT{port=80}], [OUTPUT{port=70}]\n" +
98 + "Analysis: Cycle!\n";
99 + assertEquals("Wrong labels", new TreeSet(Arrays.asList(labels.replaceAll("\\s+", "").split("!"))),
100 + new TreeSet(Arrays.asList(correctOutput.replaceAll("\\s+", "").split("!"))));
101 + }
102 +
103 + public FlowRule genFlow(String d, long inPort, long outPort) {
104 + DeviceId device = DeviceId.deviceId(d);
105 + TrafficSelector ts = DefaultTrafficSelector.builder().matchInPort(PortNumber.portNumber(inPort)).build();
106 + TrafficTreatment tt = DefaultTrafficTreatment.builder()
107 + .add(Instructions.createOutput(PortNumber.portNumber(outPort))).build();
108 + return new DefaultFlowRule(device, ts, tt, 1, new DefaultApplicationId(5000, "of"),
109 + 50000, true, FlowRuleExtPayLoad.flowRuleExtPayLoad(new byte[5]));
110 + }
111 + public FlowRule genFlow(String d, long outPort) {
112 + DeviceId device = DeviceId.deviceId(d);
113 + TrafficSelector ts = DefaultTrafficSelector.builder().build();
114 + TrafficTreatment tt = DefaultTrafficTreatment.builder()
115 + .add(Instructions.createOutput(PortNumber.portNumber(outPort))).build();
116 + return new DefaultFlowRule(device, ts, tt, 1, new DefaultApplicationId(5000, "of"),
117 + 50000, true, FlowRuleExtPayLoad.flowRuleExtPayLoad(new byte[5]));
118 + }
119 +
120 +}
1 +package org.onosproject.flowanalyzer;
2 +
3 +import com.google.common.collect.Sets;
4 +import org.onosproject.core.ApplicationId;
5 +import org.onosproject.net.DeviceId;
6 +import org.onosproject.net.flow.DefaultFlowEntry;
7 +import org.onosproject.net.flow.FlowEntry;
8 +import org.onosproject.net.flow.FlowRule;
9 +import org.onosproject.net.flow.FlowRuleOperations;
10 +import org.onosproject.net.flow.FlowRuleServiceAdapter;
11 +
12 +import java.util.Set;
13 +import java.util.concurrent.atomic.AtomicBoolean;
14 +import java.util.stream.Collectors;
15 +
16 +/**
17 + * Created by nikcheerla on 7/20/15.
18 + */
19 +
20 +public class MockFlowRuleService extends FlowRuleServiceAdapter {
21 +
22 + final Set<FlowRule> flows = Sets.newHashSet();
23 + boolean success;
24 +
25 + int errorFlow = -1;
26 + public void setErrorFlow(int errorFlow) {
27 + this.errorFlow = errorFlow;
28 + }
29 +
30 + public void setFuture(boolean success) {
31 + this.success = success;
32 + }
33 +
34 + @Override
35 + public void apply(FlowRuleOperations ops) {
36 + AtomicBoolean thisSuccess = new AtomicBoolean(success);
37 + ops.stages().forEach(stage -> stage.forEach(flow -> {
38 + if (errorFlow == flow.rule().id().value()) {
39 + thisSuccess.set(false);
40 + } else {
41 + switch (flow.type()) {
42 + case ADD:
43 + case MODIFY: //TODO is this the right behavior for modify?
44 + flows.add(flow.rule());
45 + break;
46 + case REMOVE:
47 + flows.remove(flow.rule());
48 + break;
49 + default:
50 + break;
51 + }
52 + }
53 + }));
54 + if (thisSuccess.get()) {
55 + ops.callback().onSuccess(ops);
56 + } else {
57 + ops.callback().onError(ops);
58 + }
59 + }
60 +
61 + @Override
62 + public int getFlowRuleCount() {
63 + return flows.size();
64 + }
65 +
66 + @Override
67 + public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
68 + return flows.stream()
69 + .filter(flow -> flow.deviceId().equals(deviceId))
70 + .map(DefaultFlowEntry::new)
71 + .collect(Collectors.toList());
72 + }
73 +
74 + @Override
75 + public void applyFlowRules(FlowRule... flowRules) {
76 + for (FlowRule flow : flowRules) {
77 + flows.add(flow);
78 + }
79 + }
80 +
81 + @Override
82 + public void removeFlowRules(FlowRule... flowRules) {
83 + for (FlowRule flow : flowRules) {
84 + flows.remove(flow);
85 + }
86 + }
87 +
88 + @Override
89 + public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
90 + return flows.stream()
91 + .filter(flow -> flow.appId() == id.id())
92 + .collect(Collectors.toList());
93 + }
94 +
95 + @Override
96 + public Iterable<FlowRule> getFlowRulesByGroupId(ApplicationId appId, short groupId) {
97 + return flows.stream()
98 + .filter(flow -> flow.appId() == appId.id() && flow.groupId().id() == groupId)
99 + .collect(Collectors.toList());
100 + }
101 +}
102 +
103 +
1 +package org.onosproject.flowanalyzer;
2 +
3 +import org.onosproject.net.PortNumber;
4 +import org.onosproject.net.link.LinkServiceAdapter;
5 +import org.onosproject.net.topology.TopologyEdge;
6 +import org.onosproject.net.ConnectPoint;
7 +import org.onosproject.net.DeviceId;
8 +import org.onosproject.net.ElementId;
9 +import org.onosproject.net.HostId;
10 +import org.onosproject.net.Link;
11 +import org.onosproject.net.Annotations;
12 +import org.onosproject.net.provider.ProviderId;
13 +import org.onosproject.net.topology.TopologyVertex;
14 +
15 +import java.util.Set;
16 +import java.util.ArrayList;
17 +import java.util.List;
18 +import java.util.HashSet;
19 +
20 +import static org.onosproject.net.Link.State.ACTIVE;
21 +
22 +
23 +/**
24 + * Created by nikcheerla on 7/21/15.
25 + */
26 +public class MockLinkService extends LinkServiceAdapter {
27 + DefaultMutableTopologyGraph createdGraph = new DefaultMutableTopologyGraph(new HashSet<>(), new HashSet<>());
28 + List<Link> links = new ArrayList<>();
29 +
30 + @Override
31 + public int getLinkCount() {
32 + return links.size();
33 + }
34 +
35 + @Override
36 + public Iterable<Link> getLinks() {
37 + return links;
38 + }
39 +
40 + @Override
41 + public Set<Link> getDeviceLinks(DeviceId deviceId) {
42 + Set<Link> egress = getDeviceEgressLinks(deviceId);
43 + egress.addAll(getDeviceIngressLinks(deviceId));
44 + return egress;
45 + }
46 +
47 + @Override
48 + public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
49 + Set<Link> setL = new HashSet<>();
50 + for (Link l: links) {
51 + if (l.src().elementId() instanceof DeviceId && l.src().deviceId().equals(deviceId)) {
52 + setL.add(l);
53 + }
54 + }
55 + return setL;
56 + }
57 +
58 + @Override
59 + public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
60 + Set<Link> setL = new HashSet<>();
61 + for (Link l: links) {
62 + if (l.dst().elementId() instanceof DeviceId && l.dst().deviceId().equals(deviceId)) {
63 + setL.add(l);
64 + }
65 + }
66 + return setL;
67 + }
68 +
69 +
70 + @Override
71 + public Set<Link> getEgressLinks(ConnectPoint pt) {
72 + Set<Link> setL = new HashSet<>();
73 + for (Link l: links) {
74 + if (l.src().equals(pt)) {
75 + setL.add(l);
76 + }
77 + }
78 + return setL;
79 + }
80 +
81 + @Override
82 + public Set<Link> getIngressLinks(ConnectPoint pt) {
83 + Set<Link> setL = new HashSet<>();
84 + for (Link l: links) {
85 + if (l.dst().equals(pt)) {
86 + setL.add(l);
87 + }
88 + }
89 + return setL;
90 + }
91 +
92 + @Override
93 + public Set<Link> getLinks(ConnectPoint pt) {
94 + Set<Link> setL = new HashSet<>();
95 + for (Link l: links) {
96 + if (l.src().equals(pt) || l.dst().equals(pt)) {
97 + setL.add(l);
98 + }
99 + }
100 + return setL;
101 + }
102 +
103 + public void addLink(String device, long port, String device2, long port2) {
104 + ElementId d1;
105 + if (device.charAt(0) == 'H') {
106 + device = device.substring(1, device.length());
107 + d1 = HostId.hostId(device);
108 + } else {
109 + d1 = DeviceId.deviceId(device);
110 + }
111 +
112 + ElementId d2;
113 + if (device2.charAt(0) == 'H') {
114 + d2 = HostId.hostId(device2.substring(1, device2.length()));
115 + } else {
116 + d2 = DeviceId.deviceId(device2);
117 + }
118 +
119 + ConnectPoint src = new ConnectPoint(d1, PortNumber.portNumber(port));
120 + ConnectPoint dst = new ConnectPoint(d2, PortNumber.portNumber(port2));
121 + Link curLink;
122 + curLink = new Link() {
123 + @Override
124 + public ConnectPoint src() {
125 + return src;
126 + }
127 +
128 + @Override
129 + public ConnectPoint dst() {
130 + return dst;
131 + }
132 +
133 + @Override
134 + public boolean isDurable() {
135 + return true;
136 + }
137 +
138 + @Override
139 + public Annotations annotations() {
140 + return null;
141 + }
142 +
143 + @Override
144 + public Type type() {
145 + return null;
146 + }
147 +
148 + @Override
149 + public ProviderId providerId() {
150 + return null;
151 + }
152 +
153 + @Override
154 + public State state() {
155 + return ACTIVE;
156 + }
157 + };
158 + links.add(curLink);
159 + if (d1 instanceof DeviceId && d2 instanceof DeviceId) {
160 + TopologyVertex v1 = () -> (DeviceId) d1, v2 = () -> (DeviceId) d2;
161 + createdGraph.addVertex(v1);
162 + createdGraph.addVertex(v2);
163 + createdGraph.addEdge(new TopologyEdge() {
164 + @Override
165 + public Link link() {
166 + return curLink;
167 + }
168 +
169 + @Override
170 + public TopologyVertex src() {
171 + return v1;
172 + }
173 +
174 + @Override
175 + public TopologyVertex dst() {
176 + return v2;
177 + }
178 + });
179 + }
180 + }
181 +
182 +
183 +}
1 +package org.onosproject.flowanalyzer;
2 +import org.onosproject.net.topology.Topology;
3 +import org.onosproject.net.topology.TopologyGraph;
4 +import org.onosproject.net.topology.TopologyServiceAdapter;
5 +
6 +
7 +/**
8 + * Created by nikcheerla on 7/20/15.
9 + */
10 +public class MockTopologyService extends TopologyServiceAdapter {
11 + TopologyGraph cur;
12 +
13 + public MockTopologyService(TopologyGraph g) {
14 + cur = g;
15 + }
16 +
17 + @Override
18 + public TopologyGraph getGraph(Topology topology) {
19 + return cur;
20 + }
21 +}