Brian O'Connor
Committed by Gerrit Code Review

Implementation of new Flow Subsystem:

The subsystem no longer returns futures for tracking completion of work.
Notifications are explicitely returned via a call back mechanism. Also, the
subsystem is now asynchronous.

Change-Id: I1a4cef931c24820f9ae9ed9a5398f163f05dfbc9

more flowservice improvements

Change-Id: I5c9c1b6be4b2ebfa523b64f6f52e7634b7d3e05f

more flowservice impl

Change-Id: I05f6774460effb53ced8c36844bcda2f8f6c096f

Manager to store functional (at least i believe it)

Change-Id: I09b04989bd1004c98fe0bafed4c76714b9155d53

flow subsystem functional: need to fix unit tests

Change-Id: I1667f25b91320f625a03e5e1d5e92823184d9de0

flow subsystem functional

Change-Id: I429b3335c16d4fc16f5d55f233dd37c4d1d6111d

finished refactor of flow subsystem

Change-Id: I1899abc6ff6a974a2018d936cc555049c70a6804

fix for null flow provider to use new api

Change-Id: If2fd9bd5baf74d9c61c5c8085cef8bc2d204cbdc
Showing 34 changed files with 1228 additions and 947 deletions
...@@ -19,29 +19,30 @@ package org.onosproject.cli.net; ...@@ -19,29 +19,30 @@ package org.onosproject.cli.net;
19 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
20 import com.fasterxml.jackson.databind.node.ArrayNode; 20 import com.fasterxml.jackson.databind.node.ArrayNode;
21 import com.fasterxml.jackson.databind.node.ObjectNode; 21 import com.fasterxml.jackson.databind.node.ObjectNode;
22 +import com.google.common.base.Stopwatch;
22 import com.google.common.collect.Lists; 23 import com.google.common.collect.Lists;
23 -import com.google.common.collect.Sets; 24 +import org.apache.commons.lang.math.RandomUtils;
24 import org.apache.karaf.shell.commands.Argument; 25 import org.apache.karaf.shell.commands.Argument;
25 import org.apache.karaf.shell.commands.Command; 26 import org.apache.karaf.shell.commands.Command;
27 +import org.onlab.packet.MacAddress;
26 import org.onosproject.cli.AbstractShellCommand; 28 import org.onosproject.cli.AbstractShellCommand;
29 +import org.onosproject.core.ApplicationId;
30 +import org.onosproject.core.CoreService;
27 import org.onosproject.net.Device; 31 import org.onosproject.net.Device;
28 import org.onosproject.net.PortNumber; 32 import org.onosproject.net.PortNumber;
29 import org.onosproject.net.device.DeviceService; 33 import org.onosproject.net.device.DeviceService;
30 -import org.onosproject.net.flow.CompletedBatchOperation;
31 import org.onosproject.net.flow.DefaultFlowRule; 34 import org.onosproject.net.flow.DefaultFlowRule;
32 import org.onosproject.net.flow.DefaultTrafficSelector; 35 import org.onosproject.net.flow.DefaultTrafficSelector;
33 import org.onosproject.net.flow.DefaultTrafficTreatment; 36 import org.onosproject.net.flow.DefaultTrafficTreatment;
34 -import org.onosproject.net.flow.FlowRuleBatchEntry; 37 +import org.onosproject.net.flow.FlowRuleOperations;
35 -import org.onosproject.net.flow.FlowRuleBatchOperation; 38 +import org.onosproject.net.flow.FlowRuleOperationsContext;
36 import org.onosproject.net.flow.FlowRuleService; 39 import org.onosproject.net.flow.FlowRuleService;
37 import org.onosproject.net.flow.TrafficSelector; 40 import org.onosproject.net.flow.TrafficSelector;
38 import org.onosproject.net.flow.TrafficTreatment; 41 import org.onosproject.net.flow.TrafficTreatment;
39 -import org.onlab.packet.MacAddress;
40 42
41 import java.util.ArrayList; 43 import java.util.ArrayList;
42 -import java.util.Set; 44 +import java.util.concurrent.CountDownLatch;
43 -import java.util.concurrent.ExecutionException; 45 +import java.util.concurrent.TimeUnit;
44 -import java.util.concurrent.Future;
45 46
46 /** 47 /**
47 * Installs many many flows. 48 * Installs many many flows.
...@@ -50,6 +51,8 @@ import java.util.concurrent.Future; ...@@ -50,6 +51,8 @@ import java.util.concurrent.Future;
50 description = "Installs a number of test flow rules - for testing only") 51 description = "Installs a number of test flow rules - for testing only")
51 public class AddFlowsCommand extends AbstractShellCommand { 52 public class AddFlowsCommand extends AbstractShellCommand {
52 53
54 + private CountDownLatch latch;
55 +
53 @Argument(index = 0, name = "flowPerDevice", description = "Number of flows to add per device", 56 @Argument(index = 0, name = "flowPerDevice", description = "Number of flows to add per device",
54 required = true, multiValued = false) 57 required = true, multiValued = false)
55 String flows = null; 58 String flows = null;
...@@ -63,6 +66,9 @@ public class AddFlowsCommand extends AbstractShellCommand { ...@@ -63,6 +66,9 @@ public class AddFlowsCommand extends AbstractShellCommand {
63 66
64 FlowRuleService flowService = get(FlowRuleService.class); 67 FlowRuleService flowService = get(FlowRuleService.class);
65 DeviceService deviceService = get(DeviceService.class); 68 DeviceService deviceService = get(DeviceService.class);
69 + CoreService coreService = get(CoreService.class);
70 +
71 + ApplicationId appId = coreService.registerApplication("onos.test.flow.installer");
66 72
67 int flowsPerDevice = Integer.parseInt(flows); 73 int flowsPerDevice = Integer.parseInt(flows);
68 int num = Integer.parseInt(numOfRuns); 74 int num = Integer.parseInt(numOfRuns);
...@@ -70,49 +76,73 @@ public class AddFlowsCommand extends AbstractShellCommand { ...@@ -70,49 +76,73 @@ public class AddFlowsCommand extends AbstractShellCommand {
70 ArrayList<Long> results = Lists.newArrayList(); 76 ArrayList<Long> results = Lists.newArrayList();
71 Iterable<Device> devices = deviceService.getDevices(); 77 Iterable<Device> devices = deviceService.getDevices();
72 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 78 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
73 - .setOutput(PortNumber.portNumber(1)).build(); 79 + .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build();
74 TrafficSelector.Builder sbuilder; 80 TrafficSelector.Builder sbuilder;
75 - Set<FlowRuleBatchEntry> rules = Sets.newHashSet(); 81 + FlowRuleOperations.Builder rules = FlowRuleOperations.builder();
76 - Set<FlowRuleBatchEntry> remove = Sets.newHashSet(); 82 + FlowRuleOperations.Builder remove = FlowRuleOperations.builder();
83 +
77 for (Device d : devices) { 84 for (Device d : devices) {
78 for (int i = 0; i < flowsPerDevice; i++) { 85 for (int i = 0; i < flowsPerDevice; i++) {
79 sbuilder = DefaultTrafficSelector.builder(); 86 sbuilder = DefaultTrafficSelector.builder();
80 - sbuilder.matchEthSrc(MacAddress.valueOf(i)) 87 +
81 - .matchEthDst(MacAddress.valueOf(Integer.MAX_VALUE - i)); 88 + sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i))
82 - rules.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.ADD, 89 + .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt()));
83 - new DefaultFlowRule(d.id(), sbuilder.build(), treatment, 90 +
84 - 100, (long) 0, 10, false))); 91 +
85 - remove.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.REMOVE, 92 + int randomPriority = RandomUtils.nextInt();
86 - new DefaultFlowRule(d.id(), sbuilder.build(), treatment, 93 + rules.add(new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
87 - 100, (long) 0, 10, false))); 94 + randomPriority, appId, 10, false));
95 + remove.remove(new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
96 + randomPriority, appId, 10, false));
88 97
89 } 98 }
90 } 99 }
91 - boolean isSuccess = true; 100 +
92 for (int i = 0; i < num; i++) { 101 for (int i = 0; i < num; i++) {
93 - long startTime = System.currentTimeMillis(); 102 +
94 - Future<CompletedBatchOperation> op = flowService.applyBatch( 103 + latch = new CountDownLatch(2);
95 - new FlowRuleBatchOperation(rules)); 104 + flowService.apply(rules.build(new FlowRuleOperationsContext() {
105 +
106 + private final Stopwatch timer = Stopwatch.createStarted();
107 +
108 + @Override
109 + public void onSuccess(FlowRuleOperations ops) {
110 +
111 + timer.stop();
112 + results.add(timer.elapsed(TimeUnit.MILLISECONDS));
113 + if (results.size() == num) {
114 + if (outputJson()) {
115 + print("%s", json(new ObjectMapper(), true, results));
116 + } else {
117 + printTime(true, results);
118 + }
119 + }
120 + latch.countDown();
121 + }
122 + }));
123 +
124 +
125 + flowService.apply(remove.build(new FlowRuleOperationsContext() {
126 + @Override
127 + public void onSuccess(FlowRuleOperations ops) {
128 + latch.countDown();
129 + }
130 + }));
96 try { 131 try {
97 - isSuccess &= op.get().isSuccess(); 132 + latch.await();
98 - } catch (InterruptedException | ExecutionException e) { 133 + } catch (InterruptedException e) {
99 e.printStackTrace(); 134 e.printStackTrace();
100 } 135 }
101 - long endTime = System.currentTimeMillis(); 136 +
102 - results.add(endTime - startTime);
103 - flowService.applyBatch(
104 - new FlowRuleBatchOperation(remove));
105 - }
106 - if (outputJson()) {
107 - print("%s", json(new ObjectMapper(), isSuccess, results));
108 - } else {
109 - printTime(isSuccess, results);
110 } 137 }
111 138
112 139
113 140
141 +
114 } 142 }
115 143
144 +
145 +
116 private Object json(ObjectMapper mapper, boolean isSuccess, ArrayList<Long> elapsed) { 146 private Object json(ObjectMapper mapper, boolean isSuccess, ArrayList<Long> elapsed) {
117 ObjectNode result = mapper.createObjectNode(); 147 ObjectNode result = mapper.createObjectNode();
118 result.put("Success", isSuccess); 148 result.put("Success", isSuccess);
......
...@@ -21,6 +21,7 @@ import java.util.Set; ...@@ -21,6 +21,7 @@ import java.util.Set;
21 21
22 import com.google.common.base.MoreObjects; 22 import com.google.common.base.MoreObjects;
23 import com.google.common.collect.ImmutableSet; 23 import com.google.common.collect.ImmutableSet;
24 +import org.onosproject.net.DeviceId;
24 25
25 /** 26 /**
26 * Representation of a completed flow rule batch operation. 27 * Representation of a completed flow rule batch operation.
...@@ -30,19 +31,22 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { ...@@ -30,19 +31,22 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
30 private final boolean success; 31 private final boolean success;
31 private final Set<FlowRule> failures; 32 private final Set<FlowRule> failures;
32 private final Set<Long> failedIds; 33 private final Set<Long> failedIds;
34 + private final DeviceId deviceId;
33 35
34 /** 36 /**
35 * Creates a new batch completion result. 37 * Creates a new batch completion result.
36 * 38 *
37 - * @param success indicates whether the completion is successful. 39 + * @param success indicates whether the completion is successful
38 * @param failures set of any failures encountered 40 * @param failures set of any failures encountered
39 * @param failedIds (optional) set of failed operation ids 41 * @param failedIds (optional) set of failed operation ids
42 + * @param deviceId the device this operation completed for
40 */ 43 */
41 public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures, 44 public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures,
42 - Set<Long> failedIds) { 45 + Set<Long> failedIds, DeviceId deviceId) {
43 this.success = success; 46 this.success = success;
44 this.failures = ImmutableSet.copyOf(failures); 47 this.failures = ImmutableSet.copyOf(failures);
45 this.failedIds = ImmutableSet.copyOf(failedIds); 48 this.failedIds = ImmutableSet.copyOf(failedIds);
49 + this.deviceId = deviceId;
46 } 50 }
47 51
48 /** 52 /**
...@@ -51,10 +55,12 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { ...@@ -51,10 +55,12 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
51 * @param success indicates whether the completion is successful. 55 * @param success indicates whether the completion is successful.
52 * @param failures set of any failures encountered 56 * @param failures set of any failures encountered
53 */ 57 */
54 - public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures) { 58 + public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures,
59 + DeviceId deviceId) {
55 this.success = success; 60 this.success = success;
56 this.failures = ImmutableSet.copyOf(failures); 61 this.failures = ImmutableSet.copyOf(failures);
57 this.failedIds = Collections.emptySet(); 62 this.failedIds = Collections.emptySet();
63 + this.deviceId = deviceId;
58 } 64 }
59 65
60 66
...@@ -73,12 +79,17 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { ...@@ -73,12 +79,17 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
73 return failedIds; 79 return failedIds;
74 } 80 }
75 81
82 + public DeviceId deviceId() {
83 + return this.deviceId;
84 + }
85 +
76 @Override 86 @Override
77 public String toString() { 87 public String toString() {
78 return MoreObjects.toStringHelper(getClass()) 88 return MoreObjects.toStringHelper(getClass())
79 .add("success?", success) 89 .add("success?", success)
80 .add("failedItems", failures) 90 .add("failedItems", failures)
81 .add("failedIds", failedIds) 91 .add("failedIds", failedIds)
92 + .add("deviceId", deviceId)
82 .toString(); 93 .toString();
83 } 94 }
84 } 95 }
......
...@@ -16,12 +16,14 @@ ...@@ -16,12 +16,14 @@
16 package org.onosproject.net.flow; 16 package org.onosproject.net.flow;
17 17
18 import org.onosproject.event.AbstractEvent; 18 import org.onosproject.event.AbstractEvent;
19 +import org.onosproject.net.DeviceId;
19 20
20 /** 21 /**
21 * Describes flow rule batch event. 22 * Describes flow rule batch event.
22 */ 23 */
23 public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> { 24 public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> {
24 25
26 +
25 /** 27 /**
26 * Type of flow rule events. 28 * Type of flow rule events.
27 */ 29 */
...@@ -42,14 +44,17 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T ...@@ -42,14 +44,17 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T
42 } 44 }
43 45
44 private final CompletedBatchOperation result; 46 private final CompletedBatchOperation result;
47 + private final DeviceId deviceId;
45 48
46 /** 49 /**
47 * Constructs a new FlowRuleBatchEvent. 50 * Constructs a new FlowRuleBatchEvent.
48 - * @param request batch operation request. 51 + *
52 + * @param request batch operation request
53 + * @param deviceId the device this batch will be processed on
49 * @return event. 54 * @return event.
50 */ 55 */
51 - public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request) { 56 + public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request, DeviceId deviceId) {
52 - FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, null); 57 + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, deviceId);
53 return event; 58 return event;
54 } 59 }
55 60
...@@ -73,13 +78,36 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T ...@@ -73,13 +78,36 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T
73 } 78 }
74 79
75 /** 80 /**
81 + * Returns the deviceId for this batch.
82 + * @return device id
83 + */
84 + public DeviceId deviceId() {
85 + return deviceId;
86 + }
87 +
88 + /**
76 * Creates an event of a given type and for the specified flow rule batch. 89 * Creates an event of a given type and for the specified flow rule batch.
77 * 90 *
78 * @param type flow rule batch event type 91 * @param type flow rule batch event type
79 - * @param batch event flow rule batch subject 92 + * @param request event flow rule batch subject
93 + * @param result the result of the batch operation
80 */ 94 */
81 private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) { 95 private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) {
82 super(type, request); 96 super(type, request);
83 this.result = result; 97 this.result = result;
98 + this.deviceId = result.deviceId();
99 + }
100 +
101 + /**
102 + * Creates an event of a given type and for the specified flow rule batch.
103 + *
104 + * @param type flow rule batch event type
105 + * @param request event flow rule batch subject
106 + * @param deviceId the device id for this batch
107 + */
108 + private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, DeviceId deviceId) {
109 + super(type, request);
110 + this.result = null;
111 + this.deviceId = deviceId;
84 } 112 }
85 } 113 }
......
...@@ -15,12 +15,37 @@ ...@@ -15,12 +15,37 @@
15 */ 15 */
16 package org.onosproject.net.flow; 16 package org.onosproject.net.flow;
17 17
18 +import org.onosproject.net.DeviceId;
19 +
18 import java.util.Collection; 20 import java.util.Collection;
19 21
22 +/**
23 + * Class used with the flow subsystem to process per device
24 + * batches.
25 + */
20 public class FlowRuleBatchOperation 26 public class FlowRuleBatchOperation
21 extends BatchOperation<FlowRuleBatchEntry> { 27 extends BatchOperation<FlowRuleBatchEntry> {
22 28
23 - public FlowRuleBatchOperation(Collection<FlowRuleBatchEntry> operations) { 29 + /**
30 + * This id is used to cary to id of the original
31 + * FlowOperations and track where this batch operation
32 + * came from. The id is unique cluster wide.
33 + */
34 + private final long id;
35 + private final DeviceId deviceId;
36 +
37 + public FlowRuleBatchOperation(Collection<FlowRuleBatchEntry> operations,
38 + DeviceId deviceId, long flowOperationId) {
24 super(operations); 39 super(operations);
40 + this.id = flowOperationId;
41 + this.deviceId = deviceId;
42 + }
43 +
44 + public DeviceId deviceId() {
45 + return this.deviceId;
46 + }
47 +
48 + public long id() {
49 + return id;
25 } 50 }
26 } 51 }
......
...@@ -15,59 +15,43 @@ ...@@ -15,59 +15,43 @@
15 */ 15 */
16 package org.onosproject.net.flow; 16 package org.onosproject.net.flow;
17 17
18 +import com.google.common.collect.Lists;
19 +import org.onosproject.net.DeviceId;
20 +
18 import java.util.Collections; 21 import java.util.Collections;
19 import java.util.List; 22 import java.util.List;
23 +import java.util.Set;
20 24
21 -import com.google.common.base.Function; 25 +public class FlowRuleBatchRequest {
22 -import com.google.common.collect.FluentIterable;
23 -
24 -
25 26
26 -import com.google.common.collect.Lists; 27 + /**
28 + * This id is used to cary to id of the original
29 + * FlowOperations and track where this batch operation
30 + * came from. The id is unique cluster wide.
31 + */
32 + private final long batchId;
27 33
28 -public class FlowRuleBatchRequest { 34 + private final Set<FlowRuleBatchEntry> ops;
29 35
30 - private final int batchId;
31 - private final List<FlowRuleBatchEntry> toAdd;
32 - private final List<FlowRuleBatchEntry> toRemove;
33 36
34 - public FlowRuleBatchRequest(int batchId, List<FlowRuleBatchEntry> toAdd, 37 + public FlowRuleBatchRequest(long batchId, Set<FlowRuleBatchEntry> ops) {
35 - List<FlowRuleBatchEntry> toRemove) {
36 this.batchId = batchId; 38 this.batchId = batchId;
37 - this.toAdd = Collections.unmodifiableList(toAdd); 39 + this.ops = Collections.unmodifiableSet(ops);
38 - this.toRemove = Collections.unmodifiableList(toRemove);
39 - }
40 40
41 - public List<FlowRule> toAdd() {
42 - return FluentIterable.from(toAdd).transform(
43 - new Function<FlowRuleBatchEntry, FlowRule>() {
44 41
45 - @Override
46 - public FlowRule apply(FlowRuleBatchEntry input) {
47 - return input.target();
48 } 42 }
49 - }).toList();
50 - }
51 -
52 - public List<FlowRule> toRemove() {
53 - return FluentIterable.from(toRemove).transform(
54 - new Function<FlowRuleBatchEntry, FlowRule>() {
55 43
56 - @Override 44 + public Set<FlowRuleBatchEntry> ops() {
57 - public FlowRule apply(FlowRuleBatchEntry input) { 45 + return ops;
58 - return input.target();
59 - }
60 - }).toList();
61 } 46 }
62 47
63 - public FlowRuleBatchOperation asBatchOperation() { 48 + public FlowRuleBatchOperation asBatchOperation(DeviceId deviceId) {
64 List<FlowRuleBatchEntry> entries = Lists.newArrayList(); 49 List<FlowRuleBatchEntry> entries = Lists.newArrayList();
65 - entries.addAll(toAdd); 50 + entries.addAll(ops);
66 - entries.addAll(toRemove); 51 + return new FlowRuleBatchOperation(entries, deviceId, batchId);
67 - return new FlowRuleBatchOperation(entries);
68 } 52 }
69 53
70 - public int batchId() { 54 + public long batchId() {
71 return batchId; 55 return batchId;
72 } 56 }
73 } 57 }
......
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.net.flow;
17 +
18 +import com.google.common.base.MoreObjects;
19 +
20 +/**
21 + * Representation of an operation on a flow rule table.
22 + */
23 +public class FlowRuleOperation {
24 +
25 + /**
26 + * Type of flow table operations.
27 + */
28 + public enum Type {
29 + ADD,
30 + MODIFY,
31 + REMOVE
32 + }
33 +
34 + private final FlowRule rule;
35 + private final Type type;
36 +
37 + public FlowRuleOperation(FlowRule rule, Type type) {
38 + this.rule = rule;
39 + this.type = type;
40 + }
41 +
42 + /**
43 + * Returns the type of operation.
44 + *
45 + * @return type
46 + */
47 + public Type type() {
48 + return type;
49 + }
50 +
51 + /**
52 + * Returns the flow rule.
53 + *
54 + * @return flow rule
55 + */
56 + public FlowRule rule() {
57 + return rule;
58 + }
59 +
60 + @Override
61 + public String toString() {
62 + return MoreObjects.toStringHelper(this)
63 + .add("rule", rule)
64 + .add("type", type)
65 + .toString();
66 + }
67 +}
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.net.flow;
17 +
18 +import com.google.common.base.MoreObjects;
19 +import com.google.common.collect.ImmutableList;
20 +import com.google.common.collect.ImmutableSet;
21 +import com.google.common.collect.Lists;
22 +
23 +import java.util.List;
24 +import java.util.Set;
25 +
26 +import static org.onosproject.net.flow.FlowRuleOperation.Type.*;
27 +
28 +/**
29 + * A batch of flow rule operations that are broken into stages.
30 + * TODO move this up to parent's package
31 + */
32 +public class FlowRuleOperations {
33 +
34 + private final List<Set<FlowRuleOperation>> stages;
35 + private final FlowRuleOperationsContext callback; // TODO consider Optional
36 +
37 + private FlowRuleOperations(List<Set<FlowRuleOperation>> stages,
38 + FlowRuleOperationsContext cb) {
39 + this.stages = stages;
40 + this.callback = cb;
41 + }
42 +
43 + // kryo-constructor
44 + protected FlowRuleOperations() {
45 + this.stages = Lists.newArrayList();
46 + this.callback = null;
47 + }
48 +
49 + /**
50 + * Returns the flow rule operations as sets of stages that should be
51 + * executed sequentially.
52 + *
53 + * @return flow rule stages
54 + */
55 + public List<Set<FlowRuleOperation>> stages() {
56 + return stages;
57 + }
58 +
59 + /**
60 + * Returns the callback for this batch of operations.
61 + *
62 + * @return callback
63 + */
64 + public FlowRuleOperationsContext callback() {
65 + return callback;
66 + }
67 +
68 + /**
69 + * Returns a new builder.
70 + *
71 + * @return new builder
72 + */
73 + public static Builder builder() {
74 + return new Builder();
75 + }
76 +
77 + @Override
78 + public String toString() {
79 + return MoreObjects.toStringHelper(this)
80 + .add("stages", stages)
81 + .toString();
82 + }
83 +
84 + /**
85 + * A builder for constructing flow rule operations.
86 + */
87 + public static final class Builder {
88 +
89 + private final ImmutableList.Builder<Set<FlowRuleOperation>> listBuilder = ImmutableList.builder();
90 + private ImmutableSet.Builder<FlowRuleOperation> currentStage = ImmutableSet.builder();
91 +
92 + // prevent use of the default constructor outside of this file; use the above method
93 + private Builder() {}
94 +
95 + /**
96 + * Appends a flow rule add to the current stage.
97 + *
98 + * @param flowRule flow rule
99 + * @return this
100 + */
101 + public Builder add(FlowRule flowRule) {
102 + currentStage.add(new FlowRuleOperation(flowRule, ADD));
103 + return this;
104 + }
105 +
106 + /**
107 + * Appends a flow rule modify to the current stage.
108 + *
109 + * @param flowRule flow rule
110 + * @return this
111 + */
112 + public Builder modify(FlowRule flowRule) {
113 + currentStage.add(new FlowRuleOperation(flowRule, MODIFY));
114 + return this;
115 + }
116 +
117 + /**
118 + * Appends a flow rule remove to the current stage.
119 + *
120 + * @param flowRule flow rule
121 + * @return this
122 + */
123 + // FIXME this is confusing, consider renaming
124 + public Builder remove(FlowRule flowRule) {
125 + currentStage.add(new FlowRuleOperation(flowRule, REMOVE));
126 + return this;
127 + }
128 +
129 + /**
130 + * Closes the current stage.
131 + */
132 + private void closeStage() {
133 + ImmutableSet<FlowRuleOperation> stage = currentStage.build();
134 + if (!stage.isEmpty()) {
135 + listBuilder.add(stage);
136 + }
137 + }
138 +
139 + /**
140 + * Closes the current stage and starts a new one.
141 + *
142 + * @return this
143 + */
144 + public Builder newStage() {
145 + closeStage();
146 + currentStage = ImmutableSet.builder();
147 + return this;
148 + }
149 +
150 + /**
151 + * Builds the immutable flow rule operations.
152 + *
153 + * @return flow rule operations
154 + */
155 + public FlowRuleOperations build() {
156 + return build(null);
157 + }
158 +
159 + /**
160 + * Builds the immutable flow rule operations.
161 + *
162 + * @param cb the callback to call when this operation completes
163 + * @return flow rule operations
164 + */
165 + public FlowRuleOperations build(FlowRuleOperationsContext cb) {
166 + closeStage();
167 + return new FlowRuleOperations(listBuilder.build(), cb);
168 + }
169 + }
170 +}
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.net.flow;
17 +
18 +/**
19 + * The context of a flow rule operations that will become the subject of
20 + * the notification.
21 + *
22 + * Implementations of this class must be serializable.
23 + */
24 +public interface FlowRuleOperationsContext {
25 + // TODO we might also want to execute a method on behalf of the app
26 + default void onSuccess(FlowRuleOperations ops){}
27 + default void onError(FlowRuleOperations ops){}
28 +}
...@@ -18,8 +18,6 @@ package org.onosproject.net.flow; ...@@ -18,8 +18,6 @@ package org.onosproject.net.flow;
18 import org.onosproject.core.ApplicationId; 18 import org.onosproject.core.ApplicationId;
19 import org.onosproject.net.provider.Provider; 19 import org.onosproject.net.provider.Provider;
20 20
21 -import java.util.concurrent.Future;
22 -
23 /** 21 /**
24 * Abstraction of a flow rule provider. 22 * Abstraction of a flow rule provider.
25 */ 23 */
...@@ -56,8 +54,7 @@ public interface FlowRuleProvider extends Provider { ...@@ -56,8 +54,7 @@ public interface FlowRuleProvider extends Provider {
56 * Installs a batch of flow rules. Each flowrule is associated to an 54 * Installs a batch of flow rules. Each flowrule is associated to an
57 * operation which results in either addition, removal or modification. 55 * operation which results in either addition, removal or modification.
58 * @param batch a batch of flow rules 56 * @param batch a batch of flow rules
59 - * @return a future indicating the status of this execution
60 */ 57 */
61 - Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); 58 + void executeBatch(FlowRuleBatchOperation batch);
62 59
63 } 60 }
......
...@@ -40,4 +40,13 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide ...@@ -40,4 +40,13 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide
40 */ 40 */
41 void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries); 41 void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries);
42 42
43 + /**
44 + * Indicates to the core that the requested batch operation has
45 + * been completed.
46 + *
47 + * @param batchId the batch which was processed
48 + * @param operation the resulting outcome of the operation
49 + */
50 + void batchOperationCompleted(long batchId, CompletedBatchOperation operation);
51 +
43 } 52 }
......
...@@ -15,11 +15,11 @@ ...@@ -15,11 +15,11 @@
15 */ 15 */
16 package org.onosproject.net.flow; 16 package org.onosproject.net.flow;
17 17
18 -import java.util.concurrent.Future;
19 -
20 import org.onosproject.core.ApplicationId; 18 import org.onosproject.core.ApplicationId;
21 import org.onosproject.net.DeviceId; 19 import org.onosproject.net.DeviceId;
22 20
21 +import java.util.concurrent.Future;
22 +
23 /** 23 /**
24 * Service for injecting flow rules into the environment and for obtaining 24 * Service for injecting flow rules into the environment and for obtaining
25 * information about flow rules already in the environment. This implements 25 * information about flow rules already in the environment. This implements
...@@ -30,6 +30,11 @@ import org.onosproject.net.DeviceId; ...@@ -30,6 +30,11 @@ import org.onosproject.net.DeviceId;
30 public interface FlowRuleService { 30 public interface FlowRuleService {
31 31
32 /** 32 /**
33 + * The topic used for obtaining globally unique ids.
34 + */
35 + static String FLOW_OP_TOPIC = "flow-ops-ids";
36 +
37 + /**
33 * Returns the number of flow rules in the system. 38 * Returns the number of flow rules in the system.
34 * 39 *
35 * @return flow rule count 40 * @return flow rule count
...@@ -96,11 +101,20 @@ public interface FlowRuleService { ...@@ -96,11 +101,20 @@ public interface FlowRuleService {
96 * Applies a batch operation of FlowRules. 101 * Applies a batch operation of FlowRules.
97 * 102 *
98 * @param batch batch operation to apply 103 * @param batch batch operation to apply
99 - * @return future indicating the state of the batch operation 104 + * @return future indicating the state of the batch operation, due to the
105 + * deprecation of this api the future will immediately return
100 */ 106 */
107 + @Deprecated
101 Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch); 108 Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch);
102 109
103 /** 110 /**
111 + * Applies a batch operation of FlowRules.
112 + *
113 + * @param ops batch operation to apply
114 + */
115 + void apply(FlowRuleOperations ops);
116 +
117 + /**
104 * Adds the specified flow rule listener. 118 * Adds the specified flow rule listener.
105 * 119 *
106 * @param listener flow rule listener 120 * @param listener flow rule listener
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
15 */ 15 */
16 package org.onosproject.net.flow; 16 package org.onosproject.net.flow;
17 17
18 -import java.util.concurrent.Future;
19 -
20 import org.onosproject.net.DeviceId; 18 import org.onosproject.net.DeviceId;
21 import org.onosproject.store.Store; 19 import org.onosproject.store.Store;
22 20
...@@ -54,6 +52,7 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe ...@@ -54,6 +52,7 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
54 * 52 *
55 * @param rule the flow rule to add 53 * @param rule the flow rule to add
56 */ 54 */
55 + @Deprecated
57 void storeFlowRule(FlowRule rule); 56 void storeFlowRule(FlowRule rule);
58 57
59 /** 58 /**
...@@ -61,10 +60,9 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe ...@@ -61,10 +60,9 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
61 * 60 *
62 * @param batchOperation batch of flow rules. 61 * @param batchOperation batch of flow rules.
63 * A batch can contain flow rules for a single device only. 62 * A batch can contain flow rules for a single device only.
64 - * @return Future response indicating success/failure of the batch operation 63 + *
65 - * all the way down to the device.
66 */ 64 */
67 - Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation batchOperation); 65 + void storeBatch(FlowRuleBatchOperation batchOperation);
68 66
69 /** 67 /**
70 * Invoked on the completion of a storeBatch operation. 68 * Invoked on the completion of a storeBatch operation.
......
...@@ -46,10 +46,10 @@ public class FlowRuleBatchOperationTest { ...@@ -46,10 +46,10 @@ public class FlowRuleBatchOperationTest {
46 final LinkedList<FlowRuleBatchEntry> ops3 = new LinkedList<>(); 46 final LinkedList<FlowRuleBatchEntry> ops3 = new LinkedList<>();
47 ops3.add(entry3); 47 ops3.add(entry3);
48 48
49 - final FlowRuleBatchOperation operation1 = new FlowRuleBatchOperation(ops1); 49 + final FlowRuleBatchOperation operation1 = new FlowRuleBatchOperation(ops1, null, 0);
50 - final FlowRuleBatchOperation sameAsOperation1 = new FlowRuleBatchOperation(ops1); 50 + final FlowRuleBatchOperation sameAsOperation1 = new FlowRuleBatchOperation(ops1, null, 0);
51 - final FlowRuleBatchOperation operation2 = new FlowRuleBatchOperation(ops2); 51 + final FlowRuleBatchOperation operation2 = new FlowRuleBatchOperation(ops2, null, 0);
52 - final FlowRuleBatchOperation operation3 = new FlowRuleBatchOperation(ops3); 52 + final FlowRuleBatchOperation operation3 = new FlowRuleBatchOperation(ops3, null, 0);
53 53
54 new EqualsTester() 54 new EqualsTester()
55 .addEqualityGroup(operation1, sameAsOperation1) 55 .addEqualityGroup(operation1, sameAsOperation1)
......
...@@ -15,17 +15,18 @@ ...@@ -15,17 +15,18 @@
15 */ 15 */
16 package org.onosproject.net.flow; 16 package org.onosproject.net.flow;
17 17
18 -import java.util.LinkedList;
19 -import java.util.List;
20 -
21 import org.junit.Test; 18 import org.junit.Test;
22 import org.onosproject.net.intent.IntentTestsMocks; 19 import org.onosproject.net.intent.IntentTestsMocks;
23 20
24 -import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*; 21 +import java.util.HashSet;
22 +import java.util.List;
23 +import java.util.Set;
25 24
26 import static org.hamcrest.MatcherAssert.assertThat; 25 import static org.hamcrest.MatcherAssert.assertThat;
27 import static org.hamcrest.Matchers.hasSize; 26 import static org.hamcrest.Matchers.hasSize;
28 import static org.hamcrest.Matchers.is; 27 import static org.hamcrest.Matchers.is;
28 +import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.ADD;
29 +import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.REMOVE;
29 30
30 /** 31 /**
31 * Unit tests for the FlowRuleBatchRequest class. 32 * Unit tests for the FlowRuleBatchRequest class.
...@@ -40,22 +41,19 @@ public class FlowRuleBatchRequestTest { ...@@ -40,22 +41,19 @@ public class FlowRuleBatchRequestTest {
40 public void testConstruction() { 41 public void testConstruction() {
41 final FlowRule rule1 = new IntentTestsMocks.MockFlowRule(1); 42 final FlowRule rule1 = new IntentTestsMocks.MockFlowRule(1);
42 final FlowRule rule2 = new IntentTestsMocks.MockFlowRule(2); 43 final FlowRule rule2 = new IntentTestsMocks.MockFlowRule(2);
43 - final List<FlowRuleBatchEntry> toAdd = new LinkedList<>(); 44 + final Set<FlowRuleBatchEntry> batch = new HashSet<>();
44 - toAdd.add(new FlowRuleBatchEntry(ADD, rule1)); 45 + batch.add(new FlowRuleBatchEntry(ADD, rule1));
45 - final List<FlowRuleBatchEntry> toRemove = new LinkedList<>(); 46 +
46 - toRemove.add(new FlowRuleBatchEntry(REMOVE, rule2)); 47 + batch.add(new FlowRuleBatchEntry(REMOVE, rule2));
47 48
48 49
49 final FlowRuleBatchRequest request = 50 final FlowRuleBatchRequest request =
50 - new FlowRuleBatchRequest(1, toAdd, toRemove); 51 + new FlowRuleBatchRequest(1, batch);
51 52
52 - assertThat(request.toAdd(), hasSize(1)); 53 + assertThat(request.ops(), hasSize(2));
53 - assertThat(request.toAdd().get(0), is(rule1)); 54 + assertThat(request.batchId(), is(1L));
54 - assertThat(request.toRemove(), hasSize(1));
55 - assertThat(request.toRemove().get(0), is(rule2));
56 - assertThat(request.batchId(), is(1));
57 55
58 - final FlowRuleBatchOperation op = request.asBatchOperation(); 56 + final FlowRuleBatchOperation op = request.asBatchOperation(rule1.deviceId());
59 assertThat(op.size(), is(2)); 57 assertThat(op.size(), is(2));
60 58
61 final List<FlowRuleBatchEntry> ops = op.getOperations(); 59 final List<FlowRuleBatchEntry> ops = op.getOperations();
......
...@@ -66,6 +66,11 @@ public class FlowRuleServiceAdapter implements FlowRuleService { ...@@ -66,6 +66,11 @@ public class FlowRuleServiceAdapter implements FlowRuleService {
66 } 66 }
67 67
68 @Override 68 @Override
69 + public void apply(FlowRuleOperations ops) {
70 +
71 + }
72 +
73 + @Override
69 public void addListener(FlowRuleListener listener) { 74 public void addListener(FlowRuleListener listener) {
70 75
71 } 76 }
......
...@@ -21,7 +21,7 @@ import com.google.common.collect.Lists; ...@@ -21,7 +21,7 @@ import com.google.common.collect.Lists;
21 import com.google.common.collect.Maps; 21 import com.google.common.collect.Maps;
22 import com.google.common.collect.Multimap; 22 import com.google.common.collect.Multimap;
23 import com.google.common.collect.Sets; 23 import com.google.common.collect.Sets;
24 - 24 +import com.google.common.util.concurrent.Futures;
25 import org.apache.felix.scr.annotations.Activate; 25 import org.apache.felix.scr.annotations.Activate;
26 import org.apache.felix.scr.annotations.Component; 26 import org.apache.felix.scr.annotations.Component;
27 import org.apache.felix.scr.annotations.Deactivate; 27 import org.apache.felix.scr.annotations.Deactivate;
...@@ -29,22 +29,25 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -29,22 +29,25 @@ import org.apache.felix.scr.annotations.Reference;
29 import org.apache.felix.scr.annotations.ReferenceCardinality; 29 import org.apache.felix.scr.annotations.ReferenceCardinality;
30 import org.apache.felix.scr.annotations.Service; 30 import org.apache.felix.scr.annotations.Service;
31 import org.onosproject.core.ApplicationId; 31 import org.onosproject.core.ApplicationId;
32 +import org.onosproject.core.CoreService;
33 +import org.onosproject.core.IdGenerator;
32 import org.onosproject.event.AbstractListenerRegistry; 34 import org.onosproject.event.AbstractListenerRegistry;
33 import org.onosproject.event.EventDeliveryService; 35 import org.onosproject.event.EventDeliveryService;
34 import org.onosproject.net.Device; 36 import org.onosproject.net.Device;
35 import org.onosproject.net.DeviceId; 37 import org.onosproject.net.DeviceId;
36 import org.onosproject.net.device.DeviceService; 38 import org.onosproject.net.device.DeviceService;
37 import org.onosproject.net.flow.CompletedBatchOperation; 39 import org.onosproject.net.flow.CompletedBatchOperation;
38 -import org.onosproject.net.flow.DefaultFlowEntry;
39 import org.onosproject.net.flow.FlowEntry; 40 import org.onosproject.net.flow.FlowEntry;
40 import org.onosproject.net.flow.FlowRule; 41 import org.onosproject.net.flow.FlowRule;
41 import org.onosproject.net.flow.FlowRuleBatchEntry; 42 import org.onosproject.net.flow.FlowRuleBatchEntry;
42 -import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
43 import org.onosproject.net.flow.FlowRuleBatchEvent; 43 import org.onosproject.net.flow.FlowRuleBatchEvent;
44 import org.onosproject.net.flow.FlowRuleBatchOperation; 44 import org.onosproject.net.flow.FlowRuleBatchOperation;
45 import org.onosproject.net.flow.FlowRuleBatchRequest; 45 import org.onosproject.net.flow.FlowRuleBatchRequest;
46 import org.onosproject.net.flow.FlowRuleEvent; 46 import org.onosproject.net.flow.FlowRuleEvent;
47 import org.onosproject.net.flow.FlowRuleListener; 47 import org.onosproject.net.flow.FlowRuleListener;
48 +import org.onosproject.net.flow.FlowRuleOperation;
49 +import org.onosproject.net.flow.FlowRuleOperations;
50 +import org.onosproject.net.flow.FlowRuleOperationsContext;
48 import org.onosproject.net.flow.FlowRuleProvider; 51 import org.onosproject.net.flow.FlowRuleProvider;
49 import org.onosproject.net.flow.FlowRuleProviderRegistry; 52 import org.onosproject.net.flow.FlowRuleProviderRegistry;
50 import org.onosproject.net.flow.FlowRuleProviderService; 53 import org.onosproject.net.flow.FlowRuleProviderService;
...@@ -55,18 +58,16 @@ import org.onosproject.net.provider.AbstractProviderRegistry; ...@@ -55,18 +58,16 @@ import org.onosproject.net.provider.AbstractProviderRegistry;
55 import org.onosproject.net.provider.AbstractProviderService; 58 import org.onosproject.net.provider.AbstractProviderService;
56 import org.slf4j.Logger; 59 import org.slf4j.Logger;
57 60
58 -import java.util.HashSet; 61 +import java.util.Collections;
59 import java.util.List; 62 import java.util.List;
60 import java.util.Map; 63 import java.util.Map;
61 import java.util.Set; 64 import java.util.Set;
62 -import java.util.concurrent.CancellationException; 65 +import java.util.concurrent.ConcurrentHashMap;
63 -import java.util.concurrent.ExecutionException;
64 import java.util.concurrent.ExecutorService; 66 import java.util.concurrent.ExecutorService;
65 import java.util.concurrent.Executors; 67 import java.util.concurrent.Executors;
66 import java.util.concurrent.Future; 68 import java.util.concurrent.Future;
67 -import java.util.concurrent.TimeUnit; 69 +import java.util.concurrent.atomic.AtomicBoolean;
68 -import java.util.concurrent.TimeoutException; 70 +
69 -import java.util.concurrent.atomic.AtomicReference;
70 import static com.google.common.base.Preconditions.checkNotNull; 71 import static com.google.common.base.Preconditions.checkNotNull;
71 import static org.onlab.util.Tools.namedThreads; 72 import static org.onlab.util.Tools.namedThreads;
72 import static org.slf4j.LoggerFactory.getLogger; 73 import static org.slf4j.LoggerFactory.getLogger;
...@@ -90,7 +91,16 @@ public class FlowRuleManager ...@@ -90,7 +91,16 @@ public class FlowRuleManager
90 91
91 private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate(); 92 private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
92 93
93 - private ExecutorService futureService; 94 + protected ExecutorService deviceInstallers =
95 + Executors.newCachedThreadPool(namedThreads("onos-device-installer-%d"));
96 +
97 + protected ExecutorService operationsService =
98 + Executors.newFixedThreadPool(32, namedThreads("onos-flowservice-operations-%d"));
99 +
100 + private IdGenerator idGenerator;
101 +
102 + private Map<Long, FlowOperationsProcessor> pendingFlowOperations = new
103 + ConcurrentHashMap<>();
94 104
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected FlowRuleStore store; 106 protected FlowRuleStore store;
...@@ -101,10 +111,15 @@ public class FlowRuleManager ...@@ -101,10 +111,15 @@ public class FlowRuleManager
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected DeviceService deviceService; 112 protected DeviceService deviceService;
103 113
114 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 + protected CoreService coreService;
116 +
104 @Activate 117 @Activate
105 public void activate() { 118 public void activate() {
106 - futureService = 119 +
107 - Executors.newFixedThreadPool(32, namedThreads("onos-provider-future-listeners-%d")); 120 + idGenerator = coreService.getIdGenerator(FLOW_OP_TOPIC);
121 +
122 +
108 store.setDelegate(delegate); 123 store.setDelegate(delegate);
109 eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry); 124 eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
110 log.info("Started"); 125 log.info("Started");
...@@ -112,8 +127,8 @@ public class FlowRuleManager ...@@ -112,8 +127,8 @@ public class FlowRuleManager
112 127
113 @Deactivate 128 @Deactivate
114 public void deactivate() { 129 public void deactivate() {
115 - futureService.shutdownNow(); 130 + deviceInstallers.shutdownNow();
116 - 131 + operationsService.shutdownNow();
117 store.unsetDelegate(delegate); 132 store.unsetDelegate(delegate);
118 eventDispatcher.removeSink(FlowRuleEvent.class); 133 eventDispatcher.removeSink(FlowRuleEvent.class);
119 log.info("Stopped"); 134 log.info("Stopped");
...@@ -131,20 +146,20 @@ public class FlowRuleManager ...@@ -131,20 +146,20 @@ public class FlowRuleManager
131 146
132 @Override 147 @Override
133 public void applyFlowRules(FlowRule... flowRules) { 148 public void applyFlowRules(FlowRule... flowRules) {
134 - Set<FlowRuleBatchEntry> toAddBatchEntries = Sets.newHashSet(); 149 + FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
135 for (int i = 0; i < flowRules.length; i++) { 150 for (int i = 0; i < flowRules.length; i++) {
136 - toAddBatchEntries.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, flowRules[i])); 151 + builder.add(flowRules[i]);
137 } 152 }
138 - applyBatch(new FlowRuleBatchOperation(toAddBatchEntries)); 153 + apply(builder.build());
139 } 154 }
140 155
141 @Override 156 @Override
142 public void removeFlowRules(FlowRule... flowRules) { 157 public void removeFlowRules(FlowRule... flowRules) {
143 - Set<FlowRuleBatchEntry> toRemoveBatchEntries = Sets.newHashSet(); 158 + FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
144 for (int i = 0; i < flowRules.length; i++) { 159 for (int i = 0; i < flowRules.length; i++) {
145 - toRemoveBatchEntries.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, flowRules[i])); 160 + builder.remove(flowRules[i]);
146 } 161 }
147 - applyBatch(new FlowRuleBatchOperation(toRemoveBatchEntries)); 162 + apply(builder.build());
148 } 163 }
149 164
150 @Override 165 @Override
...@@ -180,23 +195,38 @@ public class FlowRuleManager ...@@ -180,23 +195,38 @@ public class FlowRuleManager
180 } 195 }
181 196
182 @Override 197 @Override
183 - public Future<CompletedBatchOperation> applyBatch( 198 + public Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch) {
184 - FlowRuleBatchOperation batch) { 199 +
185 - Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches = 200 +
186 - ArrayListMultimap.create(); 201 + FlowRuleOperations.Builder fopsBuilder = FlowRuleOperations.builder();
187 - List<Future<CompletedBatchOperation>> futures = Lists.newArrayList(); 202 + batch.getOperations().stream().forEach(op -> {
188 - for (FlowRuleBatchEntry fbe : batch.getOperations()) { 203 + switch (op.getOperator()) {
189 - final FlowRule f = fbe.target(); 204 + case ADD:
190 - perDeviceBatches.put(f.deviceId(), fbe); 205 + fopsBuilder.add(op.getTarget());
206 + break;
207 + case REMOVE:
208 + fopsBuilder.remove(op.getTarget());
209 + break;
210 + case MODIFY:
211 + fopsBuilder.modify(op.getTarget());
212 + break;
213 + default:
214 + log.warn("Unknown flow operation operator: {}", op.getOperator());
215 +
191 } 216 }
217 + }
218 + );
219 +
220 + apply(fopsBuilder.build());
221 + return Futures.immediateFuture(
222 + new CompletedBatchOperation(true,
223 + Collections.emptySet(), null));
192 224
193 - for (DeviceId deviceId : perDeviceBatches.keySet()) {
194 - FlowRuleBatchOperation b =
195 - new FlowRuleBatchOperation(perDeviceBatches.get(deviceId));
196 - Future<CompletedBatchOperation> future = store.storeBatch(b);
197 - futures.add(future);
198 } 225 }
199 - return new FlowRuleBatchFuture(futures, perDeviceBatches); 226 +
227 + @Override
228 + public void apply(FlowRuleOperations ops) {
229 + operationsService.submit(new FlowOperationsProcessor(ops));
200 } 230 }
201 231
202 @Override 232 @Override
...@@ -373,13 +403,19 @@ public class FlowRuleManager ...@@ -373,13 +403,19 @@ public class FlowRuleManager
373 403
374 } 404 }
375 } 405 }
406 +
407 + @Override
408 + public void batchOperationCompleted(long batchId, CompletedBatchOperation operation) {
409 + store.batchOperationComplete(FlowRuleBatchEvent.completed(
410 + new FlowRuleBatchRequest(batchId, Collections.emptySet()),
411 + operation
412 + ));
413 + }
376 } 414 }
377 415
378 // Store delegate to re-post events emitted from the store. 416 // Store delegate to re-post events emitted from the store.
379 private class InternalStoreDelegate implements FlowRuleStoreDelegate { 417 private class InternalStoreDelegate implements FlowRuleStoreDelegate {
380 418
381 - // FIXME set appropriate default and make it configurable
382 - private static final int TIMEOUT_PER_OP = 500; // ms
383 419
384 // TODO: Right now we only dispatch events at individual flowEntry level. 420 // TODO: Right now we only dispatch events at individual flowEntry level.
385 // It may be more efficient for also dispatch events as a batch. 421 // It may be more efficient for also dispatch events as a batch.
...@@ -389,47 +425,55 @@ public class FlowRuleManager ...@@ -389,47 +425,55 @@ public class FlowRuleManager
389 switch (event.type()) { 425 switch (event.type()) {
390 case BATCH_OPERATION_REQUESTED: 426 case BATCH_OPERATION_REQUESTED:
391 // Request has been forwarded to MASTER Node, and was 427 // Request has been forwarded to MASTER Node, and was
392 - for (FlowRule entry : request.toAdd()) { 428 + request.ops().stream().forEach(
393 - eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, entry)); 429 + op -> {
430 + switch (op.getOperator()) {
431 +
432 + case ADD:
433 + eventDispatcher.post(
434 + new FlowRuleEvent(
435 + FlowRuleEvent.Type.RULE_ADD_REQUESTED,
436 + op.getTarget()));
437 + break;
438 + case REMOVE:
439 + eventDispatcher.post(
440 + new FlowRuleEvent(
441 + FlowRuleEvent.Type.RULE_REMOVE_REQUESTED,
442 + op.getTarget()));
443 + break;
444 + case MODIFY:
445 + //TODO: do something here when the time comes.
446 + break;
447 + default:
448 + log.warn("Unknown flow operation operator: {}", op.getOperator());
394 } 449 }
395 - for (FlowRule entry : request.toRemove()) {
396 - eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, entry));
397 } 450 }
398 - // FIXME: what about op.equals(FlowRuleOperation.MODIFY) ? 451 + );
452 +
453 + DeviceId deviceId = event.deviceId();
399 454
400 - FlowRuleBatchOperation batchOperation = request.asBatchOperation(); 455 + FlowRuleBatchOperation batchOperation =
456 + request.asBatchOperation(deviceId);
401 457
402 FlowRuleProvider flowRuleProvider = 458 FlowRuleProvider flowRuleProvider =
403 - getProvider(batchOperation.getOperations().get(0).target().deviceId()); 459 + getProvider(deviceId);
404 - final Future<CompletedBatchOperation> result = 460 +
405 flowRuleProvider.executeBatch(batchOperation); 461 flowRuleProvider.executeBatch(batchOperation);
406 - futureService.submit(new Runnable() {
407 - @Override
408 - public void run() {
409 - CompletedBatchOperation res;
410 - try {
411 - res = result.get(TIMEOUT_PER_OP * batchOperation.size(), TimeUnit.MILLISECONDS);
412 - store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res));
413 - } catch (TimeoutException | InterruptedException | ExecutionException e) {
414 - log.warn("Something went wrong with the batch operation {}",
415 - request.batchId(), e);
416 462
417 - Set<FlowRule> failures = new HashSet<>(batchOperation.size());
418 - for (FlowRuleBatchEntry op : batchOperation.getOperations()) {
419 - failures.add(op.target());
420 - }
421 - res = new CompletedBatchOperation(false, failures);
422 - store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res));
423 - }
424 - }
425 - });
426 break; 463 break;
427 464
428 case BATCH_OPERATION_COMPLETED: 465 case BATCH_OPERATION_COMPLETED:
429 - // MASTER Node has pushed the batch down to the Device
430 466
431 - // Note: RULE_ADDED will be posted 467 + FlowOperationsProcessor fops = pendingFlowOperations.remove(
432 - // when Flow was actually confirmed by stats reply. 468 + event.subject().batchId());
469 + if (event.result().isSuccess()) {
470 + if (fops != null) {
471 + fops.satisfy(event.deviceId());
472 + }
473 + } else {
474 + fops.fail(event.deviceId(), event.result().failedItems());
475 + }
476 +
433 break; 477 break;
434 478
435 default: 479 default:
...@@ -438,141 +482,100 @@ public class FlowRuleManager ...@@ -438,141 +482,100 @@ public class FlowRuleManager
438 } 482 }
439 } 483 }
440 484
441 - private class FlowRuleBatchFuture implements Future<CompletedBatchOperation> { 485 + private class FlowOperationsProcessor implements Runnable {
442 486
443 - private final List<Future<CompletedBatchOperation>> futures; 487 + private final List<Set<FlowRuleOperation>> stages;
444 - private final Multimap<DeviceId, FlowRuleBatchEntry> batches; 488 + private final FlowRuleOperationsContext context;
445 - private final AtomicReference<BatchState> state; 489 + private final FlowRuleOperations fops;
446 - private CompletedBatchOperation overall; 490 + private final AtomicBoolean hasFailed = new AtomicBoolean(false);
447 491
448 - public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures, 492 + private Set<DeviceId> pendingDevices;
449 - Multimap<DeviceId, FlowRuleBatchEntry> batches) {
450 - this.futures = futures;
451 - this.batches = batches;
452 - this.state = new AtomicReference<>(BatchState.STARTED);
453 - }
454 -
455 - @Override
456 - public boolean cancel(boolean mayInterruptIfRunning) {
457 - if (state.get() == BatchState.FINISHED) {
458 - return false;
459 - }
460 - if (log.isDebugEnabled()) {
461 - log.debug("Cancelling FlowRuleBatchFuture",
462 - new RuntimeException("Just printing backtrace"));
463 - }
464 - if (!state.compareAndSet(BatchState.STARTED, BatchState.CANCELLED)) {
465 - return false;
466 - }
467 - cleanUpBatch();
468 - for (Future<CompletedBatchOperation> f : futures) {
469 - f.cancel(mayInterruptIfRunning);
470 - }
471 - return true;
472 - }
473 493
474 - @Override 494 + public FlowOperationsProcessor(FlowRuleOperations ops) {
475 - public boolean isCancelled() {
476 - return state.get() == BatchState.CANCELLED;
477 - }
478 -
479 - @Override
480 - public boolean isDone() {
481 - return state.get() == BatchState.FINISHED;
482 - }
483 495
496 + this.stages = Lists.newArrayList(ops.stages());
497 + this.context = ops.callback();
498 + this.fops = ops;
499 + pendingDevices = Sets.newConcurrentHashSet();
484 500
485 - @Override
486 - public CompletedBatchOperation get() throws InterruptedException,
487 - ExecutionException {
488 501
489 - if (isDone()) {
490 - return overall;
491 } 502 }
492 503
493 - boolean success = true; 504 + @Override
494 - Set<FlowRule> failed = Sets.newHashSet(); 505 + public void run() {
495 - Set<Long> failedIds = Sets.newHashSet(); 506 + if (stages.size() > 0) {
496 - CompletedBatchOperation completed; 507 + process(stages.remove(0));
497 - for (Future<CompletedBatchOperation> future : futures) { 508 + } else if (!hasFailed.get() && context != null) {
498 - completed = future.get(); 509 + context.onSuccess(fops);
499 - success = validateBatchOperation(failed, failedIds, completed);
500 } 510 }
501 -
502 - return finalizeBatchOperation(success, failed, failedIds);
503 -
504 } 511 }
505 512
506 - @Override 513 + private void process(Set<FlowRuleOperation> ops) {
507 - public CompletedBatchOperation get(long timeout, TimeUnit unit) 514 + Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches =
508 - throws InterruptedException, ExecutionException, 515 + ArrayListMultimap.create();
509 - TimeoutException {
510 516
511 - if (isDone()) { 517 + FlowRuleBatchEntry fbe;
512 - return overall; 518 + for (FlowRuleOperation flowRuleOperation : ops) {
513 - } 519 + switch (flowRuleOperation.type()) {
514 - boolean success = true; 520 + // FIXME: Brian needs imagination when creating class names.
515 - Set<FlowRule> failed = Sets.newHashSet(); 521 + case ADD:
516 - Set<Long> failedIds = Sets.newHashSet(); 522 + fbe = new FlowRuleBatchEntry(
517 - CompletedBatchOperation completed; 523 + FlowRuleBatchEntry.FlowRuleOperation.ADD, flowRuleOperation.rule());
518 - for (Future<CompletedBatchOperation> future : futures) { 524 + break;
519 - completed = future.get(timeout, unit); 525 + case MODIFY:
520 - success = validateBatchOperation(failed, failedIds, completed); 526 + fbe = new FlowRuleBatchEntry(
527 + FlowRuleBatchEntry.FlowRuleOperation.MODIFY, flowRuleOperation.rule());
528 + break;
529 + case REMOVE:
530 + fbe = new FlowRuleBatchEntry(
531 + FlowRuleBatchEntry.FlowRuleOperation.REMOVE, flowRuleOperation.rule());
532 + break;
533 + default:
534 + throw new UnsupportedOperationException("Unknown flow rule type " + flowRuleOperation.type());
521 } 535 }
522 - return finalizeBatchOperation(success, failed, failedIds); 536 + pendingDevices.add(flowRuleOperation.rule().deviceId());
537 + perDeviceBatches.put(flowRuleOperation.rule().deviceId(), fbe);
523 } 538 }
524 539
525 - private boolean validateBatchOperation(Set<FlowRule> failed,
526 - Set<Long> failedIds,
527 - CompletedBatchOperation completed) {
528 540
529 - if (isCancelled()) { 541 + for (DeviceId deviceId : perDeviceBatches.keySet()) {
530 - throw new CancellationException(); 542 + Long id = idGenerator.getNewId();
543 + final FlowRuleBatchOperation b = new FlowRuleBatchOperation(perDeviceBatches.get(deviceId),
544 + deviceId, id);
545 + pendingFlowOperations.put(id, this);
546 + deviceInstallers.submit(new Runnable() {
547 + @Override
548 + public void run() {
549 + store.storeBatch(b);
531 } 550 }
532 - if (!completed.isSuccess()) { 551 + });
533 - log.warn("FlowRuleBatch failed: {}", completed);
534 - failed.addAll(completed.failedItems());
535 - failedIds.addAll(completed.failedIds());
536 - cleanUpBatch();
537 - cancelAllSubBatches();
538 - return false;
539 } 552 }
540 - return true;
541 } 553 }
542 554
543 - private void cancelAllSubBatches() { 555 + public void satisfy(DeviceId devId) {
544 - for (Future<CompletedBatchOperation> f : futures) { 556 + pendingDevices.remove(devId);
545 - f.cancel(true); 557 + if (pendingDevices.isEmpty()) {
558 + operationsService.submit(this);
546 } 559 }
547 } 560 }
548 561
549 - private CompletedBatchOperation finalizeBatchOperation(boolean success,
550 - Set<FlowRule> failed,
551 - Set<Long> failedIds) {
552 - synchronized (this) {
553 - if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) {
554 - if (state.get() == BatchState.FINISHED) {
555 - return overall;
556 - }
557 - throw new CancellationException();
558 - }
559 - overall = new CompletedBatchOperation(success, failed, failedIds);
560 - return overall;
561 - }
562 - }
563 562
564 - private void cleanUpBatch() { 563 +
565 - log.debug("cleaning up batch"); 564 + public void fail(DeviceId devId, Set<? extends FlowRule> failures) {
566 - // TODO convert these into a batch? 565 + hasFailed.set(true);
567 - for (FlowRuleBatchEntry fbe : batches.values()) { 566 + pendingDevices.remove(devId);
568 - if (fbe.operator() == FlowRuleOperation.ADD || 567 + if (pendingDevices.isEmpty()) {
569 - fbe.operator() == FlowRuleOperation.MODIFY) { 568 + operationsService.submit(this);
570 - store.deleteFlowRule(fbe.target());
571 - } else if (fbe.operator() == FlowRuleOperation.REMOVE) {
572 - store.removeFlowRule(new DefaultFlowEntry(fbe.target()));
573 - store.storeFlowRule(fbe.target());
574 } 569 }
570 +
571 + if (context != null) {
572 + final FlowRuleOperations.Builder failedOpsBuilder =
573 + FlowRuleOperations.builder();
574 + failures.stream().forEach(failedOpsBuilder::add);
575 +
576 + context.onError(failedOpsBuilder.build());
575 } 577 }
576 } 578 }
579 +
577 } 580 }
578 } 581 }
......
...@@ -1151,6 +1151,7 @@ public class IntentManager ...@@ -1151,6 +1151,7 @@ public class IntentManager
1151 */ 1151 */
1152 protected Future<CompletedBatchOperation> applyNextBatch(List<CompletedIntentUpdate> updates) { 1152 protected Future<CompletedBatchOperation> applyNextBatch(List<CompletedIntentUpdate> updates) {
1153 //TODO test this. (also, maybe save this batch) 1153 //TODO test this. (also, maybe save this batch)
1154 +
1154 FlowRuleBatchOperation batch = createFlowRuleBatchOperation(updates); 1155 FlowRuleBatchOperation batch = createFlowRuleBatchOperation(updates);
1155 if (batch.size() > 0) { 1156 if (batch.size() > 0) {
1156 //FIXME apply batch might throw an exception 1157 //FIXME apply batch might throw an exception
...@@ -1165,7 +1166,7 @@ public class IntentManager ...@@ -1165,7 +1166,7 @@ public class IntentManager
1165 } 1166 }
1166 1167
1167 private FlowRuleBatchOperation createFlowRuleBatchOperation(List<CompletedIntentUpdate> intentUpdates) { 1168 private FlowRuleBatchOperation createFlowRuleBatchOperation(List<CompletedIntentUpdate> intentUpdates) {
1168 - FlowRuleBatchOperation batch = new FlowRuleBatchOperation(Collections.emptyList()); 1169 + FlowRuleBatchOperation batch = new FlowRuleBatchOperation(Collections.emptyList(), null, 0);
1169 for (CompletedIntentUpdate update : intentUpdates) { 1170 for (CompletedIntentUpdate update : intentUpdates) {
1170 FlowRuleBatchOperation currentBatch = update.currentBatch(); 1171 FlowRuleBatchOperation currentBatch = update.currentBatch();
1171 if (currentBatch != null) { 1172 if (currentBatch != null) {
......
...@@ -98,6 +98,7 @@ public class LinkCollectionIntentInstaller ...@@ -98,6 +98,7 @@ public class LinkCollectionIntentInstaller
98 outputPorts.put(egressPoint.deviceId(), egressPoint.port()); 98 outputPorts.put(egressPoint.deviceId(), egressPoint.port());
99 } 99 }
100 100
101 + //FIXME change to new api
101 FlowRuleBatchOperation batchOperation = 102 FlowRuleBatchOperation batchOperation =
102 new FlowRuleBatchOperation(outputPorts 103 new FlowRuleBatchOperation(outputPorts
103 .keys() 104 .keys()
...@@ -105,7 +106,7 @@ public class LinkCollectionIntentInstaller ...@@ -105,7 +106,7 @@ public class LinkCollectionIntentInstaller
105 .map(deviceId -> createBatchEntry(operation, 106 .map(deviceId -> createBatchEntry(operation,
106 intent, deviceId, 107 intent, deviceId,
107 outputPorts.get(deviceId))) 108 outputPorts.get(deviceId)))
108 - .collect(Collectors.toList())); 109 + .collect(Collectors.toList()), null, 0);
109 110
110 return Collections.singletonList(batchOperation); 111 return Collections.singletonList(batchOperation);
111 } 112 }
......
...@@ -181,6 +181,7 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn ...@@ -181,6 +181,7 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
181 true); 181 true);
182 rules.add(new FlowRuleBatchEntry(operation, rule)); 182 rules.add(new FlowRuleBatchEntry(operation, rule));
183 183
184 - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 184 + //FIXME change to new api
185 + return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0));
185 } 186 }
186 } 187 }
......
...@@ -108,7 +108,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { ...@@ -108,7 +108,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
108 intent.id().fingerprint())); 108 intent.id().fingerprint()));
109 prev = link.dst(); 109 prev = link.dst();
110 } 110 }
111 - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 111 + //FIXME this should change to new api.
112 + return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0));
112 } 113 }
113 114
114 @Override 115 @Override
...@@ -138,7 +139,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { ...@@ -138,7 +139,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
138 intent.id().fingerprint())); 139 intent.id().fingerprint()));
139 prev = link.dst(); 140 prev = link.dst();
140 } 141 }
141 - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 142 + // FIXME this should change to new api
143 + return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0));
142 } 144 }
143 145
144 @Override 146 @Override
......
...@@ -31,7 +31,7 @@ public class TestEventDispatcher extends DefaultEventSinkRegistry ...@@ -31,7 +31,7 @@ public class TestEventDispatcher extends DefaultEventSinkRegistry
31 31
32 @Override 32 @Override
33 @SuppressWarnings("unchecked") 33 @SuppressWarnings("unchecked")
34 - public void post(Event event) { 34 + public synchronized void post(Event event) {
35 EventSink sink = getSink(event.getClass()); 35 EventSink sink = getSink(event.getClass());
36 checkState(sink != null, "No sink for event %s", event); 36 checkState(sink != null, "No sink for event %s", event);
37 sink.process(event); 37 sink.process(event);
......
...@@ -20,12 +20,15 @@ import com.google.common.collect.ImmutableMap; ...@@ -20,12 +20,15 @@ import com.google.common.collect.ImmutableMap;
20 import com.google.common.collect.Lists; 20 import com.google.common.collect.Lists;
21 import com.google.common.collect.Sets; 21 import com.google.common.collect.Sets;
22 import com.google.common.util.concurrent.ListenableFuture; 22 import com.google.common.util.concurrent.ListenableFuture;
23 - 23 +import com.google.common.util.concurrent.MoreExecutors;
24 import org.junit.After; 24 import org.junit.After;
25 import org.junit.Before; 25 import org.junit.Before;
26 import org.junit.Test; 26 import org.junit.Test;
27 import org.onosproject.core.ApplicationId; 27 import org.onosproject.core.ApplicationId;
28 +import org.onosproject.core.CoreService;
28 import org.onosproject.core.DefaultApplicationId; 29 import org.onosproject.core.DefaultApplicationId;
30 +import org.onosproject.core.IdGenerator;
31 +import org.onosproject.core.Version;
29 import org.onosproject.event.impl.TestEventDispatcher; 32 import org.onosproject.event.impl.TestEventDispatcher;
30 import org.onosproject.net.DefaultDevice; 33 import org.onosproject.net.DefaultDevice;
31 import org.onosproject.net.Device; 34 import org.onosproject.net.Device;
...@@ -36,7 +39,6 @@ import org.onosproject.net.Port; ...@@ -36,7 +39,6 @@ import org.onosproject.net.Port;
36 import org.onosproject.net.PortNumber; 39 import org.onosproject.net.PortNumber;
37 import org.onosproject.net.device.DeviceListener; 40 import org.onosproject.net.device.DeviceListener;
38 import org.onosproject.net.device.DeviceServiceAdapter; 41 import org.onosproject.net.device.DeviceServiceAdapter;
39 -import org.onosproject.net.flow.BatchOperation;
40 import org.onosproject.net.flow.CompletedBatchOperation; 42 import org.onosproject.net.flow.CompletedBatchOperation;
41 import org.onosproject.net.flow.DefaultFlowEntry; 43 import org.onosproject.net.flow.DefaultFlowEntry;
42 import org.onosproject.net.flow.DefaultFlowRule; 44 import org.onosproject.net.flow.DefaultFlowRule;
...@@ -72,6 +74,7 @@ import java.util.concurrent.Executor; ...@@ -72,6 +74,7 @@ import java.util.concurrent.Executor;
72 import java.util.concurrent.Future; 74 import java.util.concurrent.Future;
73 import java.util.concurrent.TimeUnit; 75 import java.util.concurrent.TimeUnit;
74 import java.util.concurrent.TimeoutException; 76 import java.util.concurrent.TimeoutException;
77 +import java.util.concurrent.atomic.AtomicLong;
75 78
76 import static org.junit.Assert.*; 79 import static org.junit.Assert.*;
77 import static org.onosproject.net.flow.FlowRuleEvent.Type.*; 80 import static org.onosproject.net.flow.FlowRuleEvent.Type.*;
...@@ -97,12 +100,16 @@ public class FlowRuleManagerTest { ...@@ -97,12 +100,16 @@ public class FlowRuleManagerTest {
97 protected TestListener listener = new TestListener(); 100 protected TestListener listener = new TestListener();
98 private ApplicationId appId; 101 private ApplicationId appId;
99 102
103 +
100 @Before 104 @Before
101 public void setUp() { 105 public void setUp() {
102 mgr = new FlowRuleManager(); 106 mgr = new FlowRuleManager();
103 mgr.store = new SimpleFlowRuleStore(); 107 mgr.store = new SimpleFlowRuleStore();
104 mgr.eventDispatcher = new TestEventDispatcher(); 108 mgr.eventDispatcher = new TestEventDispatcher();
105 mgr.deviceService = new TestDeviceService(); 109 mgr.deviceService = new TestDeviceService();
110 + mgr.coreService = new TestCoreService();
111 + mgr.operationsService = MoreExecutors.newDirectExecutorService();
112 + mgr.deviceInstallers = MoreExecutors.newDirectExecutorService();
106 service = mgr; 113 service = mgr;
107 registry = mgr; 114 registry = mgr;
108 115
...@@ -246,14 +253,23 @@ public class FlowRuleManagerTest { ...@@ -246,14 +253,23 @@ public class FlowRuleManagerTest {
246 253
247 @Test 254 @Test
248 public void flowRemoved() { 255 public void flowRemoved() {
256 +
249 FlowRule f1 = addFlowRule(1); 257 FlowRule f1 = addFlowRule(1);
250 FlowRule f2 = addFlowRule(2); 258 FlowRule f2 = addFlowRule(2);
251 StoredFlowEntry fe1 = new DefaultFlowEntry(f1); 259 StoredFlowEntry fe1 = new DefaultFlowEntry(f1);
252 FlowEntry fe2 = new DefaultFlowEntry(f2); 260 FlowEntry fe2 = new DefaultFlowEntry(f2);
261 +
262 +
253 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2)); 263 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
254 service.removeFlowRules(f1); 264 service.removeFlowRules(f1);
265 +
255 fe1.setState(FlowEntryState.REMOVED); 266 fe1.setState(FlowEntryState.REMOVED);
267 +
268 +
269 +
256 providerService.flowRemoved(fe1); 270 providerService.flowRemoved(fe1);
271 +
272 +
257 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED, 273 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED,
258 RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED); 274 RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED);
259 275
...@@ -263,11 +279,13 @@ public class FlowRuleManagerTest { ...@@ -263,11 +279,13 @@ public class FlowRuleManagerTest {
263 FlowRule f3 = flowRule(3, 3); 279 FlowRule f3 = flowRule(3, 3);
264 FlowEntry fe3 = new DefaultFlowEntry(f3); 280 FlowEntry fe3 = new DefaultFlowEntry(f3);
265 service.applyFlowRules(f3); 281 service.applyFlowRules(f3);
282 +
266 providerService.pushFlowMetrics(DID, Collections.singletonList(fe3)); 283 providerService.pushFlowMetrics(DID, Collections.singletonList(fe3));
267 validateEvents(RULE_ADD_REQUESTED, RULE_ADDED); 284 validateEvents(RULE_ADD_REQUESTED, RULE_ADDED);
268 285
269 providerService.flowRemoved(fe3); 286 providerService.flowRemoved(fe3);
270 validateEvents(); 287 validateEvents();
288 +
271 } 289 }
272 290
273 @Test 291 @Test
...@@ -281,7 +299,6 @@ public class FlowRuleManagerTest { ...@@ -281,7 +299,6 @@ public class FlowRuleManagerTest {
281 FlowEntry fe1 = new DefaultFlowEntry(f1); 299 FlowEntry fe1 = new DefaultFlowEntry(f1);
282 FlowEntry fe2 = new DefaultFlowEntry(f2); 300 FlowEntry fe2 = new DefaultFlowEntry(f2);
283 301
284 -
285 //FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED); 302 //FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
286 //FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED); 303 //FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
287 304
...@@ -388,7 +405,7 @@ public class FlowRuleManagerTest { ...@@ -388,7 +405,7 @@ public class FlowRuleManagerTest {
388 FlowRuleBatchEntry.FlowRuleOperation.ADD, f2); 405 FlowRuleBatchEntry.FlowRuleOperation.ADD, f2);
389 406
390 FlowRuleBatchOperation fbo = new FlowRuleBatchOperation( 407 FlowRuleBatchOperation fbo = new FlowRuleBatchOperation(
391 - Lists.newArrayList(fbe1, fbe2)); 408 + Lists.newArrayList(fbe1, fbe2), null, 0);
392 Future<CompletedBatchOperation> future = mgr.applyBatch(fbo); 409 Future<CompletedBatchOperation> future = mgr.applyBatch(fbo);
393 assertTrue("Entries in wrong state", 410 assertTrue("Entries in wrong state",
394 validateState(ImmutableMap.of( 411 validateState(ImmutableMap.of(
...@@ -406,53 +423,6 @@ public class FlowRuleManagerTest { ...@@ -406,53 +423,6 @@ public class FlowRuleManagerTest {
406 423
407 } 424 }
408 425
409 - @Test
410 - public void cancelBatch() {
411 - FlowRule f1 = flowRule(1, 1);
412 - FlowRule f2 = flowRule(2, 2);
413 -
414 -
415 - mgr.applyFlowRules(f1);
416 -
417 - assertTrue("Entries in wrong state",
418 - validateState(ImmutableMap.of(
419 - f1, FlowEntryState.PENDING_ADD)));
420 -
421 - FlowEntry fe1 = new DefaultFlowEntry(f1);
422 - providerService.pushFlowMetrics(DID, Collections.<FlowEntry>singletonList(fe1));
423 -
424 - assertTrue("Entries in wrong state",
425 - validateState(ImmutableMap.of(
426 - f1, FlowEntryState.ADDED)));
427 -
428 -
429 - FlowRuleBatchEntry fbe1 = new FlowRuleBatchEntry(
430 - FlowRuleBatchEntry.FlowRuleOperation.REMOVE, f1);
431 -
432 - FlowRuleBatchEntry fbe2 = new FlowRuleBatchEntry(
433 - FlowRuleBatchEntry.FlowRuleOperation.ADD, f2);
434 -
435 - FlowRuleBatchOperation fbo = new FlowRuleBatchOperation(
436 - Lists.newArrayList(fbe1, fbe2));
437 - Future<CompletedBatchOperation> future = mgr.applyBatch(fbo);
438 -
439 - future.cancel(true);
440 -
441 - assertTrue(flowCount() == 2);
442 -
443 - /*
444 - * Rule f1 should be re-added to the list and therefore be in a pending add
445 - * state.
446 - */
447 - assertTrue("Entries in wrong state",
448 - validateState(ImmutableMap.of(
449 - f2, FlowEntryState.PENDING_REMOVE,
450 - f1, FlowEntryState.PENDING_ADD)));
451 -
452 -
453 - }
454 -
455 -
456 private static class TestListener implements FlowRuleListener { 426 private static class TestListener implements FlowRuleListener {
457 final List<FlowRuleEvent> events = new ArrayList<>(); 427 final List<FlowRuleEvent> events = new ArrayList<>();
458 428
...@@ -528,9 +498,8 @@ public class FlowRuleManagerTest { ...@@ -528,9 +498,8 @@ public class FlowRuleManagerTest {
528 } 498 }
529 499
530 @Override 500 @Override
531 - public ListenableFuture<CompletedBatchOperation> executeBatch( 501 + public void executeBatch(FlowRuleBatchOperation batch) {
532 - BatchOperation<FlowRuleBatchEntry> batch) { 502 + // TODO: need to call batchOperationComplete
533 - return new TestInstallationFuture();
534 } 503 }
535 504
536 private class TestInstallationFuture 505 private class TestInstallationFuture
...@@ -554,14 +523,14 @@ public class FlowRuleManagerTest { ...@@ -554,14 +523,14 @@ public class FlowRuleManagerTest {
554 @Override 523 @Override
555 public CompletedBatchOperation get() 524 public CompletedBatchOperation get()
556 throws InterruptedException, ExecutionException { 525 throws InterruptedException, ExecutionException {
557 - return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet()); 526 + return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null);
558 } 527 }
559 528
560 @Override 529 @Override
561 public CompletedBatchOperation get(long timeout, TimeUnit unit) 530 public CompletedBatchOperation get(long timeout, TimeUnit unit)
562 throws InterruptedException, 531 throws InterruptedException,
563 ExecutionException, TimeoutException { 532 ExecutionException, TimeoutException {
564 - return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet()); 533 + return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null);
565 } 534 }
566 535
567 @Override 536 @Override
...@@ -644,4 +613,37 @@ public class FlowRuleManagerTest { ...@@ -644,4 +613,37 @@ public class FlowRuleManagerTest {
644 } 613 }
645 } 614 }
646 615
616 + private class TestCoreService implements CoreService {
617 + @Override
618 + public Version version() {
619 + return null;
620 + }
621 +
622 + @Override
623 + public Set<ApplicationId> getAppIds() {
624 + return null;
625 + }
626 +
627 + @Override
628 + public ApplicationId getAppId(Short id) {
629 + return null;
630 + }
631 +
632 + @Override
633 + public ApplicationId registerApplication(String identifier) {
634 + return null;
635 + }
636 +
637 + @Override
638 + public IdGenerator getIdGenerator(String topic) {
639 + return new IdGenerator() {
640 + private AtomicLong counter = new AtomicLong(0);
641 + @Override
642 + public long getNewId() {
643 + return counter.getAndIncrement();
644 + }
645 + };
646 + }
647 + }
648 +
647 } 649 }
......
...@@ -201,7 +201,7 @@ public class IntentManagerTest { ...@@ -201,7 +201,7 @@ public class IntentManagerTest {
201 FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue()); 201 FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
202 List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); 202 List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
203 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr)); 203 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr));
204 - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 204 + return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0));
205 } 205 }
206 206
207 @Override 207 @Override
...@@ -209,7 +209,7 @@ public class IntentManagerTest { ...@@ -209,7 +209,7 @@ public class IntentManagerTest {
209 FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue()); 209 FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
210 List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); 210 List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
211 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr)); 211 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
212 - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 212 + return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0));
213 } 213 }
214 214
215 @Override 215 @Override
...@@ -219,7 +219,7 @@ public class IntentManagerTest { ...@@ -219,7 +219,7 @@ public class IntentManagerTest {
219 List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); 219 List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
220 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr)); 220 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
221 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr2)); 221 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr2));
222 - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 222 + return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0));
223 } 223 }
224 } 224 }
225 225
......
...@@ -27,6 +27,7 @@ import org.onosproject.net.flow.FlowRule; ...@@ -27,6 +27,7 @@ import org.onosproject.net.flow.FlowRule;
27 import org.onosproject.net.flow.FlowRuleBatchEntry; 27 import org.onosproject.net.flow.FlowRuleBatchEntry;
28 import org.onosproject.net.flow.FlowRuleBatchOperation; 28 import org.onosproject.net.flow.FlowRuleBatchOperation;
29 import org.onosproject.net.flow.FlowRuleListener; 29 import org.onosproject.net.flow.FlowRuleListener;
30 +import org.onosproject.net.flow.FlowRuleOperations;
30 import org.onosproject.net.flow.FlowRuleService; 31 import org.onosproject.net.flow.FlowRuleService;
31 32
32 import com.google.common.collect.ImmutableSet; 33 import com.google.common.collect.ImmutableSet;
...@@ -45,11 +46,11 @@ public class MockFlowRuleService implements FlowRuleService { ...@@ -45,11 +46,11 @@ public class MockFlowRuleService implements FlowRuleService {
45 46
46 public void setFuture(boolean success, long intentId) { 47 public void setFuture(boolean success, long intentId) {
47 if (success) { 48 if (success) {
48 - future = Futures.immediateFuture(new CompletedBatchOperation(true, Collections.emptySet())); 49 + future = Futures.immediateFuture(new CompletedBatchOperation(true, Collections.emptySet(), null));
49 } else { 50 } else {
50 final Set<Long> failedIds = ImmutableSet.of(intentId); 51 final Set<Long> failedIds = ImmutableSet.of(intentId);
51 future = Futures.immediateFuture( 52 future = Futures.immediateFuture(
52 - new CompletedBatchOperation(false, flows, failedIds)); 53 + new CompletedBatchOperation(false, flows, failedIds, null));
53 } 54 }
54 } 55 }
55 56
...@@ -74,6 +75,11 @@ public class MockFlowRuleService implements FlowRuleService { ...@@ -74,6 +75,11 @@ public class MockFlowRuleService implements FlowRuleService {
74 } 75 }
75 76
76 @Override 77 @Override
78 + public void apply(FlowRuleOperations ops) {
79 +
80 + }
81 +
82 + @Override
77 public int getFlowRuleCount() { 83 public int getFlowRuleCount() {
78 return flows.size(); 84 return flows.size();
79 } 85 }
......
...@@ -15,33 +15,15 @@ ...@@ -15,33 +15,15 @@
15 */ 15 */
16 package org.onosproject.store.flow.impl; 16 package org.onosproject.store.flow.impl;
17 17
18 -import static com.google.common.base.Preconditions.checkNotNull; 18 +import com.google.common.cache.CacheBuilder;
19 -import static org.onlab.util.Tools.namedThreads; 19 +import com.google.common.cache.CacheLoader;
20 -import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED; 20 +import com.google.common.cache.LoadingCache;
21 -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.APPLY_BATCH_FLOWS; 21 +import com.google.common.collect.ImmutableList;
22 -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.GET_DEVICE_FLOW_ENTRIES; 22 +import com.google.common.collect.Iterables;
23 -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.GET_FLOW_ENTRY; 23 +import com.google.common.collect.Maps;
24 -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.REMOVE_FLOW_ENTRY; 24 +import com.google.common.collect.Sets;
25 -import static org.slf4j.LoggerFactory.getLogger; 25 +import com.google.common.util.concurrent.ListenableFuture;
26 - 26 +import com.hazelcast.core.IMap;
27 -import java.io.IOException;
28 -import java.util.ArrayList;
29 -import java.util.Arrays;
30 -import java.util.Collection;
31 -import java.util.Collections;
32 -import java.util.HashSet;
33 -import java.util.List;
34 -import java.util.Map.Entry;
35 -import java.util.Set;
36 -import java.util.concurrent.ExecutionException;
37 -import java.util.concurrent.ExecutorService;
38 -import java.util.concurrent.Executors;
39 -import java.util.concurrent.Future;
40 -import java.util.concurrent.TimeUnit;
41 -import java.util.concurrent.TimeoutException;
42 -import java.util.concurrent.atomic.AtomicInteger;
43 -import java.util.concurrent.locks.ReentrantReadWriteLock;
44 -
45 import org.apache.felix.scr.annotations.Activate; 27 import org.apache.felix.scr.annotations.Activate;
46 import org.apache.felix.scr.annotations.Component; 28 import org.apache.felix.scr.annotations.Component;
47 import org.apache.felix.scr.annotations.Deactivate; 29 import org.apache.felix.scr.annotations.Deactivate;
...@@ -49,8 +31,11 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -49,8 +31,11 @@ import org.apache.felix.scr.annotations.Reference;
49 import org.apache.felix.scr.annotations.ReferenceCardinality; 31 import org.apache.felix.scr.annotations.ReferenceCardinality;
50 import org.apache.felix.scr.annotations.Service; 32 import org.apache.felix.scr.annotations.Service;
51 import org.onlab.util.KryoNamespace; 33 import org.onlab.util.KryoNamespace;
34 +import org.onlab.util.NewConcurrentHashMap;
52 import org.onosproject.cluster.ClusterService; 35 import org.onosproject.cluster.ClusterService;
53 import org.onosproject.cluster.NodeId; 36 import org.onosproject.cluster.NodeId;
37 +import org.onosproject.core.CoreService;
38 +import org.onosproject.core.IdGenerator;
54 import org.onosproject.net.Device; 39 import org.onosproject.net.Device;
55 import org.onosproject.net.DeviceId; 40 import org.onosproject.net.DeviceId;
56 import org.onosproject.net.device.DeviceService; 41 import org.onosproject.net.device.DeviceService;
...@@ -67,6 +52,7 @@ import org.onosproject.net.flow.FlowRuleBatchOperation; ...@@ -67,6 +52,7 @@ import org.onosproject.net.flow.FlowRuleBatchOperation;
67 import org.onosproject.net.flow.FlowRuleBatchRequest; 52 import org.onosproject.net.flow.FlowRuleBatchRequest;
68 import org.onosproject.net.flow.FlowRuleEvent; 53 import org.onosproject.net.flow.FlowRuleEvent;
69 import org.onosproject.net.flow.FlowRuleEvent.Type; 54 import org.onosproject.net.flow.FlowRuleEvent.Type;
55 +import org.onosproject.net.flow.FlowRuleService;
70 import org.onosproject.net.flow.FlowRuleStore; 56 import org.onosproject.net.flow.FlowRuleStore;
71 import org.onosproject.net.flow.FlowRuleStoreDelegate; 57 import org.onosproject.net.flow.FlowRuleStoreDelegate;
72 import org.onosproject.net.flow.StoredFlowEntry; 58 import org.onosproject.net.flow.StoredFlowEntry;
...@@ -79,27 +65,37 @@ import org.onosproject.store.flow.ReplicaInfoEventListener; ...@@ -79,27 +65,37 @@ import org.onosproject.store.flow.ReplicaInfoEventListener;
79 import org.onosproject.store.flow.ReplicaInfoService; 65 import org.onosproject.store.flow.ReplicaInfoService;
80 import org.onosproject.store.hz.AbstractHazelcastStore; 66 import org.onosproject.store.hz.AbstractHazelcastStore;
81 import org.onosproject.store.hz.SMap; 67 import org.onosproject.store.hz.SMap;
82 -import org.onosproject.store.serializers.DecodeTo;
83 import org.onosproject.store.serializers.KryoSerializer; 68 import org.onosproject.store.serializers.KryoSerializer;
84 import org.onosproject.store.serializers.StoreSerializer; 69 import org.onosproject.store.serializers.StoreSerializer;
85 import org.onosproject.store.serializers.impl.DistributedStoreSerializers; 70 import org.onosproject.store.serializers.impl.DistributedStoreSerializers;
86 import org.slf4j.Logger; 71 import org.slf4j.Logger;
87 72
88 -import com.google.common.cache.Cache; 73 +import java.io.IOException;
89 -import com.google.common.cache.CacheBuilder; 74 +import java.util.ArrayList;
90 -import com.google.common.cache.CacheLoader; 75 +import java.util.Arrays;
91 -import com.google.common.cache.LoadingCache; 76 +import java.util.Collections;
92 -import com.google.common.cache.RemovalListener; 77 +import java.util.HashSet;
93 -import com.google.common.cache.RemovalNotification; 78 +import java.util.List;
94 -import com.google.common.collect.ArrayListMultimap; 79 +import java.util.Map;
95 -import com.google.common.collect.ImmutableList; 80 +import java.util.Map.Entry;
96 -import com.google.common.collect.ImmutableSet; 81 +import java.util.Set;
97 -import com.google.common.collect.Iterables; 82 +import java.util.concurrent.ConcurrentHashMap;
98 -import com.google.common.collect.Multimap; 83 +import java.util.concurrent.ConcurrentMap;
99 -import com.google.common.util.concurrent.Futures; 84 +import java.util.concurrent.CopyOnWriteArraySet;
100 -import com.google.common.util.concurrent.ListenableFuture; 85 +import java.util.concurrent.ExecutionException;
101 -import com.google.common.util.concurrent.SettableFuture; 86 +import java.util.concurrent.ExecutorService;
102 -import com.hazelcast.core.IMap; 87 +import java.util.concurrent.Executors;
88 +import java.util.concurrent.Future;
89 +import java.util.concurrent.TimeUnit;
90 +import java.util.concurrent.TimeoutException;
91 +import java.util.stream.Collectors;
92 +
93 +import static com.google.common.base.Preconditions.checkNotNull;
94 +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
95 +import static org.onlab.util.Tools.namedThreads;
96 +import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
97 +import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.*;
98 +import static org.slf4j.LoggerFactory.getLogger;
103 99
104 /** 100 /**
105 * Manages inventory of flow rules using a distributed state management protocol. 101 * Manages inventory of flow rules using a distributed state management protocol.
...@@ -112,12 +108,10 @@ public class DistributedFlowRuleStore ...@@ -112,12 +108,10 @@ public class DistributedFlowRuleStore
112 108
113 private final Logger log = getLogger(getClass()); 109 private final Logger log = getLogger(getClass());
114 110
115 - // primary data: 111 + private InternalFlowTable flowTable = new InternalFlowTable();
116 - // read/write needs to be locked 112 +
117 - private final ReentrantReadWriteLock flowEntriesLock = new ReentrantReadWriteLock(); 113 + /*private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, Set<StoredFlowEntry>>>
118 - // store entries as a pile of rules, no info about device tables 114 + flowEntries = new ConcurrentHashMap<>();*/
119 - private final Multimap<DeviceId, StoredFlowEntry> flowEntries
120 - = ArrayListMultimap.<DeviceId, StoredFlowEntry>create();
121 115
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected ReplicaInfoService replicaInfoManager; 117 protected ReplicaInfoService replicaInfoManager;
...@@ -131,23 +125,15 @@ public class DistributedFlowRuleStore ...@@ -131,23 +125,15 @@ public class DistributedFlowRuleStore
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected DeviceService deviceService; 126 protected DeviceService deviceService;
133 127
134 - private final AtomicInteger localBatchIdGen = new AtomicInteger(); 128 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 - 129 + protected CoreService coreService;
136 - private int pendingFutureTimeoutMinutes = 5;
137 130
138 - private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures = 131 + private Map<Long, NodeId> pendingResponses = Maps.newConcurrentMap();
139 - CacheBuilder.newBuilder()
140 - .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES)
141 - .removalListener(new TimeoutFuture())
142 - .build();
143 132
144 // Cache of SMaps used for backup data. each SMap contain device flow table 133 // Cache of SMaps used for backup data. each SMap contain device flow table
145 private LoadingCache<DeviceId, SMap<FlowId, ImmutableList<StoredFlowEntry>>> smaps; 134 private LoadingCache<DeviceId, SMap<FlowId, ImmutableList<StoredFlowEntry>>> smaps;
146 135
147 136
148 - private final ExecutorService futureListeners =
149 - Executors.newCachedThreadPool(namedThreads("onos-flowstore-peer-responders"));
150 -
151 private final ExecutorService backupExecutors = 137 private final ExecutorService backupExecutors =
152 Executors.newSingleThreadExecutor(namedThreads("onos-async-backups")); 138 Executors.newSingleThreadExecutor(namedThreads("onos-async-backups"));
153 139
...@@ -169,6 +155,8 @@ public class DistributedFlowRuleStore ...@@ -169,6 +155,8 @@ public class DistributedFlowRuleStore
169 155
170 private ReplicaInfoEventListener replicaInfoEventListener; 156 private ReplicaInfoEventListener replicaInfoEventListener;
171 157
158 + private IdGenerator idGenerator;
159 +
172 @Override 160 @Override
173 @Activate 161 @Activate
174 public void activate() { 162 public void activate() {
...@@ -176,6 +164,8 @@ public class DistributedFlowRuleStore ...@@ -176,6 +164,8 @@ public class DistributedFlowRuleStore
176 super.serializer = SERIALIZER; 164 super.serializer = SERIALIZER;
177 super.theInstance = storeService.getHazelcastInstance(); 165 super.theInstance = storeService.getHazelcastInstance();
178 166
167 + idGenerator = coreService.getIdGenerator(FlowRuleService.FLOW_OP_TOPIC);
168 +
179 // Cache to create SMap on demand 169 // Cache to create SMap on demand
180 smaps = CacheBuilder.newBuilder() 170 smaps = CacheBuilder.newBuilder()
181 .softValues() 171 .softValues()
...@@ -185,13 +175,22 @@ public class DistributedFlowRuleStore ...@@ -185,13 +175,22 @@ public class DistributedFlowRuleStore
185 175
186 clusterCommunicator.addSubscriber(APPLY_BATCH_FLOWS, new OnStoreBatch(local)); 176 clusterCommunicator.addSubscriber(APPLY_BATCH_FLOWS, new OnStoreBatch(local));
187 177
178 + clusterCommunicator.addSubscriber(REMOTE_APPLY_COMPLETED, new ClusterMessageHandler() {
179 + @Override
180 + public void handle(ClusterMessage message) {
181 + FlowRuleBatchEvent event = SERIALIZER.decode(message.payload());
182 + log.trace("received completed notification for {}", event);
183 + notifyDelegate(event);
184 + }
185 + });
186 +
188 clusterCommunicator.addSubscriber(GET_FLOW_ENTRY, new ClusterMessageHandler() { 187 clusterCommunicator.addSubscriber(GET_FLOW_ENTRY, new ClusterMessageHandler() {
189 188
190 @Override 189 @Override
191 public void handle(ClusterMessage message) { 190 public void handle(ClusterMessage message) {
192 FlowRule rule = SERIALIZER.decode(message.payload()); 191 FlowRule rule = SERIALIZER.decode(message.payload());
193 log.trace("received get flow entry request for {}", rule); 192 log.trace("received get flow entry request for {}", rule);
194 - FlowEntry flowEntry = getFlowEntryInternal(rule); 193 + FlowEntry flowEntry = flowTable.getFlowEntry(rule); //getFlowEntryInternal(rule);
195 try { 194 try {
196 message.respond(SERIALIZER.encode(flowEntry)); 195 message.respond(SERIALIZER.encode(flowEntry));
197 } catch (IOException e) { 196 } catch (IOException e) {
...@@ -206,7 +205,7 @@ public class DistributedFlowRuleStore ...@@ -206,7 +205,7 @@ public class DistributedFlowRuleStore
206 public void handle(ClusterMessage message) { 205 public void handle(ClusterMessage message) {
207 DeviceId deviceId = SERIALIZER.decode(message.payload()); 206 DeviceId deviceId = SERIALIZER.decode(message.payload());
208 log.trace("Received get flow entries request for {} from {}", deviceId, message.sender()); 207 log.trace("Received get flow entries request for {} from {}", deviceId, message.sender());
209 - Set<FlowEntry> flowEntries = getFlowEntriesInternal(deviceId); 208 + Set<FlowEntry> flowEntries = flowTable.getFlowEntries(deviceId);
210 try { 209 try {
211 message.respond(SERIALIZER.encode(flowEntries)); 210 message.respond(SERIALIZER.encode(flowEntries));
212 } catch (IOException e) { 211 } catch (IOException e) {
...@@ -272,7 +271,7 @@ public class DistributedFlowRuleStore ...@@ -272,7 +271,7 @@ public class DistributedFlowRuleStore
272 } 271 }
273 272
274 if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { 273 if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
275 - return getFlowEntryInternal(rule); 274 + return flowTable.getFlowEntry(rule);
276 } 275 }
277 276
278 log.trace("Forwarding getFlowEntry to {}, which is the primary (master) for device {}", 277 log.trace("Forwarding getFlowEntry to {}, which is the primary (master) for device {}",
...@@ -292,19 +291,7 @@ public class DistributedFlowRuleStore ...@@ -292,19 +291,7 @@ public class DistributedFlowRuleStore
292 return null; 291 return null;
293 } 292 }
294 293
295 - private StoredFlowEntry getFlowEntryInternal(FlowRule rule) { 294 +
296 - flowEntriesLock.readLock().lock();
297 - try {
298 - for (StoredFlowEntry f : flowEntries.get(rule.deviceId())) {
299 - if (f.equals(rule)) {
300 - return f;
301 - }
302 - }
303 - } finally {
304 - flowEntriesLock.readLock().unlock();
305 - }
306 - return null;
307 - }
308 295
309 @Override 296 @Override
310 public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) { 297 public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
...@@ -317,7 +304,7 @@ public class DistributedFlowRuleStore ...@@ -317,7 +304,7 @@ public class DistributedFlowRuleStore
317 } 304 }
318 305
319 if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { 306 if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
320 - return getFlowEntriesInternal(deviceId); 307 + return flowTable.getFlowEntries(deviceId);
321 } 308 }
322 309
323 log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}", 310 log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
...@@ -337,30 +324,26 @@ public class DistributedFlowRuleStore ...@@ -337,30 +324,26 @@ public class DistributedFlowRuleStore
337 return Collections.emptyList(); 324 return Collections.emptyList();
338 } 325 }
339 326
340 - private Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) { 327 +
341 - flowEntriesLock.readLock().lock();
342 - try {
343 - Collection<? extends FlowEntry> rules = flowEntries.get(deviceId);
344 - if (rules == null) {
345 - return Collections.emptySet();
346 - }
347 - return ImmutableSet.copyOf(rules);
348 - } finally {
349 - flowEntriesLock.readLock().unlock();
350 - }
351 - }
352 328
353 @Override 329 @Override
354 public void storeFlowRule(FlowRule rule) { 330 public void storeFlowRule(FlowRule rule) {
355 - storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)))); 331 + storeBatch(new FlowRuleBatchOperation(
332 + Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)),
333 + rule.deviceId(), idGenerator.getNewId()));
356 } 334 }
357 335
358 @Override 336 @Override
359 - public Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation operation) { 337 + public void storeBatch(FlowRuleBatchOperation operation) {
338 +
360 339
361 if (operation.getOperations().isEmpty()) { 340 if (operation.getOperations().isEmpty()) {
362 - return Futures.immediateFuture(new CompletedBatchOperation(true, 341 +
363 - Collections.<FlowRule>emptySet())); 342 + notifyDelegate(FlowRuleBatchEvent.completed(
343 + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()),
344 + new CompletedBatchOperation(true, Collections.emptySet(),
345 + operation.deviceId())));
346 + return;
364 } 347 }
365 348
366 DeviceId deviceId = operation.getOperations().get(0).target().deviceId(); 349 DeviceId deviceId = operation.getOperations().get(0).target().deviceId();
...@@ -369,14 +352,21 @@ public class DistributedFlowRuleStore ...@@ -369,14 +352,21 @@ public class DistributedFlowRuleStore
369 352
370 if (!replicaInfo.master().isPresent()) { 353 if (!replicaInfo.master().isPresent()) {
371 log.warn("Failed to storeBatch: No master for {}", deviceId); 354 log.warn("Failed to storeBatch: No master for {}", deviceId);
372 - // TODO: revisit if this should be "success" from Future point of view 355 +
373 - // with every FlowEntry failed 356 + Set<FlowRule> allFailures = operation.getOperations().stream()
374 - return Futures.immediateFailedFuture(new IOException("Failed to storeBatch: No master for " + deviceId)); 357 + .map(op -> op.getTarget())
358 + .collect(Collectors.toSet());
359 +
360 + notifyDelegate(FlowRuleBatchEvent.completed(
361 + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()),
362 + new CompletedBatchOperation(false, allFailures, operation.deviceId())));
363 + return;
375 } 364 }
376 365
377 final NodeId local = clusterService.getLocalNode().id(); 366 final NodeId local = clusterService.getLocalNode().id();
378 if (replicaInfo.master().get().equals(local)) { 367 if (replicaInfo.master().get().equals(local)) {
379 - return storeBatchInternal(operation); 368 + storeBatchInternal(operation);
369 + return;
380 } 370 }
381 371
382 log.trace("Forwarding storeBatch to {}, which is the primary (master) for device {}", 372 log.trace("Forwarding storeBatch to {}, which is the primary (master) for device {}",
...@@ -387,92 +377,104 @@ public class DistributedFlowRuleStore ...@@ -387,92 +377,104 @@ public class DistributedFlowRuleStore
387 APPLY_BATCH_FLOWS, 377 APPLY_BATCH_FLOWS,
388 SERIALIZER.encode(operation)); 378 SERIALIZER.encode(operation));
389 379
380 + //CompletedBatchOperation response;
390 try { 381 try {
391 ListenableFuture<byte[]> responseFuture = 382 ListenableFuture<byte[]> responseFuture =
392 clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); 383 clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
393 - return Futures.transform(responseFuture, new DecodeTo<CompletedBatchOperation>(SERIALIZER)); 384 + /*response =
394 - } catch (IOException e) { 385 + Futures.transform(responseFuture,
395 - return Futures.immediateFailedFuture(e); 386 + new DecodeTo<CompletedBatchOperation>(SERIALIZER))
387 + .get(500 * operation.size(), TimeUnit.MILLISECONDS);
388 +
389 + notifyDelegate(FlowRuleBatchEvent.completed(
390 + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), response));*/
391 +
392 + } catch (IOException /*| InterruptedException | ExecutionException | TimeoutException*/ e) {
393 + log.warn("Failed to storeBatch: {}", e.getMessage());
394 +
395 + Set<FlowRule> allFailures = operation.getOperations().stream()
396 + .map(op -> op.getTarget())
397 + .collect(Collectors.toSet());
398 +
399 + notifyDelegate(FlowRuleBatchEvent.completed(
400 + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()),
401 + new CompletedBatchOperation(false, allFailures, deviceId)));
402 + return;
396 } 403 }
404 +
397 } 405 }
398 406
399 - private ListenableFuture<CompletedBatchOperation> 407 + private void storeBatchInternal(FlowRuleBatchOperation operation) {
400 - storeBatchInternal(FlowRuleBatchOperation operation) {
401 408
402 - final List<FlowRuleBatchEntry> toRemove = new ArrayList<>(); 409 + final DeviceId did = operation.deviceId();
403 - final List<FlowRuleBatchEntry> toAdd = new ArrayList<>(); 410 + //final Collection<FlowEntry> ft = flowTable.getFlowEntries(did);
404 - DeviceId did = null; 411 + Set<FlowRuleBatchEntry> currentOps;
405 412
406 413
407 - flowEntriesLock.writeLock().lock(); 414 + currentOps = operation.getOperations().stream().map(
408 - try { 415 + op -> {
409 - for (FlowRuleBatchEntry batchEntry : operation.getOperations()) { 416 + StoredFlowEntry entry;
410 - FlowRule flowRule = batchEntry.target(); 417 + switch (op.getOperator()) {
411 - FlowRuleOperation op = batchEntry.operator(); 418 + case ADD:
412 - if (did == null) { 419 + entry = new DefaultFlowEntry(op.getTarget());
413 - did = flowRule.deviceId(); 420 + // always add requested FlowRule

414 - } 421 + // Note: 2 equal FlowEntry may have different treatment
415 - if (op.equals(FlowRuleOperation.REMOVE)) { 422 + flowTable.remove(entry.deviceId(), entry);
416 - StoredFlowEntry entry = getFlowEntryInternal(flowRule); 423 + flowTable.add(entry);
424 +
425 + return op;
426 + case REMOVE:
427 + entry = flowTable.getFlowEntry(op.target());
417 if (entry != null) { 428 if (entry != null) {
418 entry.setState(FlowEntryState.PENDING_REMOVE); 429 entry.setState(FlowEntryState.PENDING_REMOVE);
419 - toRemove.add(batchEntry); 430 + return op;
420 } 431 }
421 - } else if (op.equals(FlowRuleOperation.ADD)) { 432 + break;
422 - StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); 433 + case MODIFY:
423 - DeviceId deviceId = flowRule.deviceId(); 434 + //TODO: figure this out at some point
424 - Collection<StoredFlowEntry> ft = flowEntries.get(deviceId); 435 + break;
425 - 436 + default:
426 - // always add requested FlowRule 437 + log.warn("Unknown flow operation operator: {}", op.getOperator());
427 - // Note: 2 equal FlowEntry may have different treatment
428 - ft.remove(flowEntry);
429 - ft.add(flowEntry);
430 - toAdd.add(batchEntry);
431 } 438 }
439 + return null;
432 } 440 }
433 - if (toAdd.isEmpty() && toRemove.isEmpty()) { 441 + ).filter(op -> op != null).collect(Collectors.toSet());
434 - return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowRule>emptySet())); 442 + if (currentOps.isEmpty()) {
443 + batchOperationComplete(FlowRuleBatchEvent.completed(
444 + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()),
445 + new CompletedBatchOperation(true, Collections.emptySet(), did)));
446 + return;
435 } 447 }
448 + updateBackup(did, currentOps);
436 449
437 - // create remote backup copies
438 - updateBackup(did, toAdd, toRemove);
439 - } finally {
440 - flowEntriesLock.writeLock().unlock();
441 - }
442 450
443 - SettableFuture<CompletedBatchOperation> r = SettableFuture.create(); 451 + notifyDelegate(FlowRuleBatchEvent.requested(new
444 - final int batchId = localBatchIdGen.incrementAndGet(); 452 + FlowRuleBatchRequest(operation.id(), currentOps), operation.deviceId()));
445 453
446 - pendingFutures.put(batchId, r);
447 - notifyDelegate(FlowRuleBatchEvent.requested(new FlowRuleBatchRequest(batchId, toAdd, toRemove)));
448 454
449 - return r;
450 } 455 }
451 456
452 - private void updateBackup(final DeviceId deviceId, 457 + private void updateBackup(DeviceId deviceId, final Set<FlowRuleBatchEntry> entries) {
453 - final List<FlowRuleBatchEntry> toAdd, 458 + Future<?> backup = backupExecutors.submit(new UpdateBackup(deviceId, entries));
454 - final List<FlowRuleBatchEntry> list) {
455 -
456 - Future<?> submit = backupExecutors.submit(new UpdateBackup(deviceId, toAdd, list));
457 459
458 if (syncBackup) { 460 if (syncBackup) {
459 // wait for backup to complete 461 // wait for backup to complete
460 try { 462 try {
461 - submit.get(); 463 + backup.get();
462 } catch (InterruptedException | ExecutionException e) { 464 } catch (InterruptedException | ExecutionException e) {
463 log.error("Failed to create backups", e); 465 log.error("Failed to create backups", e);
464 } 466 }
465 } 467 }
466 } 468 }
467 469
468 - private void updateBackup(DeviceId deviceId, List<FlowRuleBatchEntry> toAdd) {
469 -
470 - updateBackup(deviceId, toAdd, Collections.<FlowRuleBatchEntry>emptyList());
471 - }
472 -
473 @Override 470 @Override
474 public void deleteFlowRule(FlowRule rule) { 471 public void deleteFlowRule(FlowRule rule) {
475 - storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)))); 472 + storeBatch(
473 + new FlowRuleBatchOperation(
474 + Arrays.asList(
475 + new FlowRuleBatchEntry(
476 + FlowRuleOperation.REMOVE,
477 + rule)), rule.deviceId(), idGenerator.getNewId()));
476 } 478 }
477 479
478 @Override 480 @Override
...@@ -491,10 +493,9 @@ public class DistributedFlowRuleStore ...@@ -491,10 +493,9 @@ public class DistributedFlowRuleStore
491 private FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) { 493 private FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) {
492 final DeviceId did = rule.deviceId(); 494 final DeviceId did = rule.deviceId();
493 495
494 - flowEntriesLock.writeLock().lock(); 496 +
495 - try {
496 // check if this new rule is an update to an existing entry 497 // check if this new rule is an update to an existing entry
497 - StoredFlowEntry stored = getFlowEntryInternal(rule); 498 + StoredFlowEntry stored = flowTable.getFlowEntry(rule);
498 if (stored != null) { 499 if (stored != null) {
499 stored.setBytes(rule.bytes()); 500 stored.setBytes(rule.bytes());
500 stored.setLife(rule.life()); 501 stored.setLife(rule.life());
...@@ -503,7 +504,7 @@ public class DistributedFlowRuleStore ...@@ -503,7 +504,7 @@ public class DistributedFlowRuleStore
503 stored.setState(FlowEntryState.ADDED); 504 stored.setState(FlowEntryState.ADDED);
504 FlowRuleBatchEntry entry = 505 FlowRuleBatchEntry entry =
505 new FlowRuleBatchEntry(FlowRuleOperation.ADD, stored); 506 new FlowRuleBatchEntry(FlowRuleOperation.ADD, stored);
506 - updateBackup(did, Arrays.asList(entry)); 507 + updateBackup(did, Sets.newHashSet(entry));
507 return new FlowRuleEvent(Type.RULE_ADDED, rule); 508 return new FlowRuleEvent(Type.RULE_ADDED, rule);
508 } 509 }
509 return new FlowRuleEvent(Type.RULE_UPDATED, rule); 510 return new FlowRuleEvent(Type.RULE_UPDATED, rule);
...@@ -511,10 +512,9 @@ public class DistributedFlowRuleStore ...@@ -511,10 +512,9 @@ public class DistributedFlowRuleStore
511 512
512 // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore 513 // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore
513 // TODO: also update backup if the behavior is correct. 514 // TODO: also update backup if the behavior is correct.
514 - flowEntries.put(did, new DefaultFlowEntry(rule)); 515 + flowTable.add(rule);
515 - } finally { 516 +
516 - flowEntriesLock.writeLock().unlock(); 517 +
517 - }
518 return null; 518 return null;
519 519
520 } 520 }
...@@ -555,38 +555,42 @@ public class DistributedFlowRuleStore ...@@ -555,38 +555,42 @@ public class DistributedFlowRuleStore
555 555
556 private FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) { 556 private FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) {
557 final DeviceId deviceId = rule.deviceId(); 557 final DeviceId deviceId = rule.deviceId();
558 - flowEntriesLock.writeLock().lock();
559 - try {
560 // This is where one could mark a rule as removed and still keep it in the store. 558 // This is where one could mark a rule as removed and still keep it in the store.
561 - final boolean removed = flowEntries.remove(deviceId, rule); 559 + final boolean removed = flowTable.remove(deviceId, rule); //flowEntries.remove(deviceId, rule);
562 FlowRuleBatchEntry entry = 560 FlowRuleBatchEntry entry =
563 new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule); 561 new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule);
564 - updateBackup(deviceId, Collections.<FlowRuleBatchEntry>emptyList(), Arrays.asList(entry)); 562 + updateBackup(deviceId, Sets.newHashSet(entry));
565 if (removed) { 563 if (removed) {
566 return new FlowRuleEvent(RULE_REMOVED, rule); 564 return new FlowRuleEvent(RULE_REMOVED, rule);
567 } else { 565 } else {
568 return null; 566 return null;
569 } 567 }
570 - } finally { 568 +
571 - flowEntriesLock.writeLock().unlock();
572 - }
573 } 569 }
574 570
575 @Override 571 @Override
576 public void batchOperationComplete(FlowRuleBatchEvent event) { 572 public void batchOperationComplete(FlowRuleBatchEvent event) {
577 - final Integer batchId = event.subject().batchId(); 573 + //FIXME: need a per device pending response
578 - SettableFuture<CompletedBatchOperation> future 574 +
579 - = pendingFutures.getIfPresent(batchId); 575 + NodeId nodeId = pendingResponses.remove(event.subject().batchId());
580 - if (future != null) { 576 + if (nodeId == null) {
581 - future.set(event.result());
582 - pendingFutures.invalidate(batchId);
583 - }
584 notifyDelegate(event); 577 notifyDelegate(event);
578 + } else {
579 + try {
580 + ClusterMessage message = new ClusterMessage(
581 + clusterService.getLocalNode().id(),
582 + REMOTE_APPLY_COMPLETED,
583 + SERIALIZER.encode(event));
584 + clusterCommunicator.sendAndReceive(message, nodeId);
585 + } catch (IOException e) {
586 + log.warn("Failed to respond to peer for batch operation result");
587 + }
588 + }
585 } 589 }
586 590
587 private void loadFromBackup(final DeviceId did) { 591 private void loadFromBackup(final DeviceId did) {
588 592
589 - flowEntriesLock.writeLock().lock(); 593 +
590 try { 594 try {
591 log.debug("Loading FlowRules for {} from backups", did); 595 log.debug("Loading FlowRules for {} from backups", did);
592 SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(did); 596 SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(did);
...@@ -595,38 +599,21 @@ public class DistributedFlowRuleStore ...@@ -595,38 +599,21 @@ public class DistributedFlowRuleStore
595 599
596 log.trace("loading {}", e.getValue()); 600 log.trace("loading {}", e.getValue());
597 for (StoredFlowEntry entry : e.getValue()) { 601 for (StoredFlowEntry entry : e.getValue()) {
598 - flowEntries.remove(did, entry); 602 + flowTable.getFlowEntriesById(entry).remove(entry);
599 - flowEntries.put(did, entry); 603 + flowTable.getFlowEntriesById(entry).add(entry);
604 +
605 +
600 } 606 }
601 } 607 }
602 } catch (ExecutionException e) { 608 } catch (ExecutionException e) {
603 log.error("Failed to load backup flowtable for {}", did, e); 609 log.error("Failed to load backup flowtable for {}", did, e);
604 - } finally {
605 - flowEntriesLock.writeLock().unlock();
606 } 610 }
607 } 611 }
608 612
609 private void removeFromPrimary(final DeviceId did) { 613 private void removeFromPrimary(final DeviceId did) {
610 - Collection<StoredFlowEntry> removed = null; 614 + flowTable.clearDevice(did);
611 - flowEntriesLock.writeLock().lock();
612 - try {
613 - removed = flowEntries.removeAll(did);
614 - } finally {
615 - flowEntriesLock.writeLock().unlock();
616 - }
617 - log.trace("removedFromPrimary {}", removed);
618 } 615 }
619 616
620 - private static final class TimeoutFuture
621 - implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> {
622 - @Override
623 - public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) {
624 - // wrapping in ExecutionException to support Future.get
625 - notification.getValue()
626 - .setException(new ExecutionException("Timed out",
627 - new TimeoutException()));
628 - }
629 - }
630 617
631 private final class OnStoreBatch implements ClusterMessageHandler { 618 private final class OnStoreBatch implements ClusterMessageHandler {
632 private final NodeId local; 619 private final NodeId local;
...@@ -640,7 +627,7 @@ public class DistributedFlowRuleStore ...@@ -640,7 +627,7 @@ public class DistributedFlowRuleStore
640 FlowRuleBatchOperation operation = SERIALIZER.decode(message.payload()); 627 FlowRuleBatchOperation operation = SERIALIZER.decode(message.payload());
641 log.debug("received batch request {}", operation); 628 log.debug("received batch request {}", operation);
642 629
643 - final DeviceId deviceId = operation.getOperations().get(0).target().deviceId(); 630 + final DeviceId deviceId = operation.deviceId();
644 ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); 631 ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId);
645 if (!local.equals(replicaInfo.master().orNull())) { 632 if (!local.equals(replicaInfo.master().orNull())) {
646 633
...@@ -648,7 +635,7 @@ public class DistributedFlowRuleStore ...@@ -648,7 +635,7 @@ public class DistributedFlowRuleStore
648 for (FlowRuleBatchEntry op : operation.getOperations()) { 635 for (FlowRuleBatchEntry op : operation.getOperations()) {
649 failures.add(op.target()); 636 failures.add(op.target());
650 } 637 }
651 - CompletedBatchOperation allFailed = new CompletedBatchOperation(false, failures); 638 + CompletedBatchOperation allFailed = new CompletedBatchOperation(false, failures, deviceId);
652 // This node is no longer the master, respond as all failed. 639 // This node is no longer the master, respond as all failed.
653 // TODO: we might want to wrap response in envelope 640 // TODO: we might want to wrap response in envelope
654 // to distinguish sw programming failure and hand over 641 // to distinguish sw programming failure and hand over
...@@ -661,31 +648,10 @@ public class DistributedFlowRuleStore ...@@ -661,31 +648,10 @@ public class DistributedFlowRuleStore
661 return; 648 return;
662 } 649 }
663 650
664 - final ListenableFuture<CompletedBatchOperation> f = storeBatchInternal(operation);
665 651
666 - f.addListener(new Runnable() { 652 + pendingResponses.put(operation.id(), message.sender());
653 + storeBatchInternal(operation);
667 654
668 - @Override
669 - public void run() {
670 - CompletedBatchOperation result;
671 - try {
672 - result = f.get();
673 - } catch (InterruptedException | ExecutionException e) {
674 - log.error("Batch operation failed", e);
675 - // create everything failed response
676 - Set<FlowRule> failures = new HashSet<>(operation.size());
677 - for (FlowRuleBatchEntry op : operation.getOperations()) {
678 - failures.add(op.target());
679 - }
680 - result = new CompletedBatchOperation(false, failures);
681 - }
682 - try {
683 - message.respond(SERIALIZER.encode(result));
684 - } catch (IOException e) {
685 - log.error("Failed to respond back", e);
686 - }
687 - }
688 - }, futureListeners);
689 } 655 }
690 } 656 }
691 657
...@@ -731,39 +697,40 @@ public class DistributedFlowRuleStore ...@@ -731,39 +697,40 @@ public class DistributedFlowRuleStore
731 } 697 }
732 698
733 // Task to update FlowEntries in backup HZ store 699 // Task to update FlowEntries in backup HZ store
734 - // TODO: Should be refactored to contain only one list and not
735 - // toAdd and toRemove
736 private final class UpdateBackup implements Runnable { 700 private final class UpdateBackup implements Runnable {
737 701
738 private final DeviceId deviceId; 702 private final DeviceId deviceId;
739 - private final List<FlowRuleBatchEntry> toAdd; 703 + private final Set<FlowRuleBatchEntry> ops;
740 - private final List<FlowRuleBatchEntry> toRemove; 704 +
741 705
742 public UpdateBackup(DeviceId deviceId, 706 public UpdateBackup(DeviceId deviceId,
743 - List<FlowRuleBatchEntry> toAdd, 707 + Set<FlowRuleBatchEntry> ops) {
744 - List<FlowRuleBatchEntry> list) {
745 this.deviceId = checkNotNull(deviceId); 708 this.deviceId = checkNotNull(deviceId);
746 - this.toAdd = checkNotNull(toAdd); 709 + this.ops = checkNotNull(ops);
747 - this.toRemove = checkNotNull(list); 710 +
748 } 711 }
749 712
750 @Override 713 @Override
751 public void run() { 714 public void run() {
752 try { 715 try {
753 - log.trace("update backup {} +{} -{}", deviceId, toAdd, toRemove); 716 + log.trace("update backup {} {}", deviceId, ops
717 + );
754 final SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(deviceId); 718 final SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(deviceId);
755 - // Following should be rewritten using async APIs 719 +
756 - for (FlowRuleBatchEntry bEntry : toAdd) { 720 +
757 - final FlowRule entry = bEntry.target(); 721 + ops.stream().forEach(
722 + op -> {
723 + final FlowRule entry = op.getTarget();
758 final FlowId id = entry.id(); 724 final FlowId id = entry.id();
759 ImmutableList<StoredFlowEntry> original = backupFlowTable.get(id); 725 ImmutableList<StoredFlowEntry> original = backupFlowTable.get(id);
760 List<StoredFlowEntry> list = new ArrayList<>(); 726 List<StoredFlowEntry> list = new ArrayList<>();
761 if (original != null) { 727 if (original != null) {
762 list.addAll(original); 728 list.addAll(original);
763 } 729 }
764 - 730 + list.remove(op.getTarget());
765 - list.remove(bEntry.target()); 731 + if (op.getOperator() == FlowRuleOperation.ADD) {
766 list.add((StoredFlowEntry) entry); 732 list.add((StoredFlowEntry) entry);
733 + }
767 734
768 ImmutableList<StoredFlowEntry> newValue = ImmutableList.copyOf(list); 735 ImmutableList<StoredFlowEntry> newValue = ImmutableList.copyOf(list);
769 boolean success; 736 boolean success;
...@@ -775,33 +742,100 @@ public class DistributedFlowRuleStore ...@@ -775,33 +742,100 @@ public class DistributedFlowRuleStore
775 if (!success) { 742 if (!success) {
776 log.error("Updating backup failed."); 743 log.error("Updating backup failed.");
777 } 744 }
745 +
778 } 746 }
779 - for (FlowRuleBatchEntry bEntry : toRemove) { 747 + );
780 - final FlowRule entry = bEntry.target(); 748 + } catch (ExecutionException e) {
781 - final FlowId id = entry.id(); 749 + log.error("Failed to write to backups", e);
782 - ImmutableList<StoredFlowEntry> original = backupFlowTable.get(id);
783 - List<StoredFlowEntry> list = new ArrayList<>();
784 - if (original != null) {
785 - list.addAll(original);
786 } 750 }
787 751
788 - list.remove(bEntry.target()); 752 + }
753 + }
789 754
790 - ImmutableList<StoredFlowEntry> newValue = ImmutableList.copyOf(list); 755 + private class InternalFlowTable {
791 - boolean success; 756 +
792 - if (original == null) { 757 + /*
793 - success = (backupFlowTable.putIfAbsent(id, newValue) == null); 758 + TODO: This needs to be cleaned up. Perhaps using the eventually consistent
794 - } else { 759 + map when it supports distributed to a sequence of instances.
795 - success = backupFlowTable.replace(id, original, newValue); 760 + */
761 +
762 +
763 + private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, Set<StoredFlowEntry>>>
764 + flowEntries = new ConcurrentHashMap<>();
765 +
766 +
767 + private NewConcurrentHashMap<FlowId, Set<StoredFlowEntry>> lazyEmptyFlowTable() {
768 + return NewConcurrentHashMap.<FlowId, Set<StoredFlowEntry>>ifNeeded();
796 } 769 }
797 - if (!success) { 770 +
798 - log.error("Updating backup failed."); 771 + /**
772 + * Returns the flow table for specified device.
773 + *
774 + * @param deviceId identifier of the device
775 + * @return Map representing Flow Table of given device.
776 + */
777 + private ConcurrentMap<FlowId, Set<StoredFlowEntry>> getFlowTable(DeviceId deviceId) {
778 + return createIfAbsentUnchecked(flowEntries,
779 + deviceId, lazyEmptyFlowTable());
799 } 780 }
781 +
782 + private Set<StoredFlowEntry> getFlowEntriesInternal(DeviceId deviceId, FlowId flowId) {
783 + final ConcurrentMap<FlowId, Set<StoredFlowEntry>> flowTable = getFlowTable(deviceId);
784 + Set<StoredFlowEntry> r = flowTable.get(flowId);
785 + if (r == null) {
786 + final Set<StoredFlowEntry> concurrentlyAdded;
787 + r = new CopyOnWriteArraySet<>();
788 + concurrentlyAdded = flowTable.putIfAbsent(flowId, r);
789 + if (concurrentlyAdded != null) {
790 + return concurrentlyAdded;
800 } 791 }
801 - } catch (ExecutionException e) { 792 + }
802 - log.error("Failed to write to backups", e); 793 + return r;
803 } 794 }
804 795
796 + private StoredFlowEntry getFlowEntryInternal(FlowRule rule) {
797 + for (StoredFlowEntry f : getFlowEntriesInternal(rule.deviceId(), rule.id())) {
798 + if (f.equals(rule)) {
799 + return f;
800 + }
801 + }
802 + return null;
803 + }
804 +
805 + private Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) {
806 + return getFlowTable(deviceId).values().stream()
807 + .flatMap((list -> list.stream())).collect(Collectors.toSet());
808 +
805 } 809 }
810 +
811 +
812 + public StoredFlowEntry getFlowEntry(FlowRule rule) {
813 + return getFlowEntryInternal(rule);
806 } 814 }
815 +
816 + public Set<FlowEntry> getFlowEntries(DeviceId deviceId) {
817 + return getFlowEntriesInternal(deviceId);
818 + }
819 +
820 + public Set<StoredFlowEntry> getFlowEntriesById(FlowEntry entry) {
821 + return getFlowEntriesInternal(entry.deviceId(), entry.id());
822 + }
823 +
824 + public void add(FlowEntry rule) {
825 + ((CopyOnWriteArraySet)
826 + getFlowEntriesInternal(rule.deviceId(), rule.id())).add(rule);
827 + }
828 +
829 + public boolean remove(DeviceId deviceId, FlowEntry rule) {
830 + return ((CopyOnWriteArraySet)
831 + getFlowEntriesInternal(deviceId, rule.id())).remove(rule);
832 + //return flowEntries.remove(deviceId, rule);
833 + }
834 +
835 + public void clearDevice(DeviceId did) {
836 + flowEntries.remove(did);
837 + }
838 + }
839 +
840 +
807 } 841 }
......
...@@ -34,4 +34,7 @@ public final class FlowStoreMessageSubjects { ...@@ -34,4 +34,7 @@ public final class FlowStoreMessageSubjects {
34 34
35 public static final MessageSubject REMOVE_FLOW_ENTRY 35 public static final MessageSubject REMOVE_FLOW_ENTRY
36 = new MessageSubject("peer-forward-remove-flow-entry"); 36 = new MessageSubject("peer-forward-remove-flow-entry");
37 +
38 + public static final MessageSubject REMOTE_APPLY_COMPLETED
39 + = new MessageSubject("peer-apply-completed");
37 } 40 }
......
...@@ -59,15 +59,17 @@ import org.onosproject.net.PortNumber; ...@@ -59,15 +59,17 @@ import org.onosproject.net.PortNumber;
59 import org.onosproject.net.device.DefaultDeviceDescription; 59 import org.onosproject.net.device.DefaultDeviceDescription;
60 import org.onosproject.net.device.DefaultPortDescription; 60 import org.onosproject.net.device.DefaultPortDescription;
61 import org.onosproject.net.flow.CompletedBatchOperation; 61 import org.onosproject.net.flow.CompletedBatchOperation;
62 -import org.onosproject.net.flow.FlowRule;
63 import org.onosproject.net.flow.DefaultFlowEntry; 62 import org.onosproject.net.flow.DefaultFlowEntry;
64 import org.onosproject.net.flow.DefaultFlowRule; 63 import org.onosproject.net.flow.DefaultFlowRule;
65 import org.onosproject.net.flow.DefaultTrafficSelector; 64 import org.onosproject.net.flow.DefaultTrafficSelector;
66 import org.onosproject.net.flow.DefaultTrafficTreatment; 65 import org.onosproject.net.flow.DefaultTrafficTreatment;
67 import org.onosproject.net.flow.FlowEntry; 66 import org.onosproject.net.flow.FlowEntry;
68 import org.onosproject.net.flow.FlowId; 67 import org.onosproject.net.flow.FlowId;
68 +import org.onosproject.net.flow.FlowRule;
69 import org.onosproject.net.flow.FlowRuleBatchEntry; 69 import org.onosproject.net.flow.FlowRuleBatchEntry;
70 +import org.onosproject.net.flow.FlowRuleBatchEvent;
70 import org.onosproject.net.flow.FlowRuleBatchOperation; 71 import org.onosproject.net.flow.FlowRuleBatchOperation;
72 +import org.onosproject.net.flow.FlowRuleBatchRequest;
71 import org.onosproject.net.flow.StoredFlowEntry; 73 import org.onosproject.net.flow.StoredFlowEntry;
72 import org.onosproject.net.flow.criteria.Criteria; 74 import org.onosproject.net.flow.criteria.Criteria;
73 import org.onosproject.net.flow.criteria.Criterion; 75 import org.onosproject.net.flow.criteria.Criterion;
...@@ -162,6 +164,7 @@ public final class KryoNamespaces { ...@@ -162,6 +164,7 @@ public final class KryoNamespaces {
162 .register(Collections.emptySet().getClass()) 164 .register(Collections.emptySet().getClass())
163 .register(Optional.class) 165 .register(Optional.class)
164 .register(Collections.emptyList().getClass()) 166 .register(Collections.emptyList().getClass())
167 + .register(Collections.unmodifiableSet(Collections.emptySet()).getClass())
165 .build(); 168 .build();
166 169
167 /** 170 /**
...@@ -255,6 +258,9 @@ public final class KryoNamespaces { ...@@ -255,6 +258,9 @@ public final class KryoNamespaces {
255 L3ModificationInstruction.L3SubType.class, 258 L3ModificationInstruction.L3SubType.class,
256 L3ModificationInstruction.ModIPInstruction.class, 259 L3ModificationInstruction.ModIPInstruction.class,
257 RoleInfo.class, 260 RoleInfo.class,
261 + FlowRuleBatchEvent.class,
262 + FlowRuleBatchEvent.Type.class,
263 + FlowRuleBatchRequest.class,
258 FlowRuleBatchOperation.class, 264 FlowRuleBatchOperation.class,
259 CompletedBatchOperation.class, 265 CompletedBatchOperation.class,
260 FlowRuleBatchEntry.class, 266 FlowRuleBatchEntry.class,
......
...@@ -21,13 +21,13 @@ import com.google.common.cache.CacheBuilder; ...@@ -21,13 +21,13 @@ import com.google.common.cache.CacheBuilder;
21 import com.google.common.cache.RemovalListener; 21 import com.google.common.cache.RemovalListener;
22 import com.google.common.cache.RemovalNotification; 22 import com.google.common.cache.RemovalNotification;
23 import com.google.common.collect.FluentIterable; 23 import com.google.common.collect.FluentIterable;
24 -import com.google.common.util.concurrent.Futures; 24 +import com.google.common.collect.Sets;
25 import com.google.common.util.concurrent.SettableFuture; 25 import com.google.common.util.concurrent.SettableFuture;
26 -
27 import org.apache.felix.scr.annotations.Activate; 26 import org.apache.felix.scr.annotations.Activate;
28 import org.apache.felix.scr.annotations.Component; 27 import org.apache.felix.scr.annotations.Component;
29 import org.apache.felix.scr.annotations.Deactivate; 28 import org.apache.felix.scr.annotations.Deactivate;
30 import org.apache.felix.scr.annotations.Service; 29 import org.apache.felix.scr.annotations.Service;
30 +import org.onlab.util.NewConcurrentHashMap;
31 import org.onosproject.net.DeviceId; 31 import org.onosproject.net.DeviceId;
32 import org.onosproject.net.flow.CompletedBatchOperation; 32 import org.onosproject.net.flow.CompletedBatchOperation;
33 import org.onosproject.net.flow.DefaultFlowEntry; 33 import org.onosproject.net.flow.DefaultFlowEntry;
...@@ -46,7 +46,6 @@ import org.onosproject.net.flow.FlowRuleStore; ...@@ -46,7 +46,6 @@ import org.onosproject.net.flow.FlowRuleStore;
46 import org.onosproject.net.flow.FlowRuleStoreDelegate; 46 import org.onosproject.net.flow.FlowRuleStoreDelegate;
47 import org.onosproject.net.flow.StoredFlowEntry; 47 import org.onosproject.net.flow.StoredFlowEntry;
48 import org.onosproject.store.AbstractStore; 48 import org.onosproject.store.AbstractStore;
49 -import org.onlab.util.NewConcurrentHashMap;
50 import org.slf4j.Logger; 49 import org.slf4j.Logger;
51 50
52 import java.util.ArrayList; 51 import java.util.ArrayList;
...@@ -56,7 +55,6 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -56,7 +55,6 @@ import java.util.concurrent.ConcurrentHashMap;
56 import java.util.concurrent.ConcurrentMap; 55 import java.util.concurrent.ConcurrentMap;
57 import java.util.concurrent.CopyOnWriteArrayList; 56 import java.util.concurrent.CopyOnWriteArrayList;
58 import java.util.concurrent.ExecutionException; 57 import java.util.concurrent.ExecutionException;
59 -import java.util.concurrent.Future;
60 import java.util.concurrent.TimeUnit; 58 import java.util.concurrent.TimeUnit;
61 import java.util.concurrent.TimeoutException; 59 import java.util.concurrent.TimeoutException;
62 import java.util.concurrent.atomic.AtomicInteger; 60 import java.util.concurrent.atomic.AtomicInteger;
...@@ -261,13 +259,14 @@ public class SimpleFlowRuleStore ...@@ -261,13 +259,14 @@ public class SimpleFlowRuleStore
261 } 259 }
262 260
263 @Override 261 @Override
264 - public Future<CompletedBatchOperation> storeBatch( 262 + public void storeBatch(
265 - FlowRuleBatchOperation batchOperation) { 263 + FlowRuleBatchOperation operation) {
266 List<FlowRuleBatchEntry> toAdd = new ArrayList<>(); 264 List<FlowRuleBatchEntry> toAdd = new ArrayList<>();
267 List<FlowRuleBatchEntry> toRemove = new ArrayList<>(); 265 List<FlowRuleBatchEntry> toRemove = new ArrayList<>();
268 - for (FlowRuleBatchEntry entry : batchOperation.getOperations()) { 266 +
269 - final FlowRule flowRule = entry.target(); 267 + for (FlowRuleBatchEntry entry : operation.getOperations()) {
270 - if (entry.operator().equals(FlowRuleOperation.ADD)) { 268 + final FlowRule flowRule = entry.getTarget();
269 + if (entry.getOperator().equals(FlowRuleOperation.ADD)) {
271 if (!getFlowEntries(flowRule.deviceId(), flowRule.id()).contains(flowRule)) { 270 if (!getFlowEntries(flowRule.deviceId(), flowRule.id()).contains(flowRule)) {
272 storeFlowRule(flowRule); 271 storeFlowRule(flowRule);
273 toAdd.add(entry); 272 toAdd.add(entry);
...@@ -283,21 +282,27 @@ public class SimpleFlowRuleStore ...@@ -283,21 +282,27 @@ public class SimpleFlowRuleStore
283 } 282 }
284 283
285 if (toAdd.isEmpty() && toRemove.isEmpty()) { 284 if (toAdd.isEmpty() && toRemove.isEmpty()) {
286 - return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowRule>emptySet())); 285 + notifyDelegate(FlowRuleBatchEvent.completed(
286 + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()),
287 + new CompletedBatchOperation(true, Collections.emptySet(),
288 + operation.deviceId())));
289 + return;
287 } 290 }
288 291
289 SettableFuture<CompletedBatchOperation> r = SettableFuture.create(); 292 SettableFuture<CompletedBatchOperation> r = SettableFuture.create();
290 final int batchId = localBatchIdGen.incrementAndGet(); 293 final int batchId = localBatchIdGen.incrementAndGet();
291 294
292 pendingFutures.put(batchId, r); 295 pendingFutures.put(batchId, r);
293 - notifyDelegate(FlowRuleBatchEvent.requested(new FlowRuleBatchRequest(batchId, toAdd, toRemove)));
294 296
295 - return r; 297 + toAdd.addAll(toRemove);
298 + notifyDelegate(FlowRuleBatchEvent.requested(
299 + new FlowRuleBatchRequest(batchId, Sets.newHashSet(toAdd)), operation.deviceId()));
300 +
296 } 301 }
297 302
298 @Override 303 @Override
299 public void batchOperationComplete(FlowRuleBatchEvent event) { 304 public void batchOperationComplete(FlowRuleBatchEvent event) {
300 - final Integer batchId = event.subject().batchId(); 305 + final Long batchId = event.subject().batchId();
301 SettableFuture<CompletedBatchOperation> future 306 SettableFuture<CompletedBatchOperation> future
302 = pendingFutures.getIfPresent(batchId); 307 = pendingFutures.getIfPresent(batchId);
303 if (future != null) { 308 if (future != null) {
......
...@@ -116,7 +116,7 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -116,7 +116,7 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
116 @Activate 116 @Activate
117 public void activate(ComponentContext context) { 117 public void activate(ComponentContext context) {
118 providerService = providerRegistry.register(this); 118 providerService = providerRegistry.register(this);
119 - if (modified(context)) { 119 + if (!modified(context)) {
120 deviceBuilder.submit(new DeviceCreator(true)); 120 deviceBuilder.submit(new DeviceCreator(true));
121 } 121 }
122 log.info("Started"); 122 log.info("Started");
...@@ -173,6 +173,9 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -173,6 +173,9 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
173 chgd |= true; 173 chgd |= true;
174 } 174 }
175 log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts); 175 log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts);
176 + if (chgd) {
177 + deviceBuilder.submit(new DeviceCreator(true));
178 + }
176 return chgd; 179 return chgd;
177 } 180 }
178 181
......
...@@ -15,9 +15,7 @@ ...@@ -15,9 +15,7 @@
15 */ 15 */
16 package org.onosproject.provider.nil.flow.impl; 16 package org.onosproject.provider.nil.flow.impl;
17 17
18 -import com.google.common.collect.HashMultimap; 18 +import com.google.common.collect.Sets;
19 -import com.google.common.collect.Multimap;
20 -import com.google.common.util.concurrent.Futures;
21 import org.apache.felix.scr.annotations.Activate; 19 import org.apache.felix.scr.annotations.Activate;
22 import org.apache.felix.scr.annotations.Component; 20 import org.apache.felix.scr.annotations.Component;
23 import org.apache.felix.scr.annotations.Deactivate; 21 import org.apache.felix.scr.annotations.Deactivate;
...@@ -29,12 +27,12 @@ import org.jboss.netty.util.TimerTask; ...@@ -29,12 +27,12 @@ import org.jboss.netty.util.TimerTask;
29 import org.onlab.util.Timer; 27 import org.onlab.util.Timer;
30 import org.onosproject.core.ApplicationId; 28 import org.onosproject.core.ApplicationId;
31 import org.onosproject.net.DeviceId; 29 import org.onosproject.net.DeviceId;
32 -import org.onosproject.net.flow.BatchOperation;
33 import org.onosproject.net.flow.CompletedBatchOperation; 30 import org.onosproject.net.flow.CompletedBatchOperation;
34 import org.onosproject.net.flow.DefaultFlowEntry; 31 import org.onosproject.net.flow.DefaultFlowEntry;
35 import org.onosproject.net.flow.FlowEntry; 32 import org.onosproject.net.flow.FlowEntry;
36 import org.onosproject.net.flow.FlowRule; 33 import org.onosproject.net.flow.FlowRule;
37 import org.onosproject.net.flow.FlowRuleBatchEntry; 34 import org.onosproject.net.flow.FlowRuleBatchEntry;
35 +import org.onosproject.net.flow.FlowRuleBatchOperation;
38 import org.onosproject.net.flow.FlowRuleProvider; 36 import org.onosproject.net.flow.FlowRuleProvider;
39 import org.onosproject.net.flow.FlowRuleProviderRegistry; 37 import org.onosproject.net.flow.FlowRuleProviderRegistry;
40 import org.onosproject.net.flow.FlowRuleProviderService; 38 import org.onosproject.net.flow.FlowRuleProviderService;
...@@ -43,7 +41,9 @@ import org.onosproject.net.provider.ProviderId; ...@@ -43,7 +41,9 @@ import org.onosproject.net.provider.ProviderId;
43 import org.slf4j.Logger; 41 import org.slf4j.Logger;
44 42
45 import java.util.Collections; 43 import java.util.Collections;
46 -import java.util.concurrent.Future; 44 +import java.util.Set;
45 +import java.util.concurrent.ConcurrentHashMap;
46 +import java.util.concurrent.ConcurrentMap;
47 import java.util.concurrent.TimeUnit; 47 import java.util.concurrent.TimeUnit;
48 48
49 import static org.slf4j.LoggerFactory.getLogger; 49 import static org.slf4j.LoggerFactory.getLogger;
...@@ -59,7 +59,7 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -59,7 +59,7 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 protected FlowRuleProviderRegistry providerRegistry; 60 protected FlowRuleProviderRegistry providerRegistry;
61 61
62 - private Multimap<DeviceId, FlowEntry> flowTable = HashMultimap.create(); 62 + private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>();
63 63
64 private FlowRuleProviderService providerService; 64 private FlowRuleProviderService providerService;
65 65
...@@ -88,18 +88,10 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -88,18 +88,10 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
88 } 88 }
89 89
90 @Override 90 @Override
91 - public void applyFlowRule(FlowRule... flowRules) { 91 + public void applyFlowRule(FlowRule... flowRules) {}
92 - for (int i = 0; i < flowRules.length; i++) {
93 - flowTable.put(flowRules[i].deviceId(), new DefaultFlowEntry(flowRules[i]));
94 - }
95 - }
96 92
97 @Override 93 @Override
98 - public void removeFlowRule(FlowRule... flowRules) { 94 + public void removeFlowRule(FlowRule... flowRules) {}
99 - for (int i = 0; i < flowRules.length; i++) {
100 - flowTable.remove(flowRules[i].deviceId(), flowRules[i]);
101 - }
102 - }
103 95
104 @Override 96 @Override
105 public void removeRulesById(ApplicationId id, FlowRule... flowRules) { 97 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
...@@ -107,26 +99,32 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -107,26 +99,32 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
107 } 99 }
108 100
109 @Override 101 @Override
110 - public Future<CompletedBatchOperation> executeBatch( 102 + public void executeBatch(
111 - BatchOperation<FlowRuleBatchEntry> batch) { 103 + FlowRuleBatchOperation batch) {
104 + Set<FlowEntry> flowRules = flowTable.getOrDefault(batch.deviceId(), Sets.newConcurrentHashSet());
112 for (FlowRuleBatchEntry fbe : batch.getOperations()) { 105 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
113 switch (fbe.operator()) { 106 switch (fbe.operator()) {
114 case ADD: 107 case ADD:
115 - applyFlowRule(fbe.target()); 108 + flowRules.add(new DefaultFlowEntry(fbe.target()));
116 break; 109 break;
117 case REMOVE: 110 case REMOVE:
118 - removeFlowRule(fbe.target()); 111 + flowRules.remove(new DefaultFlowEntry(fbe.target()));
119 break; 112 break;
120 case MODIFY: 113 case MODIFY:
121 - removeFlowRule(fbe.target()); 114 + FlowEntry entry = new DefaultFlowEntry(fbe.target());
122 - applyFlowRule(fbe.target()); 115 + flowRules.remove(entry);
116 + flowRules.add(entry);
123 break; 117 break;
124 default: 118 default:
125 log.error("Unknown flow operation: {}", fbe); 119 log.error("Unknown flow operation: {}", fbe);
126 } 120 }
127 } 121 }
128 - return Futures.immediateFuture( 122 + flowTable.put(batch.deviceId(), flowRules);
129 - new CompletedBatchOperation(true, Collections.emptySet())); 123 + providerService.batchOperationCompleted(batch.id(),
124 + new CompletedBatchOperation(
125 + true,
126 + Collections.emptySet(),
127 + batch.deviceId()));
130 } 128 }
131 129
132 private class StatisticTask implements TimerTask { 130 private class StatisticTask implements TimerTask {
...@@ -134,10 +132,11 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -134,10 +132,11 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
134 @Override 132 @Override
135 public void run(Timeout to) throws Exception { 133 public void run(Timeout to) throws Exception {
136 for (DeviceId devId : flowTable.keySet()) { 134 for (DeviceId devId : flowTable.keySet()) {
137 - providerService.pushFlowMetrics(devId, flowTable.get(devId)); 135 + providerService.pushFlowMetrics(devId,
136 + flowTable.getOrDefault(devId, Collections.emptySet()));
138 } 137 }
139 -
140 timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS); 138 timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS);
139 +
141 } 140 }
142 } 141 }
143 } 142 }
......
...@@ -35,6 +35,7 @@ import org.onosproject.net.flow.FlowRule; ...@@ -35,6 +35,7 @@ import org.onosproject.net.flow.FlowRule;
35 import org.onosproject.net.flow.TrafficSelector; 35 import org.onosproject.net.flow.TrafficSelector;
36 import org.onosproject.net.flow.TrafficTreatment; 36 import org.onosproject.net.flow.TrafficTreatment;
37 import org.onosproject.openflow.controller.Dpid; 37 import org.onosproject.openflow.controller.Dpid;
38 +import org.projectfloodlight.openflow.protocol.OFFlowMod;
38 import org.projectfloodlight.openflow.protocol.OFFlowRemoved; 39 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
39 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; 40 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
40 import org.projectfloodlight.openflow.protocol.OFInstructionType; 41 import org.projectfloodlight.openflow.protocol.OFInstructionType;
...@@ -74,13 +75,16 @@ public class FlowEntryBuilder { ...@@ -74,13 +75,16 @@ public class FlowEntryBuilder {
74 75
75 private final OFFlowStatsEntry stat; 76 private final OFFlowStatsEntry stat;
76 private final OFFlowRemoved removed; 77 private final OFFlowRemoved removed;
78 + private final OFFlowMod flowMod;
77 79
78 private final Match match; 80 private final Match match;
79 private final List<OFAction> actions; 81 private final List<OFAction> actions;
80 82
81 private final Dpid dpid; 83 private final Dpid dpid;
82 84
83 - private final boolean addedRule; 85 + public enum FlowType { STAT, REMOVED, MOD }
86 +
87 + private final FlowType type;
84 88
85 89
86 public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) { 90 public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) {
...@@ -89,7 +93,8 @@ public class FlowEntryBuilder { ...@@ -89,7 +93,8 @@ public class FlowEntryBuilder {
89 this.actions = getActions(entry); 93 this.actions = getActions(entry);
90 this.dpid = dpid; 94 this.dpid = dpid;
91 this.removed = null; 95 this.removed = null;
92 - this.addedRule = true; 96 + this.flowMod = null;
97 + this.type = FlowType.STAT;
93 } 98 }
94 99
95 public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) { 100 public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) {
...@@ -99,26 +104,48 @@ public class FlowEntryBuilder { ...@@ -99,26 +104,48 @@ public class FlowEntryBuilder {
99 this.dpid = dpid; 104 this.dpid = dpid;
100 this.actions = null; 105 this.actions = null;
101 this.stat = null; 106 this.stat = null;
102 - this.addedRule = false; 107 + this.flowMod = null;
108 + this.type = FlowType.REMOVED;
109 +
110 + }
103 111
112 + public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) {
113 + this.match = fm.getMatch();
114 + this.dpid = dpid;
115 + this.actions = fm.getActions();
116 + this.type = FlowType.MOD;
117 + this.flowMod = fm;
118 + this.stat = null;
119 + this.removed = null;
104 } 120 }
105 121
106 - public FlowEntry build() { 122 + public FlowEntry build(FlowEntryState... state) {
107 - if (addedRule) { 123 + FlowRule rule;
108 - FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), 124 + switch (this.type) {
125 + case STAT:
126 + rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
109 buildSelector(), buildTreatment(), stat.getPriority(), 127 buildSelector(), buildTreatment(), stat.getPriority(),
110 stat.getCookie().getValue(), stat.getIdleTimeout(), false); 128 stat.getCookie().getValue(), stat.getIdleTimeout(), false);
111 return new DefaultFlowEntry(rule, FlowEntryState.ADDED, 129 return new DefaultFlowEntry(rule, FlowEntryState.ADDED,
112 stat.getDurationSec(), stat.getPacketCount().getValue(), 130 stat.getDurationSec(), stat.getPacketCount().getValue(),
113 stat.getByteCount().getValue()); 131 stat.getByteCount().getValue());
114 - 132 + case REMOVED:
115 - } else { 133 + rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
116 - FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
117 buildSelector(), null, removed.getPriority(), 134 buildSelector(), null, removed.getPriority(),
118 removed.getCookie().getValue(), removed.getIdleTimeout(), false); 135 removed.getCookie().getValue(), removed.getIdleTimeout(), false);
119 return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(), 136 return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(),
120 removed.getPacketCount().getValue(), removed.getByteCount().getValue()); 137 removed.getPacketCount().getValue(), removed.getByteCount().getValue());
138 + case MOD:
139 + FlowEntryState flowState = state.length > 0 ? state[0] : FlowEntryState.FAILED;
140 + rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
141 + buildSelector(), buildTreatment(), flowMod.getPriority(),
142 + flowMod.getCookie().getValue(), flowMod.getIdleTimeout(), false);
143 + return new DefaultFlowEntry(rule, flowState, 0, 0, 0);
144 + default:
145 + log.error("Unknown flow type : {}", this.type);
146 + return null;
121 } 147 }
148 +
122 } 149 }
123 150
124 private List<OFAction> getActions(OFFlowStatsEntry entry) { 151 private List<OFAction> getActions(OFFlowStatsEntry entry) {
......
...@@ -15,25 +15,13 @@ ...@@ -15,25 +15,13 @@
15 */ 15 */
16 package org.onosproject.provider.of.flow.impl; 16 package org.onosproject.provider.of.flow.impl;
17 17
18 -import static com.google.common.base.Preconditions.checkState;
19 -import static org.slf4j.LoggerFactory.getLogger;
20 -
21 -import java.util.Collections;
22 -import java.util.HashMap;
23 -import java.util.List;
24 -import java.util.Map;
25 -import java.util.Optional;
26 -import java.util.Set;
27 -import java.util.concurrent.ConcurrentHashMap;
28 -import java.util.concurrent.CountDownLatch;
29 -import java.util.concurrent.ExecutionException;
30 -import java.util.concurrent.Future;
31 -import java.util.concurrent.TimeUnit;
32 -import java.util.concurrent.TimeoutException;
33 -import java.util.concurrent.atomic.AtomicBoolean;
34 -import java.util.concurrent.atomic.AtomicLong;
35 -import java.util.stream.Collectors;
36 18
19 +import com.google.common.cache.Cache;
20 +import com.google.common.cache.CacheBuilder;
21 +import com.google.common.cache.RemovalCause;
22 +import com.google.common.cache.RemovalNotification;
23 +import com.google.common.collect.Maps;
24 +import com.google.common.collect.Sets;
37 import org.apache.felix.scr.annotations.Activate; 25 import org.apache.felix.scr.annotations.Activate;
38 import org.apache.felix.scr.annotations.Component; 26 import org.apache.felix.scr.annotations.Component;
39 import org.apache.felix.scr.annotations.Deactivate; 27 import org.apache.felix.scr.annotations.Deactivate;
...@@ -41,19 +29,16 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -41,19 +29,16 @@ import org.apache.felix.scr.annotations.Reference;
41 import org.apache.felix.scr.annotations.ReferenceCardinality; 29 import org.apache.felix.scr.annotations.ReferenceCardinality;
42 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
43 import org.onosproject.net.DeviceId; 31 import org.onosproject.net.DeviceId;
44 -import org.onosproject.net.flow.BatchOperation;
45 import org.onosproject.net.flow.CompletedBatchOperation; 32 import org.onosproject.net.flow.CompletedBatchOperation;
46 -import org.onosproject.net.flow.DefaultFlowEntry;
47 import org.onosproject.net.flow.FlowEntry; 33 import org.onosproject.net.flow.FlowEntry;
48 import org.onosproject.net.flow.FlowRule; 34 import org.onosproject.net.flow.FlowRule;
49 import org.onosproject.net.flow.FlowRuleBatchEntry; 35 import org.onosproject.net.flow.FlowRuleBatchEntry;
50 -import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation; 36 +import org.onosproject.net.flow.FlowRuleBatchOperation;
51 import org.onosproject.net.flow.FlowRuleProvider; 37 import org.onosproject.net.flow.FlowRuleProvider;
52 import org.onosproject.net.flow.FlowRuleProviderRegistry; 38 import org.onosproject.net.flow.FlowRuleProviderRegistry;
53 import org.onosproject.net.flow.FlowRuleProviderService; 39 import org.onosproject.net.flow.FlowRuleProviderService;
54 import org.onosproject.net.provider.AbstractProvider; 40 import org.onosproject.net.provider.AbstractProvider;
55 import org.onosproject.net.provider.ProviderId; 41 import org.onosproject.net.provider.ProviderId;
56 -import org.onosproject.net.topology.TopologyService;
57 import org.onosproject.openflow.controller.Dpid; 42 import org.onosproject.openflow.controller.Dpid;
58 import org.onosproject.openflow.controller.OpenFlowController; 43 import org.onosproject.openflow.controller.OpenFlowController;
59 import org.onosproject.openflow.controller.OpenFlowEventListener; 44 import org.onosproject.openflow.controller.OpenFlowEventListener;
...@@ -63,6 +48,7 @@ import org.onosproject.openflow.controller.RoleState; ...@@ -63,6 +48,7 @@ import org.onosproject.openflow.controller.RoleState;
63 import org.projectfloodlight.openflow.protocol.OFActionType; 48 import org.projectfloodlight.openflow.protocol.OFActionType;
64 import org.projectfloodlight.openflow.protocol.OFBarrierRequest; 49 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
65 import org.projectfloodlight.openflow.protocol.OFErrorMsg; 50 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
51 +import org.projectfloodlight.openflow.protocol.OFErrorType;
66 import org.projectfloodlight.openflow.protocol.OFFlowMod; 52 import org.projectfloodlight.openflow.protocol.OFFlowMod;
67 import org.projectfloodlight.openflow.protocol.OFFlowRemoved; 53 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
68 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; 54 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
...@@ -75,21 +61,22 @@ import org.projectfloodlight.openflow.protocol.OFStatsType; ...@@ -75,21 +61,22 @@ import org.projectfloodlight.openflow.protocol.OFStatsType;
75 import org.projectfloodlight.openflow.protocol.OFVersion; 61 import org.projectfloodlight.openflow.protocol.OFVersion;
76 import org.projectfloodlight.openflow.protocol.action.OFAction; 62 import org.projectfloodlight.openflow.protocol.action.OFAction;
77 import org.projectfloodlight.openflow.protocol.action.OFActionOutput; 63 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
78 -import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
79 -import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
80 -import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
81 -import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
82 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; 64 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
83 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; 65 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
84 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; 66 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
85 import org.projectfloodlight.openflow.types.OFPort; 67 import org.projectfloodlight.openflow.types.OFPort;
86 import org.slf4j.Logger; 68 import org.slf4j.Logger;
87 69
88 -import com.google.common.base.MoreObjects; 70 +import java.util.Collections;
89 -import com.google.common.collect.ArrayListMultimap; 71 +import java.util.List;
90 -import com.google.common.collect.Maps; 72 +import java.util.Map;
91 -import com.google.common.collect.Multimap; 73 +import java.util.Optional;
92 -import com.google.common.collect.Sets; 74 +import java.util.Set;
75 +import java.util.concurrent.TimeUnit;
76 +import java.util.stream.Collectors;
77 +
78 +import static org.slf4j.LoggerFactory.getLogger;
79 +
93 80
94 /** 81 /**
95 * Provider which uses an OpenFlow controller to detect network 82 * Provider which uses an OpenFlow controller to detect network
...@@ -98,8 +85,6 @@ import com.google.common.collect.Sets; ...@@ -98,8 +85,6 @@ import com.google.common.collect.Sets;
98 @Component(immediate = true) 85 @Component(immediate = true)
99 public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider { 86 public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
100 87
101 - enum BatchState { STARTED, FINISHED, CANCELLED }
102 -
103 private static final int LOWEST_PRIORITY = 0; 88 private static final int LOWEST_PRIORITY = 0;
104 89
105 private final Logger log = getLogger(getClass()); 90 private final Logger log = getLogger(getClass());
...@@ -110,22 +95,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -110,22 +95,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected OpenFlowController controller; 96 protected OpenFlowController controller;
112 97
113 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 - protected TopologyService topologyService;
115 98
116 private FlowRuleProviderService providerService; 99 private FlowRuleProviderService providerService;
117 100
118 private final InternalFlowProvider listener = new InternalFlowProvider(); 101 private final InternalFlowProvider listener = new InternalFlowProvider();
119 102
120 - // FIXME: This should be an expiring map to ensure futures that don't have 103 + private Cache<Long, InternalCacheEntry> pendingBatches;
121 - // a future eventually get garbage collected.
122 - private final Map<Long, InstallationFuture> pendingFutures = new ConcurrentHashMap<>();
123 -
124 - private final Map<Long, InstallationFuture> pendingFMs = new ConcurrentHashMap<>();
125 104
126 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap(); 105 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
127 106
128 - private final AtomicLong xidCounter = new AtomicLong(1);
129 107
130 /** 108 /**
131 * Creates an OpenFlow host provider. 109 * Creates an OpenFlow host provider.
...@@ -140,6 +118,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -140,6 +118,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
140 controller.addListener(listener); 118 controller.addListener(listener);
141 controller.addEventListener(listener); 119 controller.addEventListener(listener);
142 120
121 + pendingBatches = CacheBuilder.newBuilder()
122 + .expireAfterWrite(10, TimeUnit.SECONDS)
123 + .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
124 + if (notification.getCause() == RemovalCause.EXPIRED) {
125 + providerService.batchOperationCompleted(notification.getKey(),
126 + notification.getValue().failedCompletion());
127 + }
128 + }).build();
129 +
130 +
143 for (OpenFlowSwitch sw : controller.getSwitches()) { 131 for (OpenFlowSwitch sw : controller.getSwitches()) {
144 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL); 132 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL);
145 fsc.start(); 133 fsc.start();
...@@ -160,8 +148,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -160,8 +148,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
160 148
161 @Override 149 @Override
162 public void applyFlowRule(FlowRule... flowRules) { 150 public void applyFlowRule(FlowRule... flowRules) {
163 - for (int i = 0; i < flowRules.length; i++) { 151 + for (FlowRule flowRule : flowRules) {
164 - applyRule(flowRules[i]); 152 + applyRule(flowRule);
165 } 153 }
166 } 154 }
167 155
...@@ -179,8 +167,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -179,8 +167,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
179 167
180 @Override 168 @Override
181 public void removeFlowRule(FlowRule... flowRules) { 169 public void removeFlowRule(FlowRule... flowRules) {
182 - for (int i = 0; i < flowRules.length; i++) { 170 + for (FlowRule flowRule : flowRules) {
183 - removeRule(flowRules[i]); 171 + removeRule(flowRule);
184 } 172 }
185 173
186 } 174 }
...@@ -203,36 +191,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -203,36 +191,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
203 } 191 }
204 192
205 @Override 193 @Override
206 - public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
207 - final Set<Dpid> sws = Sets.newConcurrentHashSet();
208 - final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>();
209 194
210 - /* 195 + public void executeBatch(FlowRuleBatchOperation batch) {
211 - * Use identity hash map for reference equality as we could have equal 196 +
212 - * flow mods for different switches. 197 + pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
213 - */ 198 +
214 - Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap(); 199 +
215 - Map<OFFlowMod, OpenFlowSwitch.TableType> modTypes = Maps.newIdentityHashMap(); 200 + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(batch.deviceId().uri()));
201 + OFFlowMod mod;
202 +
216 for (FlowRuleBatchEntry fbe : batch.getOperations()) { 203 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
217 - FlowRule flowRule = fbe.target(); 204 +
218 - final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
219 - OpenFlowSwitch sw = controller.getSwitch(dpid);
220 - if (sw == null) {
221 - /*
222 - * if a switch we are supposed to install to is gone then
223 - * cancel (ie. rollback) the work that has been done so far
224 - * and return the associated future.
225 - */
226 - InstallationFuture failed = new InstallationFuture(sws, fmXids);
227 - failed.cancel(true);
228 - return failed;
229 - }
230 - sws.add(dpid);
231 - final Long flowModXid = xidCounter.getAndIncrement();
232 FlowModBuilder builder = 205 FlowModBuilder builder =
233 - FlowModBuilder.builder(flowRule, sw.factory(), 206 + FlowModBuilder.builder(fbe.target(), sw.factory(),
234 - Optional.of(flowModXid)); 207 + Optional.of(batch.id()));
235 - OFFlowMod mod = null;
236 switch (fbe.operator()) { 208 switch (fbe.operator()) {
237 case ADD: 209 case ADD:
238 mod = builder.buildFlowAdd(); 210 mod = builder.buildFlowAdd();
...@@ -244,34 +216,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -244,34 +216,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
244 mod = builder.buildFlowMod(); 216 mod = builder.buildFlowMod();
245 break; 217 break;
246 default: 218 default:
247 - log.error("Unsupported batch operation {}", fbe.operator()); 219 + log.error("Unsupported batch operation {}; skipping flowmod {}",
248 - } 220 + fbe.operator(), fbe);
249 - if (mod != null) { 221 + continue;
250 - mods.put(mod, sw);
251 - modTypes.put(mod, getTableType(flowRule.type()));
252 - fmXids.put(flowModXid, fbe);
253 - } else {
254 - log.error("Conversion of flowrule {} failed.", flowRule);
255 } 222 }
256 - }
257 - InstallationFuture installation = new InstallationFuture(sws, fmXids);
258 - for (Long xid : fmXids.keySet()) {
259 - pendingFMs.put(xid, installation);
260 - }
261 -
262 - pendingFutures.put(installation.xid(), installation);
263 - for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) {
264 - OpenFlowSwitch sw = entry.getValue();
265 - OFFlowMod mod = entry.getKey();
266 - OpenFlowSwitch.TableType tableType = modTypes.get(mod);
267 - if (tableType == OpenFlowSwitch.TableType.NONE) {
268 sw.sendMsg(mod); 223 sw.sendMsg(mod);
269 - } else {
270 - sw.sendMsg(mod, tableType);
271 } 224 }
272 - } 225 + OFBarrierRequest.Builder builder = sw.factory()
273 - installation.verify(); 226 + .buildBarrierRequest()
274 - return installation; 227 + .setXid(batch.id());
228 + sw.sendMsg(builder.build());
275 } 229 }
276 230
277 private OpenFlowSwitch.TableType getTableType(FlowRule.Type type) { 231 private OpenFlowSwitch.TableType getTableType(FlowRule.Type type) {
...@@ -287,12 +241,11 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -287,12 +241,11 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
287 } 241 }
288 } 242 }
289 243
290 - private class InternalFlowProvider
291 - implements OpenFlowSwitchListener, OpenFlowEventListener {
292 244
293 245
294 - private final Multimap<DeviceId, FlowEntry> completeEntries = 246 +
295 - ArrayListMultimap.create(); 247 + private class InternalFlowProvider
248 + implements OpenFlowSwitchListener, OpenFlowEventListener {
296 249
297 @Override 250 @Override
298 public void switchAdded(Dpid dpid) { 251 public void switchAdded(Dpid dpid) {
...@@ -320,7 +273,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -320,7 +273,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
320 273
321 @Override 274 @Override
322 public void handleMessage(Dpid dpid, OFMessage msg) { 275 public void handleMessage(Dpid dpid, OFMessage msg) {
323 - InstallationFuture future = null;
324 switch (msg.getType()) { 276 switch (msg.getType()) {
325 case FLOW_REMOVED: 277 case FLOW_REMOVED:
326 OFFlowRemoved removed = (OFFlowRemoved) msg; 278 OFFlowRemoved removed = (OFFlowRemoved) msg;
...@@ -334,22 +286,42 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -334,22 +286,42 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
334 } 286 }
335 break; 287 break;
336 case BARRIER_REPLY: 288 case BARRIER_REPLY:
337 - future = pendingFutures.get(msg.getXid()); 289 + try {
338 - if (future != null) { 290 + InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
339 - future.satisfyRequirement(dpid); 291 + if (entry != null) {
292 + providerService.batchOperationCompleted(msg.getXid(), entry.completed());
340 } else { 293 } else {
341 log.warn("Received unknown Barrier Reply: {}", msg.getXid()); 294 log.warn("Received unknown Barrier Reply: {}", msg.getXid());
342 } 295 }
296 + } finally {
297 + pendingBatches.invalidate(msg.getXid());
298 + }
343 break; 299 break;
344 case ERROR: 300 case ERROR:
345 log.warn("received Error message {} from {}", msg, dpid); 301 log.warn("received Error message {} from {}", msg, dpid);
346 - future = pendingFMs.get(msg.getXid()); 302 +
347 - if (future != null) { 303 + OFErrorMsg error = (OFErrorMsg) msg;
348 - future.fail((OFErrorMsg) msg, dpid); 304 + if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
305 + OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
306 + if (fmFailed.getData().getParsedMessage().isPresent()) {
307 + OFMessage m = fmFailed.getData().getParsedMessage().get();
308 + OFFlowMod fm = (OFFlowMod) m;
309 + InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
310 + if (entry != null) {
311 + entry.appendFailure(new FlowEntryBuilder(dpid, fm).build());
349 } else { 312 } else {
350 - log.warn("Received unknown Error Reply: {} {}", msg.getXid(), msg); 313 + log.error("No matching batch for this error: {}", error);
351 } 314 }
352 - break; 315 + } else {
316 + //FIXME: Potentially add flowtracking to avoid this message.
317 + log.error("Flow installation failed but switch didn't" +
318 + " tell us which one.");
319 + }
320 + } else {
321 + log.warn("Received error {}", error);
322 + }
323 +
324 +
353 default: 325 default:
354 log.debug("Unhandled message type: {}", msg.getType()); 326 log.debug("Unhandled message type: {}", msg.getType());
355 } 327 }
...@@ -402,198 +374,50 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -402,198 +374,50 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
402 374
403 } 375 }
404 376
405 - private class InstallationFuture implements Future<CompletedBatchOperation> { 377 + /**
406 - 378 + * The internal cache entry holding the original request as well
407 - // barrier xid 379 + * as accumulating the any failures along the way.
408 - private final Long xid; 380 + *
409 - // waiting for barrier reply from... 381 + * If this entry is evicted from the cache then the entire operation
410 - private final Set<Dpid> sws; 382 + * is considered failed. Otherwise, only the failures reported by the device
411 - private final AtomicBoolean ok = new AtomicBoolean(true); 383 + * will be propagated up.
412 - // FlowMod xid -> 384 + */
413 - private final Map<Long, FlowRuleBatchEntry> fms; 385 + private class InternalCacheEntry {
414 -
415 -
416 - private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
417 - // Failed batch operation id
418 - private Long failedId;
419 -
420 - private final CountDownLatch countDownLatch;
421 - private BatchState state;
422 -
423 - public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
424 - this.xid = xidCounter.getAndIncrement();
425 - this.state = BatchState.STARTED;
426 - this.sws = sws;
427 - this.fms = fmXids;
428 - countDownLatch = new CountDownLatch(sws.size());
429 - }
430 -
431 - public Long xid() {
432 - return xid;
433 - }
434 -
435 - public void fail(OFErrorMsg msg, Dpid dpid) {
436 -
437 - ok.set(false);
438 - FlowEntry fe = null;
439 - FlowRuleBatchEntry fbe = fms.get(msg.getXid());
440 - failedId = fbe.id();
441 - FlowRule offending = fbe.target();
442 - //TODO handle specific error msgs
443 - switch (msg.getErrType()) {
444 - case BAD_ACTION:
445 - OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
446 - fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
447 - bad.getCode().ordinal());
448 - break;
449 - case BAD_INSTRUCTION:
450 - OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
451 - fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
452 - badins.getCode().ordinal());
453 - break;
454 - case BAD_MATCH:
455 - OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
456 - fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
457 - badMatch.getCode().ordinal());
458 - break;
459 - case BAD_REQUEST:
460 - OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
461 - fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
462 - badReq.getCode().ordinal());
463 - break;
464 - case FLOW_MOD_FAILED:
465 - OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
466 - fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
467 - fmFail.getCode().ordinal());
468 - break;
469 - case EXPERIMENTER:
470 - case GROUP_MOD_FAILED:
471 - case HELLO_FAILED:
472 - case METER_MOD_FAILED:
473 - case PORT_MOD_FAILED:
474 - case QUEUE_OP_FAILED:
475 - case ROLE_REQUEST_FAILED:
476 - case SWITCH_CONFIG_FAILED:
477 - case TABLE_FEATURES_FAILED:
478 - case TABLE_MOD_FAILED:
479 - fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
480 - break;
481 - default:
482 - log.error("Unknown error type {}", msg.getErrType());
483 -
484 - }
485 - offendingFlowMods.add(fe);
486 -
487 - removeRequirement(dpid);
488 - }
489 -
490 -
491 - public void satisfyRequirement(Dpid dpid) {
492 - log.debug("Satisfaction from switch {}", dpid);
493 - removeRequirement(dpid);
494 - }
495 -
496 -
497 - public void verify() {
498 - checkState(!sws.isEmpty());
499 - for (Dpid dpid : sws) {
500 - OpenFlowSwitch sw = controller.getSwitch(dpid);
501 - OFBarrierRequest.Builder builder = sw.factory()
502 - .buildBarrierRequest()
503 - .setXid(xid);
504 - sw.sendMsg(builder.build());
505 - }
506 - }
507 -
508 - @Override
509 - public boolean cancel(boolean mayInterruptIfRunning) {
510 - if (isDone()) {
511 - return false;
512 - }
513 - ok.set(false);
514 - this.state = BatchState.CANCELLED;
515 - cleanUp();
516 - for (FlowRuleBatchEntry fbe : fms.values()) {
517 - if (fbe.operator() == FlowRuleOperation.ADD ||
518 - fbe.operator() == FlowRuleOperation.MODIFY) {
519 - removeFlowRule(fbe.target());
520 - } else if (fbe.operator() == FlowRuleOperation.REMOVE) {
521 - applyRule(fbe.target());
522 - }
523 -
524 - }
525 - return true;
526 - }
527 -
528 - @Override
529 - public boolean isCancelled() {
530 - return this.state == BatchState.CANCELLED;
531 - }
532 386
533 - @Override 387 + private final FlowRuleBatchOperation operation;
534 - public boolean isDone() { 388 + private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
535 - return this.state == BatchState.FINISHED || isCancelled();
536 - }
537 389
538 - @Override 390 + public InternalCacheEntry(FlowRuleBatchOperation operation) {
539 - public CompletedBatchOperation get() throws InterruptedException, ExecutionException { 391 + this.operation = operation;
540 - countDownLatch.await();
541 - this.state = BatchState.FINISHED;
542 - Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
543 - CompletedBatchOperation result =
544 - new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
545 - //FIXME do cleanup here (moved by BOC)
546 - cleanUp();
547 - return result;
548 } 392 }
549 393
550 - @Override 394 + /**
551 - public CompletedBatchOperation get(long timeout, TimeUnit unit) 395 + * Appends a failed rule to the set of failed items.
552 - throws InterruptedException, ExecutionException, 396 + * @param rule the failed rule
553 - TimeoutException { 397 + */
554 - if (countDownLatch.await(timeout, unit)) { 398 + public void appendFailure(FlowRule rule) {
555 - this.state = BatchState.FINISHED; 399 + failures.add(rule);
556 - Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
557 - CompletedBatchOperation result =
558 - new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
559 - // FIXME do cleanup here (moved by BOC)
560 - cleanUp();
561 - return result;
562 - }
563 - throw new TimeoutException(this.toString());
564 } 400 }
565 401
566 - private void cleanUp() { 402 + /**
567 - if (isDone() || isCancelled()) { 403 + * Fails the entire batch and returns the failed operation.
568 - pendingFutures.remove(xid); 404 + * @return the failed operation
569 - for (Long xid : fms.keySet()) { 405 + */
570 - pendingFMs.remove(xid); 406 + public CompletedBatchOperation failedCompletion() {
571 - } 407 + Set<FlowRule> fails = operation.getOperations().stream()
572 - } 408 + .map(op -> op.target()).collect(Collectors.toSet());
409 + return new CompletedBatchOperation(false, Collections.unmodifiableSet(fails), operation.deviceId());
573 } 410 }
574 411
575 - private void removeRequirement(Dpid dpid) { 412 + /**
576 - countDownLatch.countDown(); 413 + * Returns the completed operation and whether the batch suceeded.
577 - sws.remove(dpid); 414 + * @return the completed operation
578 - //FIXME don't do cleanup here (moved by BOC) 415 + */
579 - //cleanUp(); 416 + public CompletedBatchOperation completed() {
417 + return new CompletedBatchOperation(failures.isEmpty(),
418 + Collections.unmodifiableSet(failures), operation.deviceId());
580 } 419 }
581 420
582 - @Override
583 - public String toString() {
584 - return MoreObjects.toStringHelper(getClass())
585 - .add("xid", xid)
586 - .add("pending devices", sws)
587 - .add("devices in batch",
588 - fms.values().stream()
589 - .map((fbe) -> fbe.target().deviceId())
590 - .distinct().collect(Collectors.toList()))
591 - .add("failedId", failedId)
592 - .add("latchCount", countDownLatch.getCount())
593 - .add("state", state)
594 - .add("no error?", ok.get())
595 - .toString();
596 - }
597 } 421 }
598 422
599 } 423 }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 # Instance-specific configurations, in this case, the number of 2 # Instance-specific configurations, in this case, the number of
3 # devices per node. 3 # devices per node.
4 # 4 #
5 -devConfigs = 192.168.56.30:5,192.168.56.40:7 5 +devConfigs = 192.168.97.132:5,192.168.97.131:5
6 6
7 # 7 #
8 # Number of ports per device. This is global to all devices 8 # Number of ports per device. This is global to all devices
......
...@@ -9,4 +9,4 @@ ...@@ -9,4 +9,4 @@
9 # 9 #
10 # Set order of islands to chain together, in a line. 10 # Set order of islands to chain together, in a line.
11 # 11 #
12 -neighbors = 192.168.56.20,192.168.56.30,192.168.56.40 12 +neighbors = 192.168.97.132,192.168.97.131
......