alshabib
Committed by Ali "The Bomb" Al-Shabibi

Added test code to test the flow subsystem performance

Change-Id: I1a7c68492760a63b7d092c3ca71e4964123c8aa7
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
106 com.sun.jersey.server.impl.container.servlet, 106 com.sun.jersey.server.impl.container.servlet,
107 com.fasterxml.jackson.databind, 107 com.fasterxml.jackson.databind,
108 com.fasterxml.jackson.databind.node, 108 com.fasterxml.jackson.databind.node,
109 + org.apache.commons.lang.math.*,
109 com.google.common.*, 110 com.google.common.*,
110 org.onlab.packet.*, 111 org.onlab.packet.*,
111 org.onlab.rest.*, 112 org.onlab.rest.*,
......
...@@ -27,6 +27,12 @@ public interface DemoAPI { ...@@ -27,6 +27,12 @@ public interface DemoAPI {
27 enum InstallType { MESH, RANDOM }; 27 enum InstallType { MESH, RANDOM };
28 28
29 /** 29 /**
30 + * Tests flow subsystem based on the parameters supplied.
31 + * @param params the test parameters
32 + */
33 + JsonNode flowTest(Optional<JsonNode> params);
34 +
35 + /**
30 * Installs intents based on the installation type. 36 * Installs intents based on the installation type.
31 * @param type the installation type. 37 * @param type the installation type.
32 * @param runParams run params 38 * @param runParams run params
......
...@@ -16,27 +16,40 @@ ...@@ -16,27 +16,40 @@
16 package org.onosproject.demo; 16 package org.onosproject.demo;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.ObjectMapper;
20 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 import com.google.common.base.Predicate; 21 import com.google.common.base.Predicate;
22 +import com.google.common.base.Stopwatch;
20 import com.google.common.collect.FluentIterable; 23 import com.google.common.collect.FluentIterable;
21 import com.google.common.collect.Lists; 24 import com.google.common.collect.Lists;
22 import com.google.common.collect.Sets; 25 import com.google.common.collect.Sets;
23 import com.google.common.util.concurrent.ThreadFactoryBuilder; 26 import com.google.common.util.concurrent.ThreadFactoryBuilder;
27 +import org.apache.commons.lang.math.RandomUtils;
24 import org.apache.felix.scr.annotations.Activate; 28 import org.apache.felix.scr.annotations.Activate;
25 import org.apache.felix.scr.annotations.Component; 29 import org.apache.felix.scr.annotations.Component;
26 import org.apache.felix.scr.annotations.Deactivate; 30 import org.apache.felix.scr.annotations.Deactivate;
27 import org.apache.felix.scr.annotations.Reference; 31 import org.apache.felix.scr.annotations.Reference;
28 import org.apache.felix.scr.annotations.ReferenceCardinality; 32 import org.apache.felix.scr.annotations.ReferenceCardinality;
29 import org.apache.felix.scr.annotations.Service; 33 import org.apache.felix.scr.annotations.Service;
30 - 34 +import org.onlab.packet.MacAddress;
31 import org.onosproject.cluster.ClusterService; 35 import org.onosproject.cluster.ClusterService;
36 +import org.onosproject.cluster.ControllerNode;
37 +import org.onosproject.cluster.NodeId;
32 import org.onosproject.core.ApplicationId; 38 import org.onosproject.core.ApplicationId;
33 import org.onosproject.core.CoreService; 39 import org.onosproject.core.CoreService;
34 import org.onosproject.mastership.MastershipService; 40 import org.onosproject.mastership.MastershipService;
41 +import org.onosproject.net.Device;
35 import org.onosproject.net.Host; 42 import org.onosproject.net.Host;
36 import org.onosproject.net.HostId; 43 import org.onosproject.net.HostId;
37 import org.onosproject.net.MastershipRole; 44 import org.onosproject.net.MastershipRole;
45 +import org.onosproject.net.PortNumber;
46 +import org.onosproject.net.device.DeviceService;
47 +import org.onosproject.net.flow.DefaultFlowRule;
38 import org.onosproject.net.flow.DefaultTrafficSelector; 48 import org.onosproject.net.flow.DefaultTrafficSelector;
39 import org.onosproject.net.flow.DefaultTrafficTreatment; 49 import org.onosproject.net.flow.DefaultTrafficTreatment;
50 +import org.onosproject.net.flow.FlowRuleOperations;
51 +import org.onosproject.net.flow.FlowRuleOperationsContext;
52 +import org.onosproject.net.flow.FlowRuleService;
40 import org.onosproject.net.flow.TrafficSelector; 53 import org.onosproject.net.flow.TrafficSelector;
41 import org.onosproject.net.flow.TrafficTreatment; 54 import org.onosproject.net.flow.TrafficTreatment;
42 import org.onosproject.net.host.HostService; 55 import org.onosproject.net.host.HostService;
...@@ -48,7 +61,6 @@ import org.onosproject.net.intent.IntentOperations; ...@@ -48,7 +61,6 @@ import org.onosproject.net.intent.IntentOperations;
48 import org.onosproject.net.intent.IntentService; 61 import org.onosproject.net.intent.IntentService;
49 import org.slf4j.Logger; 62 import org.slf4j.Logger;
50 63
51 -
52 import java.util.Collection; 64 import java.util.Collection;
53 import java.util.Collections; 65 import java.util.Collections;
54 import java.util.HashSet; 66 import java.util.HashSet;
...@@ -59,11 +71,14 @@ import java.util.Objects; ...@@ -59,11 +71,14 @@ import java.util.Objects;
59 import java.util.Optional; 71 import java.util.Optional;
60 import java.util.Random; 72 import java.util.Random;
61 import java.util.Set; 73 import java.util.Set;
74 +import java.util.concurrent.Callable;
62 import java.util.concurrent.CountDownLatch; 75 import java.util.concurrent.CountDownLatch;
76 +import java.util.concurrent.ExecutionException;
63 import java.util.concurrent.ExecutorService; 77 import java.util.concurrent.ExecutorService;
64 import java.util.concurrent.Executors; 78 import java.util.concurrent.Executors;
79 +import java.util.concurrent.Future;
65 import java.util.concurrent.TimeUnit; 80 import java.util.concurrent.TimeUnit;
66 - 81 +import java.util.concurrent.TimeoutException;
67 82
68 import static org.slf4j.LoggerFactory.getLogger; 83 import static org.slf4j.LoggerFactory.getLogger;
69 84
...@@ -94,15 +109,23 @@ public class DemoInstaller implements DemoAPI { ...@@ -94,15 +109,23 @@ public class DemoInstaller implements DemoAPI {
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected ClusterService clusterService; 110 protected ClusterService clusterService;
96 111
112 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 + protected DeviceService deviceService;
114 +
115 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 + protected FlowRuleService flowService;
117 +
97 private ExecutorService worker; 118 private ExecutorService worker;
98 119
99 - private ExecutorService randomWorker; 120 + private ExecutorService installWorker;
100 121
101 private ApplicationId appId; 122 private ApplicationId appId;
102 123
103 private final Set<Intent> existingIntents = new HashSet<>(); 124 private final Set<Intent> existingIntents = new HashSet<>();
104 private RandomInstaller randomInstaller; 125 private RandomInstaller randomInstaller;
105 126
127 + private ObjectMapper mapper = new ObjectMapper();
128 +
106 129
107 130
108 @Activate 131 @Activate
...@@ -120,13 +143,33 @@ public class DemoInstaller implements DemoAPI { ...@@ -120,13 +143,33 @@ public class DemoInstaller implements DemoAPI {
120 @Deactivate 143 @Deactivate
121 public void deactivate() { 144 public void deactivate() {
122 shutdownAndAwaitTermination(worker); 145 shutdownAndAwaitTermination(worker);
123 - if (!randomWorker.isShutdown()) { 146 + if (installWorker != null && !installWorker.isShutdown()) {
124 - shutdownAndAwaitTermination(randomWorker); 147 + shutdownAndAwaitTermination(installWorker);
125 } 148 }
126 log.info("Stopped"); 149 log.info("Stopped");
127 } 150 }
128 151
129 @Override 152 @Override
153 + public JsonNode flowTest(Optional<JsonNode> params) {
154 + int flowsPerDevice = 1000;
155 + int neighbours = 0;
156 + if (params.isPresent()) {
157 + flowsPerDevice = params.get().get("flowsPerDevice").asInt();
158 + neighbours = params.get().get("neighbours").asInt();
159 + }
160 +
161 + Future<JsonNode> future = worker.submit(new FlowTest(flowsPerDevice, neighbours));
162 +
163 + try {
164 + return future.get(10, TimeUnit.SECONDS);
165 + } catch (InterruptedException | ExecutionException | TimeoutException e) {
166 + ObjectNode node = mapper.createObjectNode();
167 + node.put("Error", e.getMessage());
168 + return node;
169 + }
170 + }
171 +
172 + @Override
130 public void setup(InstallType type, Optional<JsonNode> runParams) { 173 public void setup(InstallType type, Optional<JsonNode> runParams) {
131 switch (type) { 174 switch (type) {
132 case MESH: 175 case MESH:
...@@ -135,14 +178,14 @@ public class DemoInstaller implements DemoAPI { ...@@ -135,14 +178,14 @@ public class DemoInstaller implements DemoAPI {
135 break; 178 break;
136 case RANDOM: 179 case RANDOM:
137 //check that we do not have a random installer running 180 //check that we do not have a random installer running
138 - if (randomWorker == null || randomWorker.isShutdown()) { 181 + if (installWorker == null || installWorker.isShutdown()) {
139 - randomWorker = Executors.newFixedThreadPool(1, 182 + installWorker = Executors.newFixedThreadPool(1,
140 new ThreadFactoryBuilder() 183 new ThreadFactoryBuilder()
141 .setNameFormat("random-worker") 184 .setNameFormat("random-worker")
142 .build()); 185 .build());
143 log.debug("Installing random sequence of intents"); 186 log.debug("Installing random sequence of intents");
144 randomInstaller = new RandomInstaller(runParams); 187 randomInstaller = new RandomInstaller(runParams);
145 - randomWorker.execute(randomInstaller); 188 + installWorker.execute(randomInstaller);
146 } else { 189 } else {
147 log.warn("Random installer is already running"); 190 log.warn("Random installer is already running");
148 } 191 }
...@@ -239,7 +282,7 @@ public class DemoInstaller implements DemoAPI { ...@@ -239,7 +282,7 @@ public class DemoInstaller implements DemoAPI {
239 282
240 @Override 283 @Override
241 public void run() { 284 public void run() {
242 - if (!randomWorker.isShutdown()) { 285 + if (!installWorker.isShutdown()) {
243 randomize(); 286 randomize();
244 latch = new CountDownLatch(1); 287 latch = new CountDownLatch(1);
245 try { 288 try {
...@@ -269,12 +312,12 @@ public class DemoInstaller implements DemoAPI { ...@@ -269,12 +312,12 @@ public class DemoInstaller implements DemoAPI {
269 log.warn("A batch is stuck processing. " + 312 log.warn("A batch is stuck processing. " +
270 "pending : {}", 313 "pending : {}",
271 intentBatchService.getPendingOperations()); 314 intentBatchService.getPendingOperations());
272 - shutdownAndAwaitTermination(randomWorker); 315 + shutdownAndAwaitTermination(installWorker);
273 } 316 }
274 } 317 }
275 //if everyting is good proceed. 318 //if everyting is good proceed.
276 - if (!randomWorker.isShutdown()) { 319 + if (!installWorker.isShutdown()) {
277 - randomWorker.execute(this); 320 + installWorker.execute(this);
278 } 321 }
279 322
280 } 323 }
...@@ -432,8 +475,8 @@ public class DemoInstaller implements DemoAPI { ...@@ -432,8 +475,8 @@ public class DemoInstaller implements DemoAPI {
432 clearExistingIntents(); 475 clearExistingIntents();
433 } 476 }
434 477
435 - if (randomWorker != null && !randomWorker.isShutdown()) { 478 + if (installWorker != null && !installWorker.isShutdown()) {
436 - shutdownAndAwaitTermination(randomWorker); 479 + shutdownAndAwaitTermination(installWorker);
437 randomInstaller.shutdown(); 480 randomInstaller.shutdown();
438 } 481 }
439 } 482 }
...@@ -470,6 +513,91 @@ public class DemoInstaller implements DemoAPI { ...@@ -470,6 +513,91 @@ public class DemoInstaller implements DemoAPI {
470 } 513 }
471 } 514 }
472 515
516 + private class FlowTest implements Callable<JsonNode> {
517 + private final int flowPerDevice;
518 + private final int neighbours;
519 + private FlowRuleOperations.Builder adds;
520 + private FlowRuleOperations.Builder removes;
521 +
522 + public FlowTest(int flowsPerDevice, int neighbours) {
523 + this.flowPerDevice = flowsPerDevice;
524 + this.neighbours = neighbours;
525 + prepareInstallation();
526 + }
527 +
528 + private void prepareInstallation() {
529 + Set<ControllerNode> instances = Sets.newHashSet(clusterService.getNodes());
530 + instances.remove(clusterService.getLocalNode());
531 + Set<NodeId> acceptableNodes = Sets.newHashSet();
532 + if (neighbours >= instances.size()) {
533 + instances.forEach(instance -> acceptableNodes.add(instance.id()));
534 + } else {
535 + Iterator<ControllerNode> nodes = instances.iterator();
536 + for (int i = neighbours; i > 0; i--) {
537 + acceptableNodes.add(nodes.next().id());
538 + }
539 + }
540 + acceptableNodes.add(clusterService.getLocalNode().id());
541 +
542 + Set<Device> devices = Sets.newHashSet();
543 + for (Device dev : deviceService.getDevices()) {
544 + if (acceptableNodes.contains(
545 + mastershipService.getMasterFor(dev.id()))) {
546 + devices.add(dev);
547 + }
548 + }
549 +
550 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
551 + .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build();
552 + TrafficSelector.Builder sbuilder;
553 + FlowRuleOperations.Builder rules = FlowRuleOperations.builder();
554 + FlowRuleOperations.Builder remove = FlowRuleOperations.builder();
555 +
556 + for (Device d : devices) {
557 + for (int i = 0; i < this.flowPerDevice; i++) {
558 + sbuilder = DefaultTrafficSelector.builder();
559 +
560 + sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i))
561 + .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt()));
562 +
563 +
564 + int randomPriority = RandomUtils.nextInt();
565 + DefaultFlowRule f = new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
566 + randomPriority, appId, 10, false);
567 + rules.add(f);
568 + remove.remove(f);
569 +
570 + }
571 + }
572 +
573 + this.adds = rules;
574 + this.removes = remove;
575 + }
576 +
577 + @Override
578 + public JsonNode call() throws Exception {
579 + ObjectNode node = mapper.createObjectNode();
580 + CountDownLatch latch = new CountDownLatch(1);
581 + flowService.apply(adds.build(new FlowRuleOperationsContext() {
582 +
583 + private final Stopwatch timer = Stopwatch.createStarted();
584 +
585 + @Override
586 + public void onSuccess(FlowRuleOperations ops) {
587 +
588 + long elapsed = timer.elapsed(TimeUnit.MILLISECONDS);
589 + node.put("elapsed", elapsed);
590 +
591 +
592 + latch.countDown();
593 + }
594 + }));
595 +
596 + latch.await(10, TimeUnit.SECONDS);
597 + flowService.apply(removes.build());
598 + return node;
599 + }
600 + }
473 } 601 }
474 602
475 603
......
...@@ -37,6 +37,18 @@ import java.util.Optional; ...@@ -37,6 +37,18 @@ import java.util.Optional;
37 public class DemoResource extends BaseResource { 37 public class DemoResource extends BaseResource {
38 38
39 39
40 +
41 + @POST
42 + @Path("flowTest")
43 + @Consumes(MediaType.APPLICATION_JSON)
44 + @Produces(MediaType.APPLICATION_JSON)
45 + public Response flowTest(InputStream input) throws IOException {
46 + ObjectMapper mapper = new ObjectMapper();
47 + JsonNode cfg = mapper.readTree(input);
48 + DemoAPI demo = get(DemoAPI.class);
49 + return Response.ok(demo.flowTest(Optional.ofNullable(cfg)).toString()).build();
50 + }
51 +
40 @POST 52 @POST
41 @Path("setup") 53 @Path("setup")
42 @Consumes(MediaType.APPLICATION_JSON) 54 @Consumes(MediaType.APPLICATION_JSON)
......