alshabib

clean batch operations

Change-Id: I7187de40bb5276d6ae9e9831e5d47d36e16560ad
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 -public class CompletedBatchOperation { 3 +import java.util.List;
4 +
5 +import com.google.common.collect.ImmutableList;
6 +
7 +public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> {
8 +
9 +
10 + private final boolean success;
11 + private final List<FlowEntry> failures;
12 +
13 + public CompletedBatchOperation(boolean success, List<FlowEntry> failures) {
14 + this.success = success;
15 + this.failures = ImmutableList.copyOf(failures);
16 + }
17 +
18 + @Override
19 + public boolean isSuccess() {
20 + return success;
21 + }
22 +
23 + @Override
24 + public List<FlowEntry> failedItems() {
25 + return failures;
26 + }
4 27
5 28
6 } 29 }
......
...@@ -17,6 +17,10 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -17,6 +17,10 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
17 17
18 private long lastSeen = -1; 18 private long lastSeen = -1;
19 19
20 + private final int errType;
21 +
22 + private final int errCode;
23 +
20 24
21 public DefaultFlowEntry(DeviceId deviceId, TrafficSelector selector, 25 public DefaultFlowEntry(DeviceId deviceId, TrafficSelector selector,
22 TrafficTreatment treatment, int priority, FlowEntryState state, 26 TrafficTreatment treatment, int priority, FlowEntryState state,
...@@ -27,6 +31,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -27,6 +31,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
27 this.life = life; 31 this.life = life;
28 this.packets = packets; 32 this.packets = packets;
29 this.bytes = bytes; 33 this.bytes = bytes;
34 + this.errCode = -1;
35 + this.errType = -1;
30 this.lastSeen = System.currentTimeMillis(); 36 this.lastSeen = System.currentTimeMillis();
31 } 37 }
32 38
...@@ -37,6 +43,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -37,6 +43,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
37 this.life = life; 43 this.life = life;
38 this.packets = packets; 44 this.packets = packets;
39 this.bytes = bytes; 45 this.bytes = bytes;
46 + this.errCode = -1;
47 + this.errType = -1;
40 this.lastSeen = System.currentTimeMillis(); 48 this.lastSeen = System.currentTimeMillis();
41 } 49 }
42 50
...@@ -46,9 +54,18 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -46,9 +54,18 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
46 this.life = 0; 54 this.life = 0;
47 this.packets = 0; 55 this.packets = 0;
48 this.bytes = 0; 56 this.bytes = 0;
57 + this.errCode = -1;
58 + this.errType = -1;
49 this.lastSeen = System.currentTimeMillis(); 59 this.lastSeen = System.currentTimeMillis();
50 } 60 }
51 61
62 + public DefaultFlowEntry(FlowRule rule, int errType, int errCode) {
63 + super(rule);
64 + this.state = FlowEntryState.FAILED;
65 + this.errType = errType;
66 + this.errCode = errCode;
67 + }
68 +
52 @Override 69 @Override
53 public long life() { 70 public long life() {
54 return life; 71 return life;
...@@ -100,6 +117,16 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -100,6 +117,16 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
100 } 117 }
101 118
102 @Override 119 @Override
120 + public int errType() {
121 + return this.errType;
122 + }
123 +
124 + @Override
125 + public int errCode() {
126 + return this.errCode;
127 + }
128 +
129 + @Override
103 public String toString() { 130 public String toString() {
104 return toStringHelper(this) 131 return toStringHelper(this)
105 .add("rule", super.toString()) 132 .add("rule", super.toString())
...@@ -108,4 +135,6 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -108,4 +135,6 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
108 } 135 }
109 136
110 137
138 +
139 +
111 } 140 }
......
...@@ -29,7 +29,12 @@ public interface FlowEntry extends FlowRule { ...@@ -29,7 +29,12 @@ public interface FlowEntry extends FlowRule {
29 /** 29 /**
30 * Flow has been removed from flow table and can be purged. 30 * Flow has been removed from flow table and can be purged.
31 */ 31 */
32 - REMOVED 32 + REMOVED,
33 +
34 + /**
35 + * Indicates that the installation of this flow has failed.
36 + */
37 + FAILED
33 } 38 }
34 39
35 /** 40 /**
...@@ -95,4 +100,16 @@ public interface FlowEntry extends FlowRule { ...@@ -95,4 +100,16 @@ public interface FlowEntry extends FlowRule {
95 */ 100 */
96 void setBytes(long bytes); 101 void setBytes(long bytes);
97 102
103 + /**
104 + * Indicates the error type.
105 + * @return an integer value of the error
106 + */
107 + int errType();
108 +
109 + /**
110 + * Indicates the error code.
111 + * @return an integer value of the error
112 + */
113 + int errCode();
114 +
98 } 115 }
......
...@@ -37,6 +37,12 @@ public interface FlowRuleProvider extends Provider { ...@@ -37,6 +37,12 @@ public interface FlowRuleProvider extends Provider {
37 */ 37 */
38 void removeRulesById(ApplicationId id, FlowRule... flowRules); 38 void removeRulesById(ApplicationId id, FlowRule... flowRules);
39 39
40 - Future<Void> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); 40 + /**
41 + * Installs a batch of flow rules. Each flowrule is associated to an
42 + * operation which results in either addition, removal or modification.
43 + * @param batch a batch of flow rules
44 + * @return a future indicating the status of this execution
45 + */
46 + Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch);
41 47
42 } 48 }
......
...@@ -5,10 +5,12 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -5,10 +5,12 @@ import static org.slf4j.LoggerFactory.getLogger;
5 5
6 import java.util.Iterator; 6 import java.util.Iterator;
7 import java.util.List; 7 import java.util.List;
8 +import java.util.concurrent.CancellationException;
8 import java.util.concurrent.ExecutionException; 9 import java.util.concurrent.ExecutionException;
9 import java.util.concurrent.Future; 10 import java.util.concurrent.Future;
10 import java.util.concurrent.TimeUnit; 11 import java.util.concurrent.TimeUnit;
11 import java.util.concurrent.TimeoutException; 12 import java.util.concurrent.TimeoutException;
13 +import java.util.concurrent.atomic.AtomicReference;
12 14
13 import org.apache.felix.scr.annotations.Activate; 15 import org.apache.felix.scr.annotations.Activate;
14 import org.apache.felix.scr.annotations.Component; 16 import org.apache.felix.scr.annotations.Component;
...@@ -26,6 +28,7 @@ import org.onlab.onos.net.flow.CompletedBatchOperation; ...@@ -26,6 +28,7 @@ import org.onlab.onos.net.flow.CompletedBatchOperation;
26 import org.onlab.onos.net.flow.FlowEntry; 28 import org.onlab.onos.net.flow.FlowEntry;
27 import org.onlab.onos.net.flow.FlowRule; 29 import org.onlab.onos.net.flow.FlowRule;
28 import org.onlab.onos.net.flow.FlowRuleBatchEntry; 30 import org.onlab.onos.net.flow.FlowRuleBatchEntry;
31 +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
29 import org.onlab.onos.net.flow.FlowRuleBatchOperation; 32 import org.onlab.onos.net.flow.FlowRuleBatchOperation;
30 import org.onlab.onos.net.flow.FlowRuleEvent; 33 import org.onlab.onos.net.flow.FlowRuleEvent;
31 import org.onlab.onos.net.flow.FlowRuleListener; 34 import org.onlab.onos.net.flow.FlowRuleListener;
...@@ -52,6 +55,8 @@ public class FlowRuleManager ...@@ -52,6 +55,8 @@ public class FlowRuleManager
52 extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService> 55 extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
53 implements FlowRuleService, FlowRuleProviderRegistry { 56 implements FlowRuleService, FlowRuleProviderRegistry {
54 57
58 + enum BatchState { STARTED, FINISHED, CANCELLED };
59 +
55 public static final String FLOW_RULE_NULL = "FlowRule cannot be null"; 60 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
56 private final Logger log = getLogger(getClass()); 61 private final Logger log = getLogger(getClass());
57 62
...@@ -144,7 +149,7 @@ public class FlowRuleManager ...@@ -144,7 +149,7 @@ public class FlowRuleManager
144 FlowRuleBatchOperation batch) { 149 FlowRuleBatchOperation batch) {
145 Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches = 150 Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches =
146 ArrayListMultimap.create(); 151 ArrayListMultimap.create();
147 - List<Future<Void>> futures = Lists.newArrayList(); 152 + List<Future<CompletedBatchOperation>> futures = Lists.newArrayList();
148 for (FlowRuleBatchEntry fbe : batch.getOperations()) { 153 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
149 final FlowRule f = fbe.getTarget(); 154 final FlowRule f = fbe.getTarget();
150 final Device device = deviceService.getDevice(f.deviceId()); 155 final Device device = deviceService.getDevice(f.deviceId());
...@@ -165,10 +170,10 @@ public class FlowRuleManager ...@@ -165,10 +170,10 @@ public class FlowRuleManager
165 for (FlowRuleProvider provider : batches.keySet()) { 170 for (FlowRuleProvider provider : batches.keySet()) {
166 FlowRuleBatchOperation b = 171 FlowRuleBatchOperation b =
167 new FlowRuleBatchOperation(batches.get(provider)); 172 new FlowRuleBatchOperation(batches.get(provider));
168 - Future<Void> future = provider.executeBatch(b); 173 + Future<CompletedBatchOperation> future = provider.executeBatch(b);
169 futures.add(future); 174 futures.add(future);
170 } 175 }
171 - return new FlowRuleBatchFuture(futures); 176 + return new FlowRuleBatchFuture(futures, batches);
172 } 177 }
173 178
174 @Override 179 @Override
...@@ -341,59 +346,140 @@ public class FlowRuleManager ...@@ -341,59 +346,140 @@ public class FlowRuleManager
341 private class FlowRuleBatchFuture 346 private class FlowRuleBatchFuture
342 implements Future<CompletedBatchOperation> { 347 implements Future<CompletedBatchOperation> {
343 348
344 - private final List<Future<Void>> futures; 349 + private final List<Future<CompletedBatchOperation>> futures;
350 + private final Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches;
351 + private final AtomicReference<BatchState> state;
352 + private CompletedBatchOperation overall;
353 +
354 +
345 355
346 - public FlowRuleBatchFuture(List<Future<Void>> futures) { 356 + public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures,
357 + Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches) {
347 this.futures = futures; 358 this.futures = futures;
359 + this.batches = batches;
360 + state = new AtomicReference<FlowRuleManager.BatchState>();
361 + state.set(BatchState.STARTED);
348 } 362 }
349 363
350 @Override 364 @Override
351 public boolean cancel(boolean mayInterruptIfRunning) { 365 public boolean cancel(boolean mayInterruptIfRunning) {
352 - // TODO Auto-generated method stub 366 + if (state.get() == BatchState.FINISHED) {
353 - return false; 367 + return false;
368 + }
369 + if (!state.compareAndSet(BatchState.STARTED, BatchState.CANCELLED)) {
370 + return false;
371 + }
372 + cleanUpBatch();
373 + for (Future<CompletedBatchOperation> f : futures) {
374 + f.cancel(mayInterruptIfRunning);
375 + }
376 + return true;
354 } 377 }
355 378
356 @Override 379 @Override
357 public boolean isCancelled() { 380 public boolean isCancelled() {
358 - // TODO Auto-generated method stub 381 + return state.get() == BatchState.CANCELLED;
359 - return false;
360 } 382 }
361 383
362 @Override 384 @Override
363 public boolean isDone() { 385 public boolean isDone() {
364 - boolean isDone = true; 386 + return state.get() == BatchState.FINISHED;
365 - for (Future<Void> future : futures) {
366 - isDone &= future.isDone();
367 - }
368 - return isDone;
369 } 387 }
370 388
389 +
371 @Override 390 @Override
372 public CompletedBatchOperation get() throws InterruptedException, 391 public CompletedBatchOperation get() throws InterruptedException,
373 - ExecutionException { 392 + ExecutionException {
374 - // TODO Auto-generated method stub 393 +
375 - for (Future<Void> future : futures) { 394 + if (isDone()) {
376 - future.get(); 395 + return overall;
396 + }
397 +
398 + boolean success = true;
399 + List<FlowEntry> failed = Lists.newLinkedList();
400 + CompletedBatchOperation completed;
401 + for (Future<CompletedBatchOperation> future : futures) {
402 + completed = future.get();
403 + success = validateBatchOperation(failed, completed, future);
377 } 404 }
378 - return new CompletedBatchOperation(); 405 +
406 + return finalizeBatchOperation(success, failed);
407 +
379 } 408 }
380 409
381 @Override 410 @Override
382 public CompletedBatchOperation get(long timeout, TimeUnit unit) 411 public CompletedBatchOperation get(long timeout, TimeUnit unit)
383 throws InterruptedException, ExecutionException, 412 throws InterruptedException, ExecutionException,
384 TimeoutException { 413 TimeoutException {
385 - // TODO we should decrement the timeout 414 +
415 + if (isDone()) {
416 + return overall;
417 + }
418 + boolean success = true;
419 + List<FlowEntry> failed = Lists.newLinkedList();
420 + CompletedBatchOperation completed;
386 long start = System.nanoTime(); 421 long start = System.nanoTime();
387 long end = start + unit.toNanos(timeout); 422 long end = start + unit.toNanos(timeout);
388 - for (Future<Void> future : futures) { 423 +
424 + for (Future<CompletedBatchOperation> future : futures) {
389 long now = System.nanoTime(); 425 long now = System.nanoTime();
390 long thisTimeout = end - now; 426 long thisTimeout = end - now;
391 - future.get(thisTimeout, TimeUnit.NANOSECONDS); 427 + completed = future.get(thisTimeout, TimeUnit.NANOSECONDS);
428 + success = validateBatchOperation(failed, completed, future);
392 } 429 }
393 - return new CompletedBatchOperation(); 430 + return finalizeBatchOperation(success, failed);
394 } 431 }
395 432
433 + private boolean validateBatchOperation(List<FlowEntry> failed,
434 + CompletedBatchOperation completed,
435 + Future<CompletedBatchOperation> future) {
436 +
437 + if (isCancelled()) {
438 + throw new CancellationException();
439 + }
440 + if (!completed.isSuccess()) {
441 + failed.addAll(completed.failedItems());
442 + cleanUpBatch();
443 + cancelAllSubBatches();
444 + return false;
445 + }
446 + return true;
447 + }
448 +
449 + private void cancelAllSubBatches() {
450 + for (Future<CompletedBatchOperation> f : futures) {
451 + f.cancel(true);
452 + }
453 + }
454 +
455 + private CompletedBatchOperation finalizeBatchOperation(boolean success,
456 + List<FlowEntry> failed) {
457 + synchronized (overall) {
458 + if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) {
459 + if (state.get() == BatchState.FINISHED) {
460 + return overall;
461 + }
462 + throw new CancellationException();
463 + }
464 + overall = new CompletedBatchOperation(success, failed);
465 + return overall;
466 + }
467 + }
468 +
469 + private void cleanUpBatch() {
470 + for (FlowRuleBatchEntry fbe : batches.values()) {
471 + if (fbe.getOperator() == FlowRuleOperation.ADD ||
472 + fbe.getOperator() == FlowRuleOperation.MODIFY) {
473 + store.deleteFlowRule(fbe.getTarget());
474 + } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
475 + store.storeFlowRule(fbe.getTarget());
476 + }
477 + }
478 +
479 + }
396 } 480 }
397 481
398 482
483 +
484 +
399 } 485 }
......
...@@ -28,6 +28,7 @@ import org.onlab.onos.net.Port; ...@@ -28,6 +28,7 @@ import org.onlab.onos.net.Port;
28 import org.onlab.onos.net.PortNumber; 28 import org.onlab.onos.net.PortNumber;
29 import org.onlab.onos.net.device.DeviceListener; 29 import org.onlab.onos.net.device.DeviceListener;
30 import org.onlab.onos.net.device.DeviceService; 30 import org.onlab.onos.net.device.DeviceService;
31 +import org.onlab.onos.net.flow.CompletedBatchOperation;
31 import org.onlab.onos.net.flow.DefaultFlowEntry; 32 import org.onlab.onos.net.flow.DefaultFlowEntry;
32 import org.onlab.onos.net.flow.DefaultFlowRule; 33 import org.onlab.onos.net.flow.DefaultFlowRule;
33 import org.onlab.onos.net.flow.FlowEntry; 34 import org.onlab.onos.net.flow.FlowEntry;
...@@ -408,7 +409,7 @@ public class FlowRuleManagerTest { ...@@ -408,7 +409,7 @@ public class FlowRuleManagerTest {
408 } 409 }
409 410
410 @Override 411 @Override
411 - public Future<Void> executeBatch( 412 + public Future<CompletedBatchOperation> executeBatch(
412 BatchOperation<FlowRuleBatchEntry> batch) { 413 BatchOperation<FlowRuleBatchEntry> batch) {
413 // TODO Auto-generated method stub 414 // TODO Auto-generated method stub
414 return null; 415 return null;
......
...@@ -27,6 +27,8 @@ import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcp ...@@ -27,6 +27,8 @@ import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcp
27 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction; 27 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
28 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; 28 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
29 import org.projectfloodlight.openflow.protocol.OFFactory; 29 import org.projectfloodlight.openflow.protocol.OFFactory;
30 +import org.projectfloodlight.openflow.protocol.OFFlowAdd;
31 +import org.projectfloodlight.openflow.protocol.OFFlowDelete;
30 import org.projectfloodlight.openflow.protocol.OFFlowMod; 32 import org.projectfloodlight.openflow.protocol.OFFlowMod;
31 import org.projectfloodlight.openflow.protocol.OFFlowModFlags; 33 import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
32 import org.projectfloodlight.openflow.protocol.action.OFAction; 34 import org.projectfloodlight.openflow.protocol.action.OFAction;
...@@ -68,12 +70,13 @@ public class FlowModBuilder { ...@@ -68,12 +70,13 @@ public class FlowModBuilder {
68 this.cookie = flowRule.id(); 70 this.cookie = flowRule.id();
69 } 71 }
70 72
71 - public OFFlowMod buildFlowAdd() { 73 + public OFFlowAdd buildFlowAdd() {
72 Match match = buildMatch(); 74 Match match = buildMatch();
73 List<OFAction> actions = buildActions(); 75 List<OFAction> actions = buildActions();
74 76
75 //TODO: what to do without bufferid? do we assume that there will be a pktout as well? 77 //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
76 - OFFlowMod fm = factory.buildFlowAdd() 78 + OFFlowAdd fm = factory.buildFlowAdd()
79 + .setXid(cookie.value())
77 .setCookie(U64.of(cookie.value())) 80 .setCookie(U64.of(cookie.value()))
78 .setBufferId(OFBufferId.NO_BUFFER) 81 .setBufferId(OFBufferId.NO_BUFFER)
79 .setActions(actions) 82 .setActions(actions)
...@@ -92,6 +95,7 @@ public class FlowModBuilder { ...@@ -92,6 +95,7 @@ public class FlowModBuilder {
92 95
93 //TODO: what to do without bufferid? do we assume that there will be a pktout as well? 96 //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
94 OFFlowMod fm = factory.buildFlowModify() 97 OFFlowMod fm = factory.buildFlowModify()
98 + .setXid(cookie.value())
95 .setCookie(U64.of(cookie.value())) 99 .setCookie(U64.of(cookie.value()))
96 .setBufferId(OFBufferId.NO_BUFFER) 100 .setBufferId(OFBufferId.NO_BUFFER)
97 .setActions(actions) 101 .setActions(actions)
...@@ -104,11 +108,12 @@ public class FlowModBuilder { ...@@ -104,11 +108,12 @@ public class FlowModBuilder {
104 108
105 } 109 }
106 110
107 - public OFFlowMod buildFlowDel() { 111 + public OFFlowDelete buildFlowDel() {
108 Match match = buildMatch(); 112 Match match = buildMatch();
109 List<OFAction> actions = buildActions(); 113 List<OFAction> actions = buildActions();
110 114
111 - OFFlowMod fm = factory.buildFlowDelete() 115 + OFFlowDelete fm = factory.buildFlowDelete()
116 + .setXid(cookie.value())
112 .setCookie(U64.of(cookie.value())) 117 .setCookie(U64.of(cookie.value()))
113 .setBufferId(OFBufferId.NO_BUFFER) 118 .setBufferId(OFBufferId.NO_BUFFER)
114 .setActions(actions) 119 .setActions(actions)
......