blob: 8283a22fbaf5b8463de0296bb0e281420cea9eb9 [file] [log] [blame]
Thomas Vachuskab6451472015-03-31 16:03:56 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuskab6451472015-03-31 16:03:56 -07003 *
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 */
16package org.onosproject.demo;
17
Ray Milkeyd84f89b2018-08-17 14:54:17 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.base.Predicate;
22import com.google.common.base.Stopwatch;
23import com.google.common.collect.FluentIterable;
24import com.google.common.collect.Lists;
25import com.google.common.collect.Sets;
26import com.google.common.util.concurrent.ThreadFactoryBuilder;
Thomas Vachuskab6451472015-03-31 16:03:56 -070027import org.apache.commons.lang.math.RandomUtils;
Thomas Vachuskab6451472015-03-31 16:03:56 -070028import org.onlab.packet.MacAddress;
29import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.ControllerNode;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.mastership.MastershipService;
35import org.onosproject.net.Device;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070036import org.onosproject.net.DeviceId;
Thomas Vachuskab6451472015-03-31 16:03:56 -070037import org.onosproject.net.Host;
38import org.onosproject.net.HostId;
39import org.onosproject.net.MastershipRole;
40import org.onosproject.net.PortNumber;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.flow.DefaultFlowRule;
43import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
Ray Milkeyd13a37b2015-06-12 11:55:17 -070045import org.onosproject.net.flow.FlowRule;
Thomas Vachuskab6451472015-03-31 16:03:56 -070046import org.onosproject.net.flow.FlowRuleOperations;
47import org.onosproject.net.flow.FlowRuleOperationsContext;
48import org.onosproject.net.flow.FlowRuleService;
49import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +000051import org.onosproject.net.flow.criteria.Criterion;
sivachidambaram subramanianf773b652017-05-09 14:40:04 +053052import org.onosproject.net.flow.instructions.Instructions;
sivachidambaram subramanianf773b652017-05-09 14:40:04 +053053import org.onosproject.net.flowobjective.DefaultFilteringObjective;
54import org.onosproject.net.flowobjective.DefaultForwardingObjective;
sivachidambaram subramanianf773b652017-05-09 14:40:04 +053055import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070056import org.onosproject.net.flowobjective.FilteringObjective;
57import org.onosproject.net.flowobjective.FlowObjectiveService;
58import org.onosproject.net.flowobjective.ForwardingObjective;
sivachidambaram subramanianf773b652017-05-09 14:40:04 +053059import org.onosproject.net.flowobjective.ObjectiveContext;
Thomas Vachuskab6451472015-03-31 16:03:56 -070060import org.onosproject.net.host.HostService;
61import org.onosproject.net.intent.Constraint;
62import org.onosproject.net.intent.HostToHostIntent;
63import org.onosproject.net.intent.Intent;
64import org.onosproject.net.intent.IntentService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070065import org.osgi.service.component.annotations.Activate;
66import org.osgi.service.component.annotations.Component;
67import org.osgi.service.component.annotations.Deactivate;
68import org.osgi.service.component.annotations.Reference;
69import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuskab6451472015-03-31 16:03:56 -070070import org.slf4j.Logger;
71
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072import java.security.SecureRandom;
73import java.util.Collection;
74import java.util.Collections;
75import java.util.HashMap;
76import java.util.HashSet;
77import java.util.Iterator;
78import java.util.LinkedList;
79import java.util.List;
80import java.util.Map;
81import java.util.Objects;
82import java.util.Optional;
83import java.util.Random;
84import java.util.Set;
85import java.util.concurrent.Callable;
86import java.util.concurrent.CountDownLatch;
87import java.util.concurrent.ExecutionException;
88import java.util.concurrent.ExecutorService;
89import java.util.concurrent.Executors;
90import java.util.concurrent.Future;
91import java.util.concurrent.TimeUnit;
92import java.util.concurrent.TimeoutException;
93import java.util.concurrent.atomic.AtomicLong;
Thomas Vachuskab6451472015-03-31 16:03:56 -070094
95import static org.slf4j.LoggerFactory.getLogger;
96
97/**
98 * Application to set up demos.
99 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700100@Component(immediate = true, service = DemoApi.class)
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800101public class DemoInstaller implements DemoApi {
Thomas Vachuskab6451472015-03-31 16:03:56 -0700102
103 private final Logger log = getLogger(getClass());
104
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskab6451472015-03-31 16:03:56 -0700106 protected CoreService coreService;
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskab6451472015-03-31 16:03:56 -0700109 protected IntentService intentService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskab6451472015-03-31 16:03:56 -0700112 protected HostService hostService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskab6451472015-03-31 16:03:56 -0700115 protected MastershipService mastershipService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskab6451472015-03-31 16:03:56 -0700118 protected ClusterService clusterService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskab6451472015-03-31 16:03:56 -0700121 protected DeviceService deviceService;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskab6451472015-03-31 16:03:56 -0700124 protected FlowRuleService flowService;
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530127 protected FlowObjectiveService objectiveService;
128
Thomas Vachuskab6451472015-03-31 16:03:56 -0700129 private ExecutorService worker;
130
131 private ExecutorService installWorker;
132
133 private ApplicationId appId;
134
135 private final Set<Intent> existingIntents = new HashSet<>();
136 private RandomInstaller randomInstaller;
137
138 private ObjectMapper mapper = new ObjectMapper();
139
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530140 private AtomicLong macIndex;
Thomas Vachuskab6451472015-03-31 16:03:56 -0700141
142
143 @Activate
144 public void activate() {
145 String nodeId = clusterService.getLocalNode().ip().toString();
146 appId = coreService.registerApplication("org.onosproject.demo.installer."
147 + nodeId);
148 worker = Executors.newFixedThreadPool(1,
149 new ThreadFactoryBuilder()
150 .setNameFormat("demo-app-worker")
151 .build());
152 log.info("Started with Application ID {}", appId.id());
153 }
154
155 @Deactivate
156 public void deactivate() {
157 shutdownAndAwaitTermination(worker);
158 if (installWorker != null && !installWorker.isShutdown()) {
159 shutdownAndAwaitTermination(installWorker);
160 }
161 log.info("Stopped");
162 }
163
164 @Override
165 public JsonNode flowTest(Optional<JsonNode> params) {
166 int flowsPerDevice = 1000;
167 int neighbours = 0;
168 boolean remove = true;
169 if (params.isPresent()) {
170 flowsPerDevice = params.get().get("flowsPerDevice").asInt();
171 neighbours = params.get().get("neighbours").asInt();
172 remove = params.get().get("remove").asBoolean();
173 }
174
175 Future<JsonNode> future = worker.submit(new FlowTest(flowsPerDevice, neighbours, remove));
176
177 try {
178 return future.get(10, TimeUnit.SECONDS);
179 } catch (InterruptedException | ExecutionException | TimeoutException e) {
180 ObjectNode node = mapper.createObjectNode();
181 node.put("Error", e.getMessage());
182 return node;
183 }
184 }
185
186 @Override
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530187 public JsonNode flowObjTest(Optional<JsonNode> params) {
188 int flowObjPerDevice = 1000;
189 int neighbours = 0;
190 boolean remove = true;
191 String typeObj = "forward";
192 if (params.isPresent()) {
193 flowObjPerDevice = params.get().get("flowObjPerDevice").asInt();
194 neighbours = params.get().get("neighbours").asInt();
195 remove = params.get().get("remove").asBoolean();
196 typeObj = params.get().get("typeObj").asText().toString();
197 }
198
199 Future<JsonNode> future = worker.submit(new FlowObjTest(flowObjPerDevice, neighbours, remove, typeObj));
200
201 try {
202 return future.get(10, TimeUnit.SECONDS);
203 } catch (InterruptedException | ExecutionException | TimeoutException e) {
204 ObjectNode node = mapper.createObjectNode();
205 node.put("Error", e.getMessage());
206 return node;
207 }
208 }
209
210 @Override
Thomas Vachuskab6451472015-03-31 16:03:56 -0700211 public void setup(InstallType type, Optional<JsonNode> runParams) {
212 switch (type) {
213 case MESH:
214 log.debug("Installing mesh intents");
215 worker.execute(new MeshInstaller());
216 break;
217 case RANDOM:
218 //check that we do not have a random installer running
219 if (installWorker == null || installWorker.isShutdown()) {
220 installWorker = Executors.newFixedThreadPool(1,
221 new ThreadFactoryBuilder()
222 .setNameFormat("random-worker")
223 .build());
224 log.debug("Installing random sequence of intents");
225 randomInstaller = new RandomInstaller(runParams);
226 installWorker.execute(randomInstaller);
227 } else {
228 log.warn("Random installer is already running");
229 }
230 break;
231 default:
232 throw new IllegalArgumentException("What is it you want exactly?");
233 }
234 }
235
236 @Override
237 public void tearDown() {
238 worker.submit(new UnInstaller());
239 }
240
241
242 /**
243 * Simply installs a mesh of intents from all the hosts existing in the network.
244 */
245 private class MeshInstaller implements Runnable {
246
247 @Override
248 public void run() {
249 TrafficSelector selector = DefaultTrafficSelector.emptySelector();
250 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
251 List<Constraint> constraint = Lists.newArrayList();
252 List<Host> hosts = Lists.newArrayList(hostService.getHosts());
253 while (!hosts.isEmpty()) {
254 Host src = hosts.remove(0);
255 for (Host dst : hosts) {
256 HostToHostIntent intent = HostToHostIntent.builder()
257 .appId(appId)
258 .one(src.id())
259 .two(dst.id())
260 .selector(selector)
261 .treatment(treatment)
262 .constraints(constraint)
263 .build();
264 existingIntents.add(intent);
265 intentService.submit(intent);
266 }
267 }
268 }
269 }
270
271 /**
272 * Randomly installs and withdraws intents.
273 */
274 private class RandomInstaller implements Runnable {
275
276 private final boolean isLocal;
277 private final Set<Host> hosts;
278
Ray Milkeyb68bbbc2017-12-18 10:05:49 -0800279 private final Random random = new SecureRandom();
Thomas Vachuskab6451472015-03-31 16:03:56 -0700280
281 private Set<HostPair> uninstalledOrWithdrawn;
282 private Set<HostPair> installed;
283
284 private CountDownLatch latch;
285
286 //used to wait on a batch to be processed.
287 private static final int ITERATIONMAX = 50000000;
288
289
290 public RandomInstaller(Optional<JsonNode> runParams) {
291 /*
292 Check if we have params and honour them. Otherwise
293 set defaults to processing only local stuff and
294 all local hosts.
295 */
296 if (runParams.isPresent()) {
297 JsonNode node = runParams.get();
298 isLocal = node.get("local").asBoolean();
299 hosts = node.get("hosts") == null ? Sets.newHashSet(hostService.getHosts()) :
300 constructHostIds(node.get("hosts").elements());
301 } else {
302 isLocal = true;
303 hosts = Sets.newHashSet(hostService.getHosts());
304 }
305
306 //construct list of intents.
307 installed = Sets.newHashSet();
308 if (isLocal) {
309 uninstalledOrWithdrawn = buildPairs(pruneHostsByMasterShip());
310 } else {
311 uninstalledOrWithdrawn = buildPairs(hosts);
312 }
313
314 }
315
316 private Set<Host> constructHostIds(Iterator<JsonNode> elements) {
317 Set<Host> hostIds = Sets.newHashSet();
318 JsonNode n;
319 while (elements.hasNext()) {
320 n = elements.next();
321 hostIds.add(hostService.getHost(HostId.hostId(n.textValue())));
322 }
323 return hostIds;
324 }
325
326 @Override
327 public void run() {
328 if (!installWorker.isShutdown()) {
329 randomize();
330 latch = new CountDownLatch(1);
331 try {
332 trackIntents();
333 } catch (InterruptedException e) {
334 shutdown();
335 }
336 }
337
338 }
339
340
341 /**
342 * Check whether the previously submitted batch is in progress
343 * and if yes submit the next one. If things hang, wait for at
344 * most 5 seconds and bail.
345 * @throws InterruptedException if the thread go interupted
346 */
347 private void trackIntents() throws InterruptedException {
348 //FIXME
349 // TODO generate keys for each set of intents to allow manager to throttle
350 // TODO may also look into the store to see how many operations are pending
351
352 //if everything is good proceed.
353 if (!installWorker.isShutdown()) {
354 installWorker.execute(this);
355 }
356
357 }
358
359 public void shutdown() {
360 log.warn("Shutting down random installer!");
361 cleanUp();
362 }
363
364
365 /**
366 * Shuffle the uninstalled and installed list (separately) and select
367 * a random number of them and install or uninstall them respectively.
368 */
369 private void randomize() {
370 List<HostPair> hostList = new LinkedList<>(uninstalledOrWithdrawn);
371 Collections.shuffle(hostList);
372 List<HostPair> toInstall = hostList.subList(0,
373 random.nextInt(hostList.size() - 1));
374 List<HostPair> toRemove;
375 if (!installed.isEmpty()) {
376 hostList = new LinkedList<>(installed);
377 Collections.shuffle(hostList);
378 toRemove = hostList.subList(0,
379 random.nextInt(hostList.size() - 1));
380 uninstallIntents(toRemove);
381 }
382 installIntents(toInstall);
383
384 }
385
386 private void installIntents(List<HostPair> toInstall) {
387 for (HostPair pair : toInstall) {
388 installed.add(pair);
389 uninstalledOrWithdrawn.remove(pair);
390 intentService.submit(pair.h2hIntent());
391 }
392 }
393
394 private void uninstallIntents(Collection<HostPair> toRemove) {
395 for (HostPair pair : toRemove) {
396 installed.remove(pair);
397 uninstalledOrWithdrawn.add(pair);
398 intentService.withdraw(pair.h2hIntent());
399 }
400 }
401
402 /**
403 * Take everything and remove it all.
404 */
405 private void cleanUp() {
406 List<HostPair> allPairs = Lists.newArrayList(installed);
407 allPairs.addAll(uninstalledOrWithdrawn);
408 for (HostPair pair : allPairs) {
409 intentService.withdraw(pair.h2hIntent());
410 }
411 }
412
413
414 private Set<HostPair> buildPairs(Set<Host> hosts) {
415 Set<HostPair> pairs = Sets.newHashSet();
416 Iterator<Host> it = Sets.newHashSet(hosts).iterator();
417 while (it.hasNext()) {
418 Host src = it.next();
419 it.remove();
420 for (Host dst : hosts) {
421 pairs.add(new HostPair(src, dst));
422 }
423 }
424 return pairs;
425 }
426
427 private Set<Host> pruneHostsByMasterShip() {
428 return FluentIterable.from(hosts)
429 .filter(hasLocalMaster())
430 .toSet();
431
432 }
433
434 private Predicate<? super Host> hasLocalMaster() {
Sho SHIMIZU74626412015-09-11 11:46:27 -0700435 return host -> mastershipService.getLocalRole(
436 host.location().deviceId()).equals(MastershipRole.MASTER);
Thomas Vachuskab6451472015-03-31 16:03:56 -0700437 }
438
439
440 /**
441 * Simple class representing a pair of hosts and precomputes the associated
442 * h2h intent.
443 */
444 private class HostPair {
445
446 private final Host src;
447 private final Host dst;
448
449 private final TrafficSelector selector = DefaultTrafficSelector.emptySelector();
450 private final TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
451 private final List<Constraint> constraint = Lists.newArrayList();
452 private final HostToHostIntent intent;
453
454 public HostPair(Host src, Host dst) {
455 this.src = src;
456 this.dst = dst;
457 this.intent = HostToHostIntent.builder()
458 .appId(appId)
459 .one(src.id())
460 .two(dst.id())
461 .selector(selector)
462 .treatment(treatment)
463 .constraints(constraint)
464 .build();
465 }
466
467 public HostToHostIntent h2hIntent() {
468 return intent;
469 }
470
471 @Override
472 public boolean equals(Object o) {
473 if (this == o) {
474 return true;
475 }
476 if (o == null || getClass() != o.getClass()) {
477 return false;
478 }
479
480 HostPair hostPair = (HostPair) o;
481
482 return Objects.equals(src, hostPair.src) &&
483 Objects.equals(dst, hostPair.dst);
484
485 }
486
487 @Override
488 public int hashCode() {
489 return Objects.hash(src, dst);
490 }
491
492
493 }
494
495 }
496
497 /**
498 * Remove anything that is running and clear it all out.
499 */
500 private class UnInstaller implements Runnable {
501 @Override
502 public void run() {
503 if (!existingIntents.isEmpty()) {
504 clearExistingIntents();
505 }
506
507 if (installWorker != null && !installWorker.isShutdown()) {
508 shutdownAndAwaitTermination(installWorker);
509 randomInstaller.shutdown();
510 }
511 }
512
513 private void clearExistingIntents() {
514 for (Intent i : existingIntents) {
515 intentService.withdraw(i);
516 }
517 existingIntents.clear();
518 }
519 }
520
521 /**
522 * Shutdown a pool cleanly if possible.
523 *
524 * @param pool an executorService
525 */
526 private void shutdownAndAwaitTermination(ExecutorService pool) {
527 pool.shutdown(); // Disable new tasks from being submitted
528 try {
529 // Wait a while for existing tasks to terminate
530 if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
531 pool.shutdownNow(); // Cancel currently executing tasks
532 // Wait a while for tasks to respond to being cancelled
533 if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
534 log.error("Pool did not terminate");
535 }
536 }
537 } catch (Exception ie) {
538 // (Re-)Cancel if current thread also interrupted
539 pool.shutdownNow();
540 // Preserve interrupt status
541 Thread.currentThread().interrupt();
542 }
543 }
544
545 private class FlowTest implements Callable<JsonNode> {
546 private final int flowPerDevice;
547 private final int neighbours;
548 private final boolean remove;
549 private FlowRuleOperations.Builder adds;
550 private FlowRuleOperations.Builder removes;
551
552 public FlowTest(int flowsPerDevice, int neighbours, boolean remove) {
553 this.flowPerDevice = flowsPerDevice;
554 this.neighbours = neighbours;
555 this.remove = remove;
556 prepareInstallation();
557 }
558
559 private void prepareInstallation() {
560 Set<ControllerNode> instances = Sets.newHashSet(clusterService.getNodes());
561 instances.remove(clusterService.getLocalNode());
562 Set<NodeId> acceptableNodes = Sets.newHashSet();
563 if (neighbours >= instances.size()) {
564 instances.forEach(instance -> acceptableNodes.add(instance.id()));
565 } else {
566 Iterator<ControllerNode> nodes = instances.iterator();
567 for (int i = neighbours; i > 0; i--) {
568 acceptableNodes.add(nodes.next().id());
569 }
570 }
571 acceptableNodes.add(clusterService.getLocalNode().id());
572
573 Set<Device> devices = Sets.newHashSet();
574 for (Device dev : deviceService.getDevices()) {
575 if (acceptableNodes.contains(
576 mastershipService.getMasterFor(dev.id()))) {
577 devices.add(dev);
578 }
579 }
580
581 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
582 .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build();
583 TrafficSelector.Builder sbuilder;
584 FlowRuleOperations.Builder rules = FlowRuleOperations.builder();
585 FlowRuleOperations.Builder remove = FlowRuleOperations.builder();
586
587 for (Device d : devices) {
Ray Milkey3717e602018-02-01 13:49:47 -0800588 for (long i = 0; i < this.flowPerDevice; i++) {
Thomas Vachuskab6451472015-03-31 16:03:56 -0700589 sbuilder = DefaultTrafficSelector.builder();
590
591 sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i))
592 .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt()));
593
594
YPZhang47309762016-06-17 16:27:41 -0700595 int randomPriority = RandomUtils.nextInt(FlowRule.MAX_PRIORITY);
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700596 FlowRule f = DefaultFlowRule.builder()
597 .forDevice(d.id())
598 .withSelector(sbuilder.build())
599 .withTreatment(treatment)
600 .withPriority(randomPriority)
601 .fromApp(appId)
602 .makeTemporary(10)
603 .build();
Thomas Vachuskab6451472015-03-31 16:03:56 -0700604 rules.add(f);
605 remove.remove(f);
606
607 }
608 }
609
610 this.adds = rules;
611 this.removes = remove;
612 }
613
614 @Override
615 public JsonNode call() throws Exception {
616 ObjectNode node = mapper.createObjectNode();
617 CountDownLatch latch = new CountDownLatch(1);
618 flowService.apply(adds.build(new FlowRuleOperationsContext() {
619
620 private final Stopwatch timer = Stopwatch.createStarted();
621
622 @Override
623 public void onSuccess(FlowRuleOperations ops) {
624
625 long elapsed = timer.elapsed(TimeUnit.MILLISECONDS);
626 node.put("elapsed", elapsed);
627
628
629 latch.countDown();
630 }
631 }));
632
633 latch.await(10, TimeUnit.SECONDS);
634 if (this.remove) {
635 flowService.apply(removes.build());
636 }
637 return node;
638 }
639 }
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530640
641 private class FlowObjTest implements Callable<JsonNode> {
642 private final int flowObjPerDevice;
643 private final int neighbours;
644 private final boolean remove;
645 private final String typeObj;
646 Map<DeviceId, Set<ForwardingObjective.Builder>> forwardingObj = new HashMap<>();
647 Map<DeviceId, Set<FilteringObjective.Builder>> filteringObj = new HashMap<>();
648
649 public FlowObjTest(int flowObjPerDevice, int neighbours, boolean remove, String typeObj) {
650 this.flowObjPerDevice = flowObjPerDevice;
651 this.neighbours = neighbours;
652 this.remove = remove;
653 this.typeObj = typeObj;
654 prepareInstallation();
655 }
656
657 private void prepareInstallation() {
658 Set<ControllerNode> instances = Sets.newHashSet(clusterService.getNodes());
659 instances.remove(clusterService.getLocalNode());
660 Set<NodeId> acceptableNodes = Sets.newHashSet();
661 macIndex = new AtomicLong(0);
662 if (neighbours >= instances.size()) {
663 instances.forEach(instance -> acceptableNodes.add(instance.id()));
664 } else {
665 Iterator<ControllerNode> nodes = instances.iterator();
666 for (int i = neighbours; i > 0; i--) {
667 acceptableNodes.add(nodes.next().id());
668 }
669 }
670 acceptableNodes.add(clusterService.getLocalNode().id());
671
672 Set<Device> devices = Sets.newHashSet();
673 for (Device dev : deviceService.getDevices()) {
674 if (acceptableNodes.contains(
675 mastershipService.getMasterFor(dev.id()))) {
676 devices.add(dev);
677 }
678 }
679 for (Device device : devices) {
680 switch (this.typeObj) {
681 case "forward":
682 forwardingObj.put(device.id(), createForward(flowObjPerDevice));
683 break;
684 case "filter":
685 filteringObj.put(device.id(), createFilter(flowObjPerDevice));
686 break;
687 default:
688 log.warn("Unsupported Flow Objective Type");
689 break;
690 }
691 }
692 }
693
694 /*
695 * Method to create forwarding flow objectives.
696 */
697 private Set<ForwardingObjective.Builder> createForward(int flowObjPerDevice) {
698 Set<ForwardingObjective.Builder> fObj = new HashSet<>();
699 for (int i = 0; i < flowObjPerDevice; i++) {
700 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
701 sbuilder.matchEthSrc(MacAddress.valueOf(macIndex.incrementAndGet()));
702 sbuilder.matchInPort(PortNumber.portNumber(2));
703
704 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
705 tbuilder.add(Instructions.createOutput(PortNumber.portNumber(3)));
706
707 ForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
708 fobBuilder.withFlag(ForwardingObjective.Flag.SPECIFIC)
709 .withSelector(sbuilder.build())
710 .withTreatment(tbuilder.build())
711 .withPriority(i + 1)
712 .fromApp(appId)
713 .makePermanent();
714
715 fObj.add(fobBuilder);
716 }
717 return fObj;
718 }
719
720 /*
721 *Method to install forwarding flow objectives.
722 */
723 private ObjectNode installForward() {
724 ObjectNode node = mapper.createObjectNode();
725 long addStartTime = System.currentTimeMillis();
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +0000726 int totalFlowObj = (flowObjPerDevice * forwardingObj.keySet().size());
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530727 CountDownLatch installationLatch = new CountDownLatch(totalFlowObj);
728 for (DeviceId dId : forwardingObj.keySet()) {
729 Set<ForwardingObjective.Builder> fObjs = forwardingObj.get(dId);
730 for (ForwardingObjective.Builder builder : fObjs) {
731 ObjectiveContext context = new DefaultObjectiveContext(
732 (objective -> {
733 installationLatch.countDown();
734 })
735 );
736 objectiveService.forward(dId, builder.add(context));
737 }
738 }
739
740 try {
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +0000741 installationLatch.await(10, TimeUnit.SECONDS);
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530742 } catch (InterruptedException e) {
743 Thread.interrupted();
744 }
745
746 node.put("elapsed", System.currentTimeMillis() - addStartTime);
747 log.info("{} Forward Flow Objectives elapsed -> {} ms",
748 totalFlowObj, (System.currentTimeMillis() - addStartTime));
749
750 if (this.remove) {
751 for (DeviceId dId : forwardingObj.keySet()) {
752 Set<ForwardingObjective.Builder> fObjs = forwardingObj.get(dId);
753 for (ForwardingObjective.Builder builder : fObjs) {
754 objectiveService.forward(dId, builder.remove());
755 }
756 }
757 }
758 return node;
759
760 }
761
762 /*
763 * Method to create filtering flow objectives.
764 */
765 private Set<FilteringObjective.Builder> createFilter(int flowObjPerDevice) {
766 Set<FilteringObjective.Builder> filterObjSet = new HashSet<>();
767 for (int i = 0; i < flowObjPerDevice; i++) {
768 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
769 tbuilder.add(Instructions.createOutput(PortNumber.portNumber(2)));
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +0000770 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Ray Milkey3717e602018-02-01 13:49:47 -0800771 sbuilder.matchInPort(PortNumber.portNumber(i + 3L));
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +0000772 sbuilder.matchEthDst(MacAddress.valueOf("12:00:00:00:00:10"));
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530773
774 FilteringObjective.Builder fobBuilder = DefaultFilteringObjective.builder();
775 fobBuilder.fromApp(appId)
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +0000776 .withKey(sbuilder.build().getCriterion(Criterion.Type.IN_PORT))
777 .addCondition(sbuilder.build().getCriterion(Criterion.Type.ETH_DST))
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530778 .withMeta(tbuilder.build())
779 .permit()
780 .withPriority(i + 1)
781 .makePermanent();
782
783 filterObjSet.add(fobBuilder);
784 }
785
786 return filterObjSet;
787 }
788
789 /*
790 * Method to install filtering flow objectives.
791 */
792 private ObjectNode installFilter() {
793 ObjectNode node = mapper.createObjectNode();
794 long addStartTime = System.currentTimeMillis();
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +0000795 int totalFlowObj = (flowObjPerDevice * filteringObj.keySet().size());
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530796 CountDownLatch installationLatch = new CountDownLatch(totalFlowObj);
797 for (DeviceId dId : filteringObj.keySet()) {
798 Set<FilteringObjective.Builder> fObjs = filteringObj.get(dId);
799 for (FilteringObjective.Builder builder : fObjs) {
800 ObjectiveContext context = new DefaultObjectiveContext(
801 (objective -> {
802 installationLatch.countDown();
803 })
804 );
805 objectiveService.filter(dId, builder.add(context));
806 }
807 }
808
809 try {
Sivachidambaram Subramanian89a09ec2017-07-11 09:46:34 +0000810 installationLatch.await(10, TimeUnit.SECONDS);
sivachidambaram subramanianf773b652017-05-09 14:40:04 +0530811 } catch (InterruptedException e) {
812 Thread.interrupted();
813 }
814
815 node.put("elapsed", System.currentTimeMillis() - addStartTime);
816 log.info("{} Filter Flow Objectives elapsed -> {} ms",
817 totalFlowObj, (System.currentTimeMillis() - addStartTime));
818
819 if (this.remove) {
820 for (DeviceId dId : filteringObj.keySet()) {
821 Set<FilteringObjective.Builder> fObjs = filteringObj.get(dId);
822 for (FilteringObjective.Builder builder : fObjs) {
823 objectiveService.filter(dId, builder.remove());
824 }
825 }
826 }
827 return node;
828 }
829
830
831 @Override
832 public JsonNode call() throws Exception {
833 ObjectNode node = mapper.createObjectNode();
834 switch (this.typeObj) {
835 case "forward":
836 node = installForward();
837 break;
838 case "filter":
839 node = installFilter();
840 break;
841 default:
842 log.warn("Unsupported Flow Objective Type");
843 }
844 return node;
845 }
846 }
Thomas Vachuskab6451472015-03-31 16:03:56 -0700847}
848
849