Showing
14 changed files
with
395 additions
and
154 deletions
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | -import java.util.List; | 3 | +import java.util.Set; |
4 | 4 | ||
5 | /** | 5 | /** |
6 | * Interface capturing the result of a batch operation. | 6 | * Interface capturing the result of a batch operation. |
... | @@ -15,9 +15,9 @@ public interface BatchOperationResult<T> { | ... | @@ -15,9 +15,9 @@ public interface BatchOperationResult<T> { |
15 | boolean isSuccess(); | 15 | boolean isSuccess(); |
16 | 16 | ||
17 | /** | 17 | /** |
18 | - * Obtains a list of items which failed. | 18 | + * Obtains a set of items which failed. |
19 | - * @return a list of failures | 19 | + * @return a set of failures |
20 | */ | 20 | */ |
21 | - List<T> failedItems(); | 21 | + Set<T> failedItems(); |
22 | 22 | ||
23 | } | 23 | } | ... | ... |
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | -import java.util.List; | 3 | +import java.util.Set; |
4 | 4 | ||
5 | -import com.google.common.collect.ImmutableList; | 5 | +import com.google.common.collect.ImmutableSet; |
6 | 6 | ||
7 | public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> { | 7 | public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> { |
8 | 8 | ||
9 | 9 | ||
10 | private final boolean success; | 10 | private final boolean success; |
11 | - private final List<FlowEntry> failures; | 11 | + private final Set<FlowEntry> failures; |
12 | 12 | ||
13 | - public CompletedBatchOperation(boolean success, List<FlowEntry> failures) { | 13 | + public CompletedBatchOperation(boolean success, Set<FlowEntry> failures) { |
14 | this.success = success; | 14 | this.success = success; |
15 | - this.failures = ImmutableList.copyOf(failures); | 15 | + this.failures = ImmutableSet.copyOf(failures); |
16 | } | 16 | } |
17 | 17 | ||
18 | @Override | 18 | @Override |
... | @@ -21,7 +21,7 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> | ... | @@ -21,7 +21,7 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> |
21 | } | 21 | } |
22 | 22 | ||
23 | @Override | 23 | @Override |
24 | - public List<FlowEntry> failedItems() { | 24 | + public Set<FlowEntry> failedItems() { |
25 | return failures; | 25 | return failures; |
26 | } | 26 | } |
27 | 27 | ... | ... |
1 | +package org.onlab.onos.net.flow; | ||
2 | + | ||
3 | +import org.onlab.onos.event.AbstractEvent; | ||
4 | + | ||
5 | +/** | ||
6 | + * Describes flow rule batch event. | ||
7 | + */ | ||
8 | +public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> { | ||
9 | + | ||
10 | + /** | ||
11 | + * Type of flow rule events. | ||
12 | + */ | ||
13 | + public enum Type { | ||
14 | + | ||
15 | + /** | ||
16 | + * Signifies that a batch operation has been initiated. | ||
17 | + */ | ||
18 | + BATCH_OPERATION_REQUESTED, | ||
19 | + | ||
20 | + /** | ||
21 | + * Signifies that a batch operation has completed. | ||
22 | + */ | ||
23 | + BATCH_OPERATION_COMPLETED, | ||
24 | + } | ||
25 | + | ||
26 | + private final CompletedBatchOperation result; | ||
27 | + | ||
28 | + /** | ||
29 | + * Constructs a new FlowRuleBatchEvent. | ||
30 | + * @param request batch operation request. | ||
31 | + * @return event. | ||
32 | + */ | ||
33 | + public static FlowRuleBatchEvent create(FlowRuleBatchRequest request) { | ||
34 | + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, null); | ||
35 | + return event; | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * Constructs a new FlowRuleBatchEvent. | ||
40 | + * @param request batch operation request. | ||
41 | + * @param result completed batch operation result. | ||
42 | + * @return event. | ||
43 | + */ | ||
44 | + public static FlowRuleBatchEvent create(FlowRuleBatchRequest request, CompletedBatchOperation result) { | ||
45 | + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_COMPLETED, request, result); | ||
46 | + return event; | ||
47 | + } | ||
48 | + | ||
49 | + /** | ||
50 | + * Returns the result of this batch operation. | ||
51 | + * @return batch operation result. | ||
52 | + */ | ||
53 | + public CompletedBatchOperation result() { | ||
54 | + return result; | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Creates an event of a given type and for the specified flow rule batch. | ||
59 | + * | ||
60 | + * @param type flow rule batch event type | ||
61 | + * @param batch event flow rule batch subject | ||
62 | + */ | ||
63 | + private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) { | ||
64 | + super(type, request); | ||
65 | + this.result = result; | ||
66 | + } | ||
67 | +} |
1 | +package org.onlab.onos.net.flow; | ||
2 | + | ||
3 | +import java.util.Collections; | ||
4 | +import java.util.List; | ||
5 | + | ||
6 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
7 | + | ||
8 | +import com.google.common.collect.Lists; | ||
9 | + | ||
10 | +public class FlowRuleBatchRequest { | ||
11 | + | ||
12 | + private final List<FlowEntry> toAdd; | ||
13 | + private final List<FlowEntry> toRemove; | ||
14 | + | ||
15 | + public FlowRuleBatchRequest(List<FlowEntry> toAdd, List<FlowEntry> toRemove) { | ||
16 | + this.toAdd = Collections.unmodifiableList(toAdd); | ||
17 | + this.toRemove = Collections.unmodifiableList(toRemove); | ||
18 | + } | ||
19 | + | ||
20 | + public List<FlowEntry> toAdd() { | ||
21 | + return toAdd; | ||
22 | + } | ||
23 | + | ||
24 | + public List<FlowEntry> toRemove() { | ||
25 | + return toRemove; | ||
26 | + } | ||
27 | + | ||
28 | + public FlowRuleBatchOperation asBatchOperation() { | ||
29 | + List<FlowRuleBatchEntry> entries = Lists.newArrayList(); | ||
30 | + for (FlowEntry e : toAdd) { | ||
31 | + entries.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, e)); | ||
32 | + } | ||
33 | + for (FlowEntry e : toRemove) { | ||
34 | + entries.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, e)); | ||
35 | + } | ||
36 | + return new FlowRuleBatchOperation(entries); | ||
37 | + } | ||
38 | +} |
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | -import java.util.concurrent.Future; | ||
4 | - | ||
5 | import org.onlab.onos.ApplicationId; | 3 | import org.onlab.onos.ApplicationId; |
6 | import org.onlab.onos.net.intent.BatchOperation; | 4 | import org.onlab.onos.net.intent.BatchOperation; |
7 | import org.onlab.onos.net.provider.Provider; | 5 | import org.onlab.onos.net.provider.Provider; |
8 | 6 | ||
7 | +import com.google.common.util.concurrent.ListenableFuture; | ||
8 | + | ||
9 | /** | 9 | /** |
10 | * Abstraction of a flow rule provider. | 10 | * Abstraction of a flow rule provider. |
11 | */ | 11 | */ |
... | @@ -43,6 +43,6 @@ public interface FlowRuleProvider extends Provider { | ... | @@ -43,6 +43,6 @@ public interface FlowRuleProvider extends Provider { |
43 | * @param batch a batch of flow rules | 43 | * @param batch a batch of flow rules |
44 | * @return a future indicating the status of this execution | 44 | * @return a future indicating the status of this execution |
45 | */ | 45 | */ |
46 | - Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); | 46 | + ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); |
47 | 47 | ||
48 | } | 48 | } | ... | ... |
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | +import java.util.concurrent.Future; | ||
4 | + | ||
3 | import org.onlab.onos.ApplicationId; | 5 | import org.onlab.onos.ApplicationId; |
4 | import org.onlab.onos.net.DeviceId; | 6 | import org.onlab.onos.net.DeviceId; |
5 | import org.onlab.onos.store.Store; | 7 | import org.onlab.onos.store.Store; |
... | @@ -7,7 +9,7 @@ import org.onlab.onos.store.Store; | ... | @@ -7,7 +9,7 @@ import org.onlab.onos.store.Store; |
7 | /** | 9 | /** |
8 | * Manages inventory of flow rules; not intended for direct use. | 10 | * Manages inventory of flow rules; not intended for direct use. |
9 | */ | 11 | */ |
10 | -public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegate> { | 12 | +public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDelegate> { |
11 | 13 | ||
12 | /** | 14 | /** |
13 | * Returns the number of flow rule in the store. | 15 | * Returns the number of flow rule in the store. |
... | @@ -41,12 +43,26 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat | ... | @@ -41,12 +43,26 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat |
41 | Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId); | 43 | Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId); |
42 | 44 | ||
43 | /** | 45 | /** |
46 | + // TODO: Better description of method behavior. | ||
44 | * Stores a new flow rule without generating events. | 47 | * Stores a new flow rule without generating events. |
45 | * | 48 | * |
46 | * @param rule the flow rule to add | 49 | * @param rule the flow rule to add |
47 | - * @return true if the rule should be handled locally | ||
48 | */ | 50 | */ |
49 | - boolean storeFlowRule(FlowRule rule); | 51 | + void storeFlowRule(FlowRule rule); |
52 | + | ||
53 | + /** | ||
54 | + * Stores a batch of flow rules. | ||
55 | + * @param batchOperation batch of flow rules. | ||
56 | + * @return Future response indicating success/failure of the batch operation | ||
57 | + * all the way down to the device. | ||
58 | + */ | ||
59 | + Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation batchOperation); | ||
60 | + | ||
61 | + /** | ||
62 | + * Invoked on the completion of a storeBatch operation. | ||
63 | + * @param result | ||
64 | + */ | ||
65 | + void batchOperationComplete(FlowRuleBatchEvent event); | ||
50 | 66 | ||
51 | /** | 67 | /** |
52 | * Marks a flow rule for deletion. Actual deletion will occur | 68 | * Marks a flow rule for deletion. Actual deletion will occur |
... | @@ -55,7 +71,7 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat | ... | @@ -55,7 +71,7 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat |
55 | * @param rule the flow rule to delete | 71 | * @param rule the flow rule to delete |
56 | * @return true if the rule should be handled locally | 72 | * @return true if the rule should be handled locally |
57 | */ | 73 | */ |
58 | - boolean deleteFlowRule(FlowRule rule); | 74 | + void deleteFlowRule(FlowRule rule); |
59 | 75 | ||
60 | /** | 76 | /** |
61 | * Stores a new flow rule, or updates an existing entry. | 77 | * Stores a new flow rule, or updates an existing entry. | ... | ... |
... | @@ -5,5 +5,5 @@ import org.onlab.onos.store.StoreDelegate; | ... | @@ -5,5 +5,5 @@ import org.onlab.onos.store.StoreDelegate; |
5 | /** | 5 | /** |
6 | * Flow rule store delegate abstraction. | 6 | * Flow rule store delegate abstraction. |
7 | */ | 7 | */ |
8 | -public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleEvent> { | 8 | +public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleBatchEvent> { |
9 | } | 9 | } | ... | ... |
... | @@ -5,8 +5,10 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,8 +5,10 @@ import static org.slf4j.LoggerFactory.getLogger; |
5 | 5 | ||
6 | import java.util.List; | 6 | import java.util.List; |
7 | import java.util.Map; | 7 | import java.util.Map; |
8 | +import java.util.Set; | ||
8 | import java.util.concurrent.CancellationException; | 9 | import java.util.concurrent.CancellationException; |
9 | import java.util.concurrent.ExecutionException; | 10 | import java.util.concurrent.ExecutionException; |
11 | +import java.util.concurrent.Executors; | ||
10 | import java.util.concurrent.Future; | 12 | import java.util.concurrent.Future; |
11 | import java.util.concurrent.TimeUnit; | 13 | import java.util.concurrent.TimeUnit; |
12 | import java.util.concurrent.TimeoutException; | 14 | import java.util.concurrent.TimeoutException; |
... | @@ -30,7 +32,9 @@ import org.onlab.onos.net.flow.FlowEntry; | ... | @@ -30,7 +32,9 @@ import org.onlab.onos.net.flow.FlowEntry; |
30 | import org.onlab.onos.net.flow.FlowRule; | 32 | import org.onlab.onos.net.flow.FlowRule; |
31 | import org.onlab.onos.net.flow.FlowRuleBatchEntry; | 33 | import org.onlab.onos.net.flow.FlowRuleBatchEntry; |
32 | import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | 34 | import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; |
35 | +import org.onlab.onos.net.flow.FlowRuleBatchEvent; | ||
33 | import org.onlab.onos.net.flow.FlowRuleBatchOperation; | 36 | import org.onlab.onos.net.flow.FlowRuleBatchOperation; |
37 | +import org.onlab.onos.net.flow.FlowRuleBatchRequest; | ||
34 | import org.onlab.onos.net.flow.FlowRuleEvent; | 38 | import org.onlab.onos.net.flow.FlowRuleEvent; |
35 | import org.onlab.onos.net.flow.FlowRuleListener; | 39 | import org.onlab.onos.net.flow.FlowRuleListener; |
36 | import org.onlab.onos.net.flow.FlowRuleProvider; | 40 | import org.onlab.onos.net.flow.FlowRuleProvider; |
... | @@ -47,6 +51,9 @@ import com.google.common.collect.ArrayListMultimap; | ... | @@ -47,6 +51,9 @@ import com.google.common.collect.ArrayListMultimap; |
47 | import com.google.common.collect.Lists; | 51 | import com.google.common.collect.Lists; |
48 | import com.google.common.collect.Maps; | 52 | import com.google.common.collect.Maps; |
49 | import com.google.common.collect.Multimap; | 53 | import com.google.common.collect.Multimap; |
54 | +import com.google.common.collect.Sets; | ||
55 | +import com.google.common.util.concurrent.Futures; | ||
56 | +import com.google.common.util.concurrent.ListenableFuture; | ||
50 | 57 | ||
51 | /** | 58 | /** |
52 | * Provides implementation of the flow NB & SB APIs. | 59 | * Provides implementation of the flow NB & SB APIs. |
... | @@ -104,11 +111,7 @@ public class FlowRuleManager | ... | @@ -104,11 +111,7 @@ public class FlowRuleManager |
104 | public void applyFlowRules(FlowRule... flowRules) { | 111 | public void applyFlowRules(FlowRule... flowRules) { |
105 | for (int i = 0; i < flowRules.length; i++) { | 112 | for (int i = 0; i < flowRules.length; i++) { |
106 | FlowRule f = flowRules[i]; | 113 | FlowRule f = flowRules[i]; |
107 | - boolean local = store.storeFlowRule(f); | 114 | + store.storeFlowRule(f); |
108 | - if (local) { | ||
109 | - // TODO: aggregate all local rules and push down once? | ||
110 | - applyFlowRulesToProviders(f); | ||
111 | - } | ||
112 | } | 115 | } |
113 | } | 116 | } |
114 | 117 | ||
... | @@ -132,11 +135,7 @@ public class FlowRuleManager | ... | @@ -132,11 +135,7 @@ public class FlowRuleManager |
132 | FlowRule f; | 135 | FlowRule f; |
133 | for (int i = 0; i < flowRules.length; i++) { | 136 | for (int i = 0; i < flowRules.length; i++) { |
134 | f = flowRules[i]; | 137 | f = flowRules[i]; |
135 | - boolean local = store.deleteFlowRule(f); | 138 | + store.deleteFlowRule(f); |
136 | - if (local) { | ||
137 | - // TODO: aggregate all local rules and push down once? | ||
138 | - removeFlowRulesFromProviders(f); | ||
139 | - } | ||
140 | } | 139 | } |
141 | } | 140 | } |
142 | 141 | ||
... | @@ -180,33 +179,21 @@ public class FlowRuleManager | ... | @@ -180,33 +179,21 @@ public class FlowRuleManager |
180 | @Override | 179 | @Override |
181 | public Future<CompletedBatchOperation> applyBatch( | 180 | public Future<CompletedBatchOperation> applyBatch( |
182 | FlowRuleBatchOperation batch) { | 181 | FlowRuleBatchOperation batch) { |
183 | - Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches = | 182 | + Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches = |
184 | ArrayListMultimap.create(); | 183 | ArrayListMultimap.create(); |
185 | List<Future<CompletedBatchOperation>> futures = Lists.newArrayList(); | 184 | List<Future<CompletedBatchOperation>> futures = Lists.newArrayList(); |
186 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { | 185 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { |
187 | final FlowRule f = fbe.getTarget(); | 186 | final FlowRule f = fbe.getTarget(); |
188 | - final Device device = deviceService.getDevice(f.deviceId()); | 187 | + perDeviceBatches.put(f.deviceId(), fbe); |
189 | - final FlowRuleProvider frp = getProvider(device.providerId()); | ||
190 | - batches.put(frp, fbe); | ||
191 | - switch (fbe.getOperator()) { | ||
192 | - case ADD: | ||
193 | - store.storeFlowRule(f); | ||
194 | - break; | ||
195 | - case REMOVE: | ||
196 | - store.deleteFlowRule(f); | ||
197 | - break; | ||
198 | - case MODIFY: | ||
199 | - default: | ||
200 | - log.error("Batch operation type {} unsupported.", fbe.getOperator()); | ||
201 | - } | ||
202 | } | 188 | } |
203 | - for (FlowRuleProvider provider : batches.keySet()) { | 189 | + |
190 | + for (DeviceId deviceId : perDeviceBatches.keySet()) { | ||
204 | FlowRuleBatchOperation b = | 191 | FlowRuleBatchOperation b = |
205 | - new FlowRuleBatchOperation(batches.get(provider)); | 192 | + new FlowRuleBatchOperation(perDeviceBatches.get(deviceId)); |
206 | - Future<CompletedBatchOperation> future = provider.executeBatch(b); | 193 | + Future<CompletedBatchOperation> future = store.storeBatch(b); |
207 | futures.add(future); | 194 | futures.add(future); |
208 | } | 195 | } |
209 | - return new FlowRuleBatchFuture(futures, batches); | 196 | + return new FlowRuleBatchFuture(futures, perDeviceBatches); |
210 | } | 197 | } |
211 | 198 | ||
212 | @Override | 199 | @Override |
... | @@ -318,6 +305,7 @@ public class FlowRuleManager | ... | @@ -318,6 +305,7 @@ public class FlowRuleManager |
318 | post(event); | 305 | post(event); |
319 | } | 306 | } |
320 | } else { | 307 | } else { |
308 | + log.info("Removing flow rules...."); | ||
321 | removeFlowRules(flowEntry); | 309 | removeFlowRules(flowEntry); |
322 | } | 310 | } |
323 | 311 | ||
... | @@ -385,21 +373,47 @@ public class FlowRuleManager | ... | @@ -385,21 +373,47 @@ public class FlowRuleManager |
385 | 373 | ||
386 | // Store delegate to re-post events emitted from the store. | 374 | // Store delegate to re-post events emitted from the store. |
387 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { | 375 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { |
376 | + // TODO: Right now we only dispatch events at individual flowEntry level. | ||
377 | + // It may be more efficient for also dispatch events as a batch. | ||
388 | @Override | 378 | @Override |
389 | - public void notify(FlowRuleEvent event) { | 379 | + public void notify(FlowRuleBatchEvent event) { |
380 | + final FlowRuleBatchRequest request = event.subject(); | ||
390 | switch (event.type()) { | 381 | switch (event.type()) { |
391 | - case RULE_ADD_REQUESTED: | 382 | + case BATCH_OPERATION_REQUESTED: |
392 | - applyFlowRulesToProviders(event.subject()); | 383 | +// for (FlowEntry entry : request.toAdd()) { |
393 | - break; | 384 | +// //eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, entry)); |
394 | - case RULE_REMOVE_REQUESTED: | 385 | +// } |
395 | - removeFlowRulesFromProviders(event.subject()); | 386 | +// for (FlowEntry entry : request.toRemove()) { |
396 | - break; | 387 | +// //eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, entry)); |
388 | +// } | ||
389 | +// // FIXME: what about op.equals(FlowRuleOperation.MODIFY) ? | ||
390 | +// | ||
391 | + FlowRuleBatchOperation batchOperation = request.asBatchOperation(); | ||
392 | + | ||
393 | + FlowRuleProvider flowRuleProvider = | ||
394 | + getProvider(batchOperation.getOperations().get(0).getTarget().deviceId()); | ||
395 | + final ListenableFuture<CompletedBatchOperation> result = | ||
396 | + flowRuleProvider.executeBatch(batchOperation); | ||
397 | + result.addListener(new Runnable() { | ||
398 | + @Override | ||
399 | + public void run() { | ||
400 | + store.batchOperationComplete(FlowRuleBatchEvent.create(request, Futures.getUnchecked(result))); | ||
401 | + } | ||
402 | + }, Executors.newCachedThreadPool()); | ||
397 | 403 | ||
398 | - case RULE_ADDED: | 404 | + break; |
399 | - case RULE_REMOVED: | 405 | + case BATCH_OPERATION_COMPLETED: |
400 | - case RULE_UPDATED: | 406 | + Set<FlowEntry> failedItems = event.result().failedItems(); |
401 | - // only dispatch events related to switch | 407 | + for (FlowEntry entry : request.toAdd()) { |
402 | - eventDispatcher.post(event); | 408 | + if (!failedItems.contains(entry)) { |
409 | + eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADDED, entry)); | ||
410 | + } | ||
411 | + } | ||
412 | + for (FlowEntry entry : request.toRemove()) { | ||
413 | + if (!failedItems.contains(entry)) { | ||
414 | + eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVED, entry)); | ||
415 | + } | ||
416 | + } | ||
403 | break; | 417 | break; |
404 | default: | 418 | default: |
405 | break; | 419 | break; |
... | @@ -407,18 +421,15 @@ public class FlowRuleManager | ... | @@ -407,18 +421,15 @@ public class FlowRuleManager |
407 | } | 421 | } |
408 | } | 422 | } |
409 | 423 | ||
410 | - private class FlowRuleBatchFuture | 424 | + private class FlowRuleBatchFuture implements Future<CompletedBatchOperation> { |
411 | - implements Future<CompletedBatchOperation> { | ||
412 | 425 | ||
413 | private final List<Future<CompletedBatchOperation>> futures; | 426 | private final List<Future<CompletedBatchOperation>> futures; |
414 | - private final Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches; | 427 | + private final Multimap<DeviceId, FlowRuleBatchEntry> batches; |
415 | private final AtomicReference<BatchState> state; | 428 | private final AtomicReference<BatchState> state; |
416 | private CompletedBatchOperation overall; | 429 | private CompletedBatchOperation overall; |
417 | 430 | ||
418 | - | ||
419 | - | ||
420 | public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures, | 431 | public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures, |
421 | - Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches) { | 432 | + Multimap<DeviceId, FlowRuleBatchEntry> batches) { |
422 | this.futures = futures; | 433 | this.futures = futures; |
423 | this.batches = batches; | 434 | this.batches = batches; |
424 | state = new AtomicReference<FlowRuleManager.BatchState>(); | 435 | state = new AtomicReference<FlowRuleManager.BatchState>(); |
... | @@ -460,7 +471,7 @@ public class FlowRuleManager | ... | @@ -460,7 +471,7 @@ public class FlowRuleManager |
460 | } | 471 | } |
461 | 472 | ||
462 | boolean success = true; | 473 | boolean success = true; |
463 | - List<FlowEntry> failed = Lists.newLinkedList(); | 474 | + Set<FlowEntry> failed = Sets.newHashSet(); |
464 | CompletedBatchOperation completed; | 475 | CompletedBatchOperation completed; |
465 | for (Future<CompletedBatchOperation> future : futures) { | 476 | for (Future<CompletedBatchOperation> future : futures) { |
466 | completed = future.get(); | 477 | completed = future.get(); |
... | @@ -480,7 +491,7 @@ public class FlowRuleManager | ... | @@ -480,7 +491,7 @@ public class FlowRuleManager |
480 | return overall; | 491 | return overall; |
481 | } | 492 | } |
482 | boolean success = true; | 493 | boolean success = true; |
483 | - List<FlowEntry> failed = Lists.newLinkedList(); | 494 | + Set<FlowEntry> failed = Sets.newHashSet(); |
484 | CompletedBatchOperation completed; | 495 | CompletedBatchOperation completed; |
485 | long start = System.nanoTime(); | 496 | long start = System.nanoTime(); |
486 | long end = start + unit.toNanos(timeout); | 497 | long end = start + unit.toNanos(timeout); |
... | @@ -494,7 +505,7 @@ public class FlowRuleManager | ... | @@ -494,7 +505,7 @@ public class FlowRuleManager |
494 | return finalizeBatchOperation(success, failed); | 505 | return finalizeBatchOperation(success, failed); |
495 | } | 506 | } |
496 | 507 | ||
497 | - private boolean validateBatchOperation(List<FlowEntry> failed, | 508 | + private boolean validateBatchOperation(Set<FlowEntry> failed, |
498 | CompletedBatchOperation completed) { | 509 | CompletedBatchOperation completed) { |
499 | 510 | ||
500 | if (isCancelled()) { | 511 | if (isCancelled()) { |
... | @@ -516,7 +527,7 @@ public class FlowRuleManager | ... | @@ -516,7 +527,7 @@ public class FlowRuleManager |
516 | } | 527 | } |
517 | 528 | ||
518 | private CompletedBatchOperation finalizeBatchOperation(boolean success, | 529 | private CompletedBatchOperation finalizeBatchOperation(boolean success, |
519 | - List<FlowEntry> failed) { | 530 | + Set<FlowEntry> failed) { |
520 | synchronized (this) { | 531 | synchronized (this) { |
521 | if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) { | 532 | if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) { |
522 | if (state.get() == BatchState.FINISHED) { | 533 | if (state.get() == BatchState.FINISHED) { |
... | @@ -539,11 +550,6 @@ public class FlowRuleManager | ... | @@ -539,11 +550,6 @@ public class FlowRuleManager |
539 | store.storeFlowRule(fbe.getTarget()); | 550 | store.storeFlowRule(fbe.getTarget()); |
540 | } | 551 | } |
541 | } | 552 | } |
542 | - | ||
543 | } | 553 | } |
544 | } | 554 | } |
545 | - | ||
546 | - | ||
547 | - | ||
548 | - | ||
549 | } | 555 | } | ... | ... |
1 | package org.onlab.onos.net.flow.impl; | 1 | package org.onlab.onos.net.flow.impl; |
2 | 2 | ||
3 | -import static java.util.Collections.EMPTY_LIST; | ||
4 | import static org.junit.Assert.assertEquals; | 3 | import static org.junit.Assert.assertEquals; |
5 | import static org.junit.Assert.assertFalse; | 4 | import static org.junit.Assert.assertFalse; |
6 | import static org.junit.Assert.assertNotNull; | 5 | import static org.junit.Assert.assertNotNull; |
... | @@ -17,6 +16,7 @@ import java.util.List; | ... | @@ -17,6 +16,7 @@ import java.util.List; |
17 | import java.util.Map; | 16 | import java.util.Map; |
18 | import java.util.Set; | 17 | import java.util.Set; |
19 | import java.util.concurrent.ExecutionException; | 18 | import java.util.concurrent.ExecutionException; |
19 | +import java.util.concurrent.Executor; | ||
20 | import java.util.concurrent.Future; | 20 | import java.util.concurrent.Future; |
21 | import java.util.concurrent.TimeUnit; | 21 | import java.util.concurrent.TimeUnit; |
22 | import java.util.concurrent.TimeoutException; | 22 | import java.util.concurrent.TimeoutException; |
... | @@ -64,6 +64,7 @@ import com.google.common.collect.ImmutableList; | ... | @@ -64,6 +64,7 @@ import com.google.common.collect.ImmutableList; |
64 | import com.google.common.collect.ImmutableMap; | 64 | import com.google.common.collect.ImmutableMap; |
65 | import com.google.common.collect.Lists; | 65 | import com.google.common.collect.Lists; |
66 | import com.google.common.collect.Sets; | 66 | import com.google.common.collect.Sets; |
67 | +import com.google.common.util.concurrent.ListenableFuture; | ||
67 | 68 | ||
68 | /** | 69 | /** |
69 | * Test codifying the flow rule service & flow rule provider service contracts. | 70 | * Test codifying the flow rule service & flow rule provider service contracts. |
... | @@ -515,13 +516,13 @@ public class FlowRuleManagerTest { | ... | @@ -515,13 +516,13 @@ public class FlowRuleManagerTest { |
515 | } | 516 | } |
516 | 517 | ||
517 | @Override | 518 | @Override |
518 | - public Future<CompletedBatchOperation> executeBatch( | 519 | + public ListenableFuture<CompletedBatchOperation> executeBatch( |
519 | BatchOperation<FlowRuleBatchEntry> batch) { | 520 | BatchOperation<FlowRuleBatchEntry> batch) { |
520 | return new TestInstallationFuture(); | 521 | return new TestInstallationFuture(); |
521 | } | 522 | } |
522 | 523 | ||
523 | private class TestInstallationFuture | 524 | private class TestInstallationFuture |
524 | - implements Future<CompletedBatchOperation> { | 525 | + implements ListenableFuture<CompletedBatchOperation> { |
525 | 526 | ||
526 | @Override | 527 | @Override |
527 | public boolean cancel(boolean mayInterruptIfRunning) { | 528 | public boolean cancel(boolean mayInterruptIfRunning) { |
... | @@ -541,7 +542,7 @@ public class FlowRuleManagerTest { | ... | @@ -541,7 +542,7 @@ public class FlowRuleManagerTest { |
541 | @Override | 542 | @Override |
542 | public CompletedBatchOperation get() | 543 | public CompletedBatchOperation get() |
543 | throws InterruptedException, ExecutionException { | 544 | throws InterruptedException, ExecutionException { |
544 | - return new CompletedBatchOperation(true, EMPTY_LIST); | 545 | + return new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet()); |
545 | } | 546 | } |
546 | 547 | ||
547 | @Override | 548 | @Override |
... | @@ -550,6 +551,11 @@ public class FlowRuleManagerTest { | ... | @@ -550,6 +551,11 @@ public class FlowRuleManagerTest { |
550 | ExecutionException, TimeoutException { | 551 | ExecutionException, TimeoutException { |
551 | return null; | 552 | return null; |
552 | } | 553 | } |
554 | + | ||
555 | + @Override | ||
556 | + public void addListener(Runnable task, Executor executor) { | ||
557 | + // TODO: add stuff. | ||
558 | + } | ||
553 | } | 559 | } |
554 | 560 | ||
555 | } | 561 | } | ... | ... |
... | @@ -5,10 +5,14 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,10 +5,14 @@ import static org.slf4j.LoggerFactory.getLogger; |
5 | import static org.onlab.onos.store.flow.impl.FlowStoreMessageSubjects.*; | 5 | import static org.onlab.onos.store.flow.impl.FlowStoreMessageSubjects.*; |
6 | 6 | ||
7 | import java.io.IOException; | 7 | import java.io.IOException; |
8 | +import java.util.ArrayList; | ||
9 | +import java.util.Arrays; | ||
8 | import java.util.Collection; | 10 | import java.util.Collection; |
9 | import java.util.Collections; | 11 | import java.util.Collections; |
12 | +import java.util.concurrent.Future; | ||
10 | import java.util.concurrent.TimeUnit; | 13 | import java.util.concurrent.TimeUnit; |
11 | import java.util.concurrent.TimeoutException; | 14 | import java.util.concurrent.TimeoutException; |
15 | +import java.util.List; | ||
12 | 16 | ||
13 | import org.apache.felix.scr.annotations.Activate; | 17 | import org.apache.felix.scr.annotations.Activate; |
14 | import org.apache.felix.scr.annotations.Component; | 18 | import org.apache.felix.scr.annotations.Component; |
... | @@ -19,11 +23,17 @@ import org.apache.felix.scr.annotations.Service; | ... | @@ -19,11 +23,17 @@ import org.apache.felix.scr.annotations.Service; |
19 | import org.onlab.onos.ApplicationId; | 23 | import org.onlab.onos.ApplicationId; |
20 | import org.onlab.onos.cluster.ClusterService; | 24 | import org.onlab.onos.cluster.ClusterService; |
21 | import org.onlab.onos.net.DeviceId; | 25 | import org.onlab.onos.net.DeviceId; |
26 | +import org.onlab.onos.net.flow.CompletedBatchOperation; | ||
22 | import org.onlab.onos.net.flow.DefaultFlowEntry; | 27 | import org.onlab.onos.net.flow.DefaultFlowEntry; |
23 | import org.onlab.onos.net.flow.FlowEntry; | 28 | import org.onlab.onos.net.flow.FlowEntry; |
24 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; | 29 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; |
25 | import org.onlab.onos.net.flow.FlowRule; | 30 | import org.onlab.onos.net.flow.FlowRule; |
31 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
32 | +import org.onlab.onos.net.flow.FlowRuleBatchEvent; | ||
33 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
34 | +import org.onlab.onos.net.flow.FlowRuleBatchRequest; | ||
26 | import org.onlab.onos.net.flow.FlowRuleEvent; | 35 | import org.onlab.onos.net.flow.FlowRuleEvent; |
36 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
27 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; | 37 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; |
28 | import org.onlab.onos.net.flow.FlowRuleStore; | 38 | import org.onlab.onos.net.flow.FlowRuleStore; |
29 | import org.onlab.onos.net.flow.FlowRuleStoreDelegate; | 39 | import org.onlab.onos.net.flow.FlowRuleStoreDelegate; |
... | @@ -43,6 +53,7 @@ import org.slf4j.Logger; | ... | @@ -43,6 +53,7 @@ import org.slf4j.Logger; |
43 | import com.google.common.collect.ArrayListMultimap; | 53 | import com.google.common.collect.ArrayListMultimap; |
44 | import com.google.common.collect.ImmutableSet; | 54 | import com.google.common.collect.ImmutableSet; |
45 | import com.google.common.collect.Multimap; | 55 | import com.google.common.collect.Multimap; |
56 | +import com.google.common.util.concurrent.Futures; | ||
46 | 57 | ||
47 | /** | 58 | /** |
48 | * Manages inventory of flow rules using a distributed state management protocol. | 59 | * Manages inventory of flow rules using a distributed state management protocol. |
... | @@ -50,7 +61,7 @@ import com.google.common.collect.Multimap; | ... | @@ -50,7 +61,7 @@ import com.google.common.collect.Multimap; |
50 | @Component(immediate = true) | 61 | @Component(immediate = true) |
51 | @Service | 62 | @Service |
52 | public class DistributedFlowRuleStore | 63 | public class DistributedFlowRuleStore |
53 | - extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate> | 64 | + extends AbstractStore<FlowRuleBatchEvent, FlowRuleStoreDelegate> |
54 | implements FlowRuleStore { | 65 | implements FlowRuleStore { |
55 | 66 | ||
56 | private final Logger log = getLogger(getClass()); | 67 | private final Logger log = getLogger(getClass()); |
... | @@ -92,7 +103,7 @@ public class DistributedFlowRuleStore | ... | @@ -92,7 +103,7 @@ public class DistributedFlowRuleStore |
92 | public void handle(ClusterMessage message) { | 103 | public void handle(ClusterMessage message) { |
93 | FlowRule rule = SERIALIZER.decode(message.payload()); | 104 | FlowRule rule = SERIALIZER.decode(message.payload()); |
94 | log.info("received add request for {}", rule); | 105 | log.info("received add request for {}", rule); |
95 | - storeFlowEntryInternal(rule); | 106 | + storeFlowRule(rule); |
96 | // FIXME what to respond. | 107 | // FIXME what to respond. |
97 | try { | 108 | try { |
98 | message.respond(SERIALIZER.encode("ACK")); | 109 | message.respond(SERIALIZER.encode("ACK")); |
... | @@ -108,7 +119,7 @@ public class DistributedFlowRuleStore | ... | @@ -108,7 +119,7 @@ public class DistributedFlowRuleStore |
108 | public void handle(ClusterMessage message) { | 119 | public void handle(ClusterMessage message) { |
109 | FlowRule rule = SERIALIZER.decode(message.payload()); | 120 | FlowRule rule = SERIALIZER.decode(message.payload()); |
110 | log.info("received delete request for {}", rule); | 121 | log.info("received delete request for {}", rule); |
111 | - deleteFlowRuleInternal(rule); | 122 | + deleteFlowRule(rule); |
112 | // FIXME what to respond. | 123 | // FIXME what to respond. |
113 | try { | 124 | try { |
114 | message.respond(SERIALIZER.encode("ACK")); | 125 | message.respond(SERIALIZER.encode("ACK")); |
... | @@ -118,6 +129,22 @@ public class DistributedFlowRuleStore | ... | @@ -118,6 +129,22 @@ public class DistributedFlowRuleStore |
118 | 129 | ||
119 | } | 130 | } |
120 | }); | 131 | }); |
132 | + | ||
133 | + clusterCommunicator.addSubscriber(GET_FLOW_ENTRY, new ClusterMessageHandler() { | ||
134 | + | ||
135 | + @Override | ||
136 | + public void handle(ClusterMessage message) { | ||
137 | + FlowRule rule = SERIALIZER.decode(message.payload()); | ||
138 | + log.info("received get flow entry request for {}", rule); | ||
139 | + FlowEntry flowEntry = getFlowEntryInternal(rule); | ||
140 | + try { | ||
141 | + message.respond(SERIALIZER.encode(flowEntry)); | ||
142 | + } catch (IOException e) { | ||
143 | + log.error("Failed to respond back", e); | ||
144 | + } | ||
145 | + } | ||
146 | + }); | ||
147 | + | ||
121 | log.info("Started"); | 148 | log.info("Started"); |
122 | } | 149 | } |
123 | 150 | ||
... | @@ -127,6 +154,9 @@ public class DistributedFlowRuleStore | ... | @@ -127,6 +154,9 @@ public class DistributedFlowRuleStore |
127 | } | 154 | } |
128 | 155 | ||
129 | 156 | ||
157 | + // TODO: This is not a efficient operation on a distributed sharded | ||
158 | + // flow store. We need to revisit the need for this operation or at least | ||
159 | + // make it device specific. | ||
130 | @Override | 160 | @Override |
131 | public int getFlowRuleCount() { | 161 | public int getFlowRuleCount() { |
132 | return flowEntries.size(); | 162 | return flowEntries.size(); |
... | @@ -134,7 +164,26 @@ public class DistributedFlowRuleStore | ... | @@ -134,7 +164,26 @@ public class DistributedFlowRuleStore |
134 | 164 | ||
135 | @Override | 165 | @Override |
136 | public synchronized FlowEntry getFlowEntry(FlowRule rule) { | 166 | public synchronized FlowEntry getFlowEntry(FlowRule rule) { |
137 | - return getFlowEntryInternal(rule); | 167 | + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); |
168 | + if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | ||
169 | + return getFlowEntryInternal(rule); | ||
170 | + } | ||
171 | + | ||
172 | + log.info("Forwarding getFlowEntry to {}, which is the primary (master) for device {}", | ||
173 | + replicaInfo.master().orNull(), rule.deviceId()); | ||
174 | + | ||
175 | + ClusterMessage message = new ClusterMessage( | ||
176 | + clusterService.getLocalNode().id(), | ||
177 | + FlowStoreMessageSubjects.GET_FLOW_ENTRY, | ||
178 | + SERIALIZER.encode(rule)); | ||
179 | + | ||
180 | + try { | ||
181 | + ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | ||
182 | + return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); | ||
183 | + } catch (IOException | TimeoutException e) { | ||
184 | + // FIXME: throw a FlowStoreException | ||
185 | + throw new RuntimeException(e); | ||
186 | + } | ||
138 | } | 187 | } |
139 | 188 | ||
140 | private synchronized StoredFlowEntry getFlowEntryInternal(FlowRule rule) { | 189 | private synchronized StoredFlowEntry getFlowEntryInternal(FlowRule rule) { |
... | @@ -165,19 +214,30 @@ public class DistributedFlowRuleStore | ... | @@ -165,19 +214,30 @@ public class DistributedFlowRuleStore |
165 | } | 214 | } |
166 | 215 | ||
167 | @Override | 216 | @Override |
168 | - public boolean storeFlowRule(FlowRule rule) { | 217 | + public void storeFlowRule(FlowRule rule) { |
169 | - ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | 218 | + storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)))); |
219 | + } | ||
220 | + | ||
221 | + public Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation operation) { | ||
222 | + if (operation.getOperations().isEmpty()) { | ||
223 | + return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet())); | ||
224 | + } | ||
225 | + | ||
226 | + DeviceId deviceId = operation.getOperations().get(0).getTarget().deviceId(); | ||
227 | + | ||
228 | + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); | ||
229 | + | ||
170 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 230 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { |
171 | - return storeFlowEntryInternal(rule); | 231 | + return storeBatchInternal(operation); |
172 | } | 232 | } |
173 | 233 | ||
174 | - log.info("Forwarding storeFlowRule to {}, which is the primary (master) for device {}", | 234 | + log.info("Forwarding storeBatch to {}, which is the primary (master) for device {}", |
175 | - replicaInfo.master().orNull(), rule.deviceId()); | 235 | + replicaInfo.master().orNull(), deviceId); |
176 | 236 | ||
177 | ClusterMessage message = new ClusterMessage( | 237 | ClusterMessage message = new ClusterMessage( |
178 | clusterService.getLocalNode().id(), | 238 | clusterService.getLocalNode().id(), |
179 | FlowStoreMessageSubjects.STORE_FLOW_RULE, | 239 | FlowStoreMessageSubjects.STORE_FLOW_RULE, |
180 | - SERIALIZER.encode(rule)); | 240 | + SERIALIZER.encode(operation)); |
181 | 241 | ||
182 | try { | 242 | try { |
183 | ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | 243 | ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); |
... | @@ -186,58 +246,44 @@ public class DistributedFlowRuleStore | ... | @@ -186,58 +246,44 @@ public class DistributedFlowRuleStore |
186 | // FIXME: throw a FlowStoreException | 246 | // FIXME: throw a FlowStoreException |
187 | throw new RuntimeException(e); | 247 | throw new RuntimeException(e); |
188 | } | 248 | } |
189 | - return false; | ||
190 | - } | ||
191 | 249 | ||
192 | - private synchronized boolean storeFlowEntryInternal(FlowRule flowRule) { | 250 | + return null; |
193 | - StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); | ||
194 | - DeviceId deviceId = flowRule.deviceId(); | ||
195 | - // write to local copy. | ||
196 | - if (!flowEntries.containsEntry(deviceId, flowEntry)) { | ||
197 | - flowEntries.put(deviceId, flowEntry); | ||
198 | - flowEntriesById.put(flowRule.appId(), flowEntry); | ||
199 | - notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, flowRule)); | ||
200 | - return true; | ||
201 | - } | ||
202 | - // write to backup. | ||
203 | - // TODO: write to a hazelcast map. | ||
204 | - return false; | ||
205 | } | 251 | } |
206 | 252 | ||
207 | - @Override | 253 | + private Future<CompletedBatchOperation> storeBatchInternal(FlowRuleBatchOperation operation) { |
208 | - public synchronized boolean deleteFlowRule(FlowRule rule) { | 254 | + List<FlowEntry> toRemove = new ArrayList<>(); |
209 | - ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | 255 | + List<FlowEntry> toAdd = new ArrayList<>(); |
210 | - if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 256 | + // TODO: backup changes to hazelcast map |
211 | - return deleteFlowRuleInternal(rule); | 257 | + for (FlowRuleBatchEntry batchEntry : operation.getOperations()) { |
258 | + FlowRule flowRule = batchEntry.getTarget(); | ||
259 | + FlowRuleOperation op = batchEntry.getOperator(); | ||
260 | + if (op.equals(FlowRuleOperation.REMOVE)) { | ||
261 | + StoredFlowEntry entry = getFlowEntryInternal(flowRule); | ||
262 | + if (entry != null) { | ||
263 | + entry.setState(FlowEntryState.PENDING_REMOVE); | ||
264 | + } | ||
265 | + toRemove.add(entry); | ||
266 | + } else if (op.equals(FlowRuleOperation.ADD)) { | ||
267 | + StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); | ||
268 | + DeviceId deviceId = flowRule.deviceId(); | ||
269 | + if (!flowEntries.containsEntry(deviceId, flowEntry)) { | ||
270 | + flowEntries.put(deviceId, flowEntry); | ||
271 | + flowEntriesById.put(flowRule.appId(), flowEntry); | ||
272 | + toAdd.add(flowEntry); | ||
273 | + } | ||
274 | + } | ||
212 | } | 275 | } |
213 | - | 276 | + if (toAdd.isEmpty() && toRemove.isEmpty()) { |
214 | - ClusterMessage message = new ClusterMessage( | 277 | + return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet())); |
215 | - clusterService.getLocalNode().id(), | ||
216 | - FlowStoreMessageSubjects.DELETE_FLOW_RULE, | ||
217 | - SERIALIZER.encode(rule)); | ||
218 | - | ||
219 | - try { | ||
220 | - ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | ||
221 | - response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); | ||
222 | - } catch (IOException | TimeoutException e) { | ||
223 | - // FIXME: throw a FlowStoreException | ||
224 | - throw new RuntimeException(e); | ||
225 | } | 278 | } |
226 | - return false; | 279 | + notifyDelegate(FlowRuleBatchEvent.create(new FlowRuleBatchRequest(toAdd, toRemove))); |
280 | + // TODO: imlpement this. | ||
281 | + return Futures.immediateFailedFuture(new RuntimeException("Implement this.")); | ||
227 | } | 282 | } |
228 | 283 | ||
229 | - private synchronized boolean deleteFlowRuleInternal(FlowRule flowRule) { | 284 | + @Override |
230 | - StoredFlowEntry entry = getFlowEntryInternal(flowRule); | 285 | + public void deleteFlowRule(FlowRule rule) { |
231 | - if (entry == null) { | 286 | + storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)))); |
232 | - return false; | ||
233 | - } | ||
234 | - entry.setState(FlowEntryState.PENDING_REMOVE); | ||
235 | - | ||
236 | - // TODO: also update backup. | ||
237 | - | ||
238 | - notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, flowRule)); | ||
239 | - | ||
240 | - return true; | ||
241 | } | 287 | } |
242 | 288 | ||
243 | @Override | 289 | @Override |
... | @@ -315,4 +361,9 @@ public class DistributedFlowRuleStore | ... | @@ -315,4 +361,9 @@ public class DistributedFlowRuleStore |
315 | } | 361 | } |
316 | // TODO: also update backup. | 362 | // TODO: also update backup. |
317 | } | 363 | } |
364 | + | ||
365 | + @Override | ||
366 | + public void batchOperationComplete(FlowRuleBatchEvent event) { | ||
367 | + notifyDelegate(event); | ||
368 | + } | ||
318 | } | 369 | } | ... | ... |
... | @@ -12,4 +12,5 @@ public final class FlowStoreMessageSubjects { | ... | @@ -12,4 +12,5 @@ public final class FlowStoreMessageSubjects { |
12 | public static final MessageSubject ADD_OR_UPDATE_FLOW_RULE = | 12 | public static final MessageSubject ADD_OR_UPDATE_FLOW_RULE = |
13 | new MessageSubject("peer-forward-add-or-update-flow-rule"); | 13 | new MessageSubject("peer-forward-add-or-update-flow-rule"); |
14 | public static final MessageSubject REMOVE_FLOW_RULE = new MessageSubject("peer-forward-remove-flow-rule"); | 14 | public static final MessageSubject REMOVE_FLOW_RULE = new MessageSubject("peer-forward-remove-flow-rule"); |
15 | + public static final MessageSubject GET_FLOW_ENTRY = new MessageSubject("peer-forward-get-flow-entry"); | ||
15 | } | 16 | } | ... | ... |
... | @@ -26,10 +26,12 @@ import org.onlab.onos.net.Port; | ... | @@ -26,10 +26,12 @@ import org.onlab.onos.net.Port; |
26 | import org.onlab.onos.net.PortNumber; | 26 | import org.onlab.onos.net.PortNumber; |
27 | import org.onlab.onos.net.device.DefaultDeviceDescription; | 27 | import org.onlab.onos.net.device.DefaultDeviceDescription; |
28 | import org.onlab.onos.net.device.DefaultPortDescription; | 28 | import org.onlab.onos.net.device.DefaultPortDescription; |
29 | +import org.onlab.onos.net.flow.DefaultFlowEntry; | ||
29 | import org.onlab.onos.net.flow.DefaultFlowRule; | 30 | import org.onlab.onos.net.flow.DefaultFlowRule; |
30 | import org.onlab.onos.net.flow.DefaultTrafficSelector; | 31 | import org.onlab.onos.net.flow.DefaultTrafficSelector; |
31 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; | 32 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; |
32 | import org.onlab.onos.net.flow.FlowId; | 33 | import org.onlab.onos.net.flow.FlowId; |
34 | +import org.onlab.onos.net.flow.StoredFlowEntry; | ||
33 | import org.onlab.onos.net.flow.criteria.Criteria; | 35 | import org.onlab.onos.net.flow.criteria.Criteria; |
34 | import org.onlab.onos.net.flow.criteria.Criterion; | 36 | import org.onlab.onos.net.flow.criteria.Criterion; |
35 | import org.onlab.onos.net.flow.instructions.Instructions; | 37 | import org.onlab.onos.net.flow.instructions.Instructions; |
... | @@ -93,6 +95,8 @@ public final class KryoNamespaces { | ... | @@ -93,6 +95,8 @@ public final class KryoNamespaces { |
93 | HostId.class, | 95 | HostId.class, |
94 | HostDescription.class, | 96 | HostDescription.class, |
95 | DefaultHostDescription.class, | 97 | DefaultHostDescription.class, |
98 | + DefaultFlowEntry.class, | ||
99 | + StoredFlowEntry.class, | ||
96 | DefaultFlowRule.class, | 100 | DefaultFlowRule.class, |
97 | FlowId.class, | 101 | FlowId.class, |
98 | DefaultTrafficSelector.class, | 102 | DefaultTrafficSelector.class, | ... | ... |
... | @@ -3,6 +3,8 @@ package org.onlab.onos.store.trivial.impl; | ... | @@ -3,6 +3,8 @@ package org.onlab.onos.store.trivial.impl; |
3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; |
4 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
5 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | 5 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; |
6 | + | ||
7 | +import java.util.Arrays; | ||
6 | import java.util.Collections; | 8 | import java.util.Collections; |
7 | import java.util.HashSet; | 9 | import java.util.HashSet; |
8 | import java.util.List; | 10 | import java.util.List; |
... | @@ -10,6 +12,7 @@ import java.util.Set; | ... | @@ -10,6 +12,7 @@ import java.util.Set; |
10 | import java.util.concurrent.ConcurrentHashMap; | 12 | import java.util.concurrent.ConcurrentHashMap; |
11 | import java.util.concurrent.ConcurrentMap; | 13 | import java.util.concurrent.ConcurrentMap; |
12 | import java.util.concurrent.CopyOnWriteArrayList; | 14 | import java.util.concurrent.CopyOnWriteArrayList; |
15 | +import java.util.concurrent.Future; | ||
13 | 16 | ||
14 | import org.apache.felix.scr.annotations.Activate; | 17 | import org.apache.felix.scr.annotations.Activate; |
15 | import org.apache.felix.scr.annotations.Component; | 18 | import org.apache.felix.scr.annotations.Component; |
... | @@ -17,11 +20,17 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -17,11 +20,17 @@ import org.apache.felix.scr.annotations.Deactivate; |
17 | import org.apache.felix.scr.annotations.Service; | 20 | import org.apache.felix.scr.annotations.Service; |
18 | import org.onlab.onos.ApplicationId; | 21 | import org.onlab.onos.ApplicationId; |
19 | import org.onlab.onos.net.DeviceId; | 22 | import org.onlab.onos.net.DeviceId; |
23 | +import org.onlab.onos.net.flow.CompletedBatchOperation; | ||
20 | import org.onlab.onos.net.flow.DefaultFlowEntry; | 24 | import org.onlab.onos.net.flow.DefaultFlowEntry; |
21 | import org.onlab.onos.net.flow.FlowEntry; | 25 | import org.onlab.onos.net.flow.FlowEntry; |
22 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; | 26 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; |
23 | import org.onlab.onos.net.flow.FlowId; | 27 | import org.onlab.onos.net.flow.FlowId; |
24 | import org.onlab.onos.net.flow.FlowRule; | 28 | import org.onlab.onos.net.flow.FlowRule; |
29 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
30 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
31 | +import org.onlab.onos.net.flow.FlowRuleBatchEvent; | ||
32 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
33 | +import org.onlab.onos.net.flow.FlowRuleBatchRequest; | ||
25 | import org.onlab.onos.net.flow.FlowRuleEvent; | 34 | import org.onlab.onos.net.flow.FlowRuleEvent; |
26 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; | 35 | import org.onlab.onos.net.flow.FlowRuleEvent.Type; |
27 | import org.onlab.onos.net.flow.FlowRuleStore; | 36 | import org.onlab.onos.net.flow.FlowRuleStore; |
... | @@ -33,6 +42,7 @@ import org.slf4j.Logger; | ... | @@ -33,6 +42,7 @@ import org.slf4j.Logger; |
33 | 42 | ||
34 | import com.google.common.base.Function; | 43 | import com.google.common.base.Function; |
35 | import com.google.common.collect.FluentIterable; | 44 | import com.google.common.collect.FluentIterable; |
45 | +import com.google.common.util.concurrent.Futures; | ||
36 | 46 | ||
37 | /** | 47 | /** |
38 | * Manages inventory of flow rules using trivial in-memory implementation. | 48 | * Manages inventory of flow rules using trivial in-memory implementation. |
... | @@ -40,7 +50,7 @@ import com.google.common.collect.FluentIterable; | ... | @@ -40,7 +50,7 @@ import com.google.common.collect.FluentIterable; |
40 | @Component(immediate = true) | 50 | @Component(immediate = true) |
41 | @Service | 51 | @Service |
42 | public class SimpleFlowRuleStore | 52 | public class SimpleFlowRuleStore |
43 | - extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate> | 53 | + extends AbstractStore<FlowRuleBatchEvent, FlowRuleStoreDelegate> |
44 | implements FlowRuleStore { | 54 | implements FlowRuleStore { |
45 | 55 | ||
46 | private final Logger log = getLogger(getClass()); | 56 | private final Logger log = getLogger(getClass()); |
... | @@ -148,12 +158,11 @@ public class SimpleFlowRuleStore | ... | @@ -148,12 +158,11 @@ public class SimpleFlowRuleStore |
148 | } | 158 | } |
149 | 159 | ||
150 | @Override | 160 | @Override |
151 | - public boolean storeFlowRule(FlowRule rule) { | 161 | + public void storeFlowRule(FlowRule rule) { |
152 | - final boolean added = storeFlowRuleInternal(rule); | 162 | + storeFlowRuleInternal(rule); |
153 | - return added; | ||
154 | } | 163 | } |
155 | 164 | ||
156 | - private boolean storeFlowRuleInternal(FlowRule rule) { | 165 | + private void storeFlowRuleInternal(FlowRule rule) { |
157 | StoredFlowEntry f = new DefaultFlowEntry(rule); | 166 | StoredFlowEntry f = new DefaultFlowEntry(rule); |
158 | final DeviceId did = f.deviceId(); | 167 | final DeviceId did = f.deviceId(); |
159 | final FlowId fid = f.id(); | 168 | final FlowId fid = f.id(); |
... | @@ -162,19 +171,20 @@ public class SimpleFlowRuleStore | ... | @@ -162,19 +171,20 @@ public class SimpleFlowRuleStore |
162 | for (StoredFlowEntry fe : existing) { | 171 | for (StoredFlowEntry fe : existing) { |
163 | if (fe.equals(rule)) { | 172 | if (fe.equals(rule)) { |
164 | // was already there? ignore | 173 | // was already there? ignore |
165 | - return false; | 174 | + return; |
166 | } | 175 | } |
167 | } | 176 | } |
168 | // new flow rule added | 177 | // new flow rule added |
169 | existing.add(f); | 178 | existing.add(f); |
170 | - // TODO: Should we notify only if it's "remote" event? | 179 | + notifyDelegate(FlowRuleBatchEvent.create( |
171 | - //notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, rule)); | 180 | + new FlowRuleBatchRequest( |
172 | - return true; | 181 | + Arrays.<FlowEntry>asList(f), |
182 | + Collections.<FlowEntry>emptyList()))); | ||
173 | } | 183 | } |
174 | } | 184 | } |
175 | 185 | ||
176 | @Override | 186 | @Override |
177 | - public boolean deleteFlowRule(FlowRule rule) { | 187 | + public void deleteFlowRule(FlowRule rule) { |
178 | 188 | ||
179 | List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id()); | 189 | List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id()); |
180 | synchronized (entries) { | 190 | synchronized (entries) { |
... | @@ -184,13 +194,11 @@ public class SimpleFlowRuleStore | ... | @@ -184,13 +194,11 @@ public class SimpleFlowRuleStore |
184 | entry.setState(FlowEntryState.PENDING_REMOVE); | 194 | entry.setState(FlowEntryState.PENDING_REMOVE); |
185 | // TODO: Should we notify only if it's "remote" event? | 195 | // TODO: Should we notify only if it's "remote" event? |
186 | //notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, rule)); | 196 | //notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, rule)); |
187 | - return true; | ||
188 | } | 197 | } |
189 | } | 198 | } |
190 | } | 199 | } |
191 | } | 200 | } |
192 | //log.warn("Cannot find rule {}", rule); | 201 | //log.warn("Cannot find rule {}", rule); |
193 | - return false; | ||
194 | } | 202 | } |
195 | 203 | ||
196 | @Override | 204 | @Override |
... | @@ -236,4 +244,24 @@ public class SimpleFlowRuleStore | ... | @@ -236,4 +244,24 @@ public class SimpleFlowRuleStore |
236 | } | 244 | } |
237 | return null; | 245 | return null; |
238 | } | 246 | } |
247 | + | ||
248 | + @Override | ||
249 | + public Future<CompletedBatchOperation> storeBatch( | ||
250 | + FlowRuleBatchOperation batchOperation) { | ||
251 | + for (FlowRuleBatchEntry entry : batchOperation.getOperations()) { | ||
252 | + if (entry.getOperator().equals(FlowRuleOperation.ADD)) { | ||
253 | + storeFlowRule(entry.getTarget()); | ||
254 | + } else if (entry.getOperator().equals(FlowRuleOperation.REMOVE)) { | ||
255 | + deleteFlowRule(entry.getTarget()); | ||
256 | + } else { | ||
257 | + throw new UnsupportedOperationException("Unsupported operation type"); | ||
258 | + } | ||
259 | + } | ||
260 | + return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet())); | ||
261 | + } | ||
262 | + | ||
263 | + @Override | ||
264 | + public void batchOperationComplete(FlowRuleBatchEvent event) { | ||
265 | + notifyDelegate(event); | ||
266 | + } | ||
239 | } | 267 | } | ... | ... |
providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
... | @@ -10,7 +10,7 @@ import java.util.Set; | ... | @@ -10,7 +10,7 @@ import java.util.Set; |
10 | import java.util.concurrent.ConcurrentHashMap; | 10 | import java.util.concurrent.ConcurrentHashMap; |
11 | import java.util.concurrent.CountDownLatch; | 11 | import java.util.concurrent.CountDownLatch; |
12 | import java.util.concurrent.ExecutionException; | 12 | import java.util.concurrent.ExecutionException; |
13 | -import java.util.concurrent.Future; | 13 | +import java.util.concurrent.Executor; |
14 | import java.util.concurrent.TimeUnit; | 14 | import java.util.concurrent.TimeUnit; |
15 | import java.util.concurrent.TimeoutException; | 15 | import java.util.concurrent.TimeoutException; |
16 | import java.util.concurrent.atomic.AtomicBoolean; | 16 | import java.util.concurrent.atomic.AtomicBoolean; |
... | @@ -69,9 +69,11 @@ import org.projectfloodlight.openflow.types.U32; | ... | @@ -69,9 +69,11 @@ import org.projectfloodlight.openflow.types.U32; |
69 | import org.slf4j.Logger; | 69 | import org.slf4j.Logger; |
70 | 70 | ||
71 | import com.google.common.collect.ArrayListMultimap; | 71 | import com.google.common.collect.ArrayListMultimap; |
72 | -import com.google.common.collect.Lists; | ||
73 | import com.google.common.collect.Maps; | 72 | import com.google.common.collect.Maps; |
74 | import com.google.common.collect.Multimap; | 73 | import com.google.common.collect.Multimap; |
74 | +import com.google.common.collect.Sets; | ||
75 | +import com.google.common.util.concurrent.ExecutionList; | ||
76 | +import com.google.common.util.concurrent.ListenableFuture; | ||
75 | 77 | ||
76 | /** | 78 | /** |
77 | * Provider which uses an OpenFlow controller to detect network | 79 | * Provider which uses an OpenFlow controller to detect network |
... | @@ -97,6 +99,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -97,6 +99,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
97 | 99 | ||
98 | private final InternalFlowProvider listener = new InternalFlowProvider(); | 100 | private final InternalFlowProvider listener = new InternalFlowProvider(); |
99 | 101 | ||
102 | + // FIXME: This should be an expiring map to ensure futures that don't have | ||
103 | + // a future eventually get garbage collected. | ||
100 | private final Map<Long, InstallationFuture> pendingFutures = | 104 | private final Map<Long, InstallationFuture> pendingFutures = |
101 | new ConcurrentHashMap<Long, InstallationFuture>(); | 105 | new ConcurrentHashMap<Long, InstallationFuture>(); |
102 | 106 | ||
... | @@ -159,7 +163,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -159,7 +163,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
159 | } | 163 | } |
160 | 164 | ||
161 | @Override | 165 | @Override |
162 | - public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) { | 166 | + public ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) { |
163 | final Set<Dpid> sws = | 167 | final Set<Dpid> sws = |
164 | Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>()); | 168 | Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>()); |
165 | final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>(); | 169 | final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>(); |
... | @@ -315,18 +319,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -315,18 +319,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
315 | } | 319 | } |
316 | } | 320 | } |
317 | 321 | ||
318 | - private class InstallationFuture implements Future<CompletedBatchOperation> { | 322 | + private class InstallationFuture implements ListenableFuture<CompletedBatchOperation> { |
319 | 323 | ||
320 | private final Set<Dpid> sws; | 324 | private final Set<Dpid> sws; |
321 | private final AtomicBoolean ok = new AtomicBoolean(true); | 325 | private final AtomicBoolean ok = new AtomicBoolean(true); |
322 | private final Map<Long, FlowRuleBatchEntry> fms; | 326 | private final Map<Long, FlowRuleBatchEntry> fms; |
323 | 327 | ||
324 | - private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList(); | 328 | + private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet(); |
325 | 329 | ||
326 | private final CountDownLatch countDownLatch; | 330 | private final CountDownLatch countDownLatch; |
327 | private Long pendingXid; | 331 | private Long pendingXid; |
328 | private BatchState state; | 332 | private BatchState state; |
329 | 333 | ||
334 | + private final ExecutionList executionList = new ExecutionList(); | ||
335 | + | ||
330 | public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) { | 336 | public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) { |
331 | this.state = BatchState.STARTED; | 337 | this.state = BatchState.STARTED; |
332 | this.sws = sws; | 338 | this.sws = sws; |
... | @@ -335,6 +341,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -335,6 +341,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
335 | } | 341 | } |
336 | 342 | ||
337 | public void fail(OFErrorMsg msg, Dpid dpid) { | 343 | public void fail(OFErrorMsg msg, Dpid dpid) { |
344 | + | ||
338 | ok.set(false); | 345 | ok.set(false); |
339 | removeRequirement(dpid); | 346 | removeRequirement(dpid); |
340 | FlowEntry fe = null; | 347 | FlowEntry fe = null; |
... | @@ -407,6 +414,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -407,6 +414,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
407 | 414 | ||
408 | @Override | 415 | @Override |
409 | public boolean cancel(boolean mayInterruptIfRunning) { | 416 | public boolean cancel(boolean mayInterruptIfRunning) { |
417 | + if (isDone()) { | ||
418 | + return false; | ||
419 | + } | ||
410 | ok.set(false); | 420 | ok.set(false); |
411 | this.state = BatchState.CANCELLED; | 421 | this.state = BatchState.CANCELLED; |
412 | cleanUp(); | 422 | cleanUp(); |
... | @@ -419,7 +429,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -419,7 +429,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
419 | } | 429 | } |
420 | 430 | ||
421 | } | 431 | } |
422 | - return isCancelled(); | 432 | + invokeCallbacks(); |
433 | + return true; | ||
423 | } | 434 | } |
424 | 435 | ||
425 | @Override | 436 | @Override |
... | @@ -429,14 +440,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -429,14 +440,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
429 | 440 | ||
430 | @Override | 441 | @Override |
431 | public boolean isDone() { | 442 | public boolean isDone() { |
432 | - return this.state == BatchState.FINISHED; | 443 | + return this.state == BatchState.FINISHED || isCancelled(); |
433 | } | 444 | } |
434 | 445 | ||
435 | @Override | 446 | @Override |
436 | public CompletedBatchOperation get() throws InterruptedException, ExecutionException { | 447 | public CompletedBatchOperation get() throws InterruptedException, ExecutionException { |
437 | countDownLatch.await(); | 448 | countDownLatch.await(); |
438 | this.state = BatchState.FINISHED; | 449 | this.state = BatchState.FINISHED; |
439 | - return new CompletedBatchOperation(ok.get(), offendingFlowMods); | 450 | + CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods); |
451 | + return result; | ||
440 | } | 452 | } |
441 | 453 | ||
442 | @Override | 454 | @Override |
... | @@ -445,7 +457,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -445,7 +457,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
445 | TimeoutException { | 457 | TimeoutException { |
446 | if (countDownLatch.await(timeout, unit)) { | 458 | if (countDownLatch.await(timeout, unit)) { |
447 | this.state = BatchState.FINISHED; | 459 | this.state = BatchState.FINISHED; |
448 | - return new CompletedBatchOperation(ok.get(), offendingFlowMods); | 460 | + CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods); |
461 | + return result; | ||
449 | } | 462 | } |
450 | throw new TimeoutException(); | 463 | throw new TimeoutException(); |
451 | } | 464 | } |
... | @@ -463,10 +476,21 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -463,10 +476,21 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
463 | 476 | ||
464 | private void removeRequirement(Dpid dpid) { | 477 | private void removeRequirement(Dpid dpid) { |
465 | countDownLatch.countDown(); | 478 | countDownLatch.countDown(); |
479 | + if (countDownLatch.getCount() == 0) { | ||
480 | + invokeCallbacks(); | ||
481 | + } | ||
466 | sws.remove(dpid); | 482 | sws.remove(dpid); |
467 | cleanUp(); | 483 | cleanUp(); |
468 | } | 484 | } |
469 | 485 | ||
486 | + @Override | ||
487 | + public void addListener(Runnable runnable, Executor executor) { | ||
488 | + executionList.add(runnable, executor); | ||
489 | + } | ||
490 | + | ||
491 | + private void invokeCallbacks() { | ||
492 | + executionList.execute(); | ||
493 | + } | ||
470 | } | 494 | } |
471 | 495 | ||
472 | } | 496 | } | ... | ... |
-
Please register or login to post a comment