tom

Merge remote-tracking branch 'origin/master'

1 +package org.onlab.onos.net.flow;
2 +
3 +import java.util.List;
4 +
5 +/**
6 + * Interface capturing the result of a batch operation.
7 + *
8 + */
9 +public interface BatchOperationResult<T> {
10 +
11 + /**
12 + * Returns whether the operation was successful.
13 + * @return true if successful, false otherwise
14 + */
15 + boolean isSuccess();
16 +
17 + /**
18 + * Obtains a list of items which failed.
19 + * @return a list of failures
20 + */
21 + List<T> failedItems();
22 +
23 +}
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) {
367 + return false;
368 + }
369 + if (!state.compareAndSet(BatchState.STARTED, BatchState.CANCELLED)) {
353 return false; 370 return false;
354 } 371 }
372 + cleanUpBatch();
373 + for (Future<CompletedBatchOperation> f : futures) {
374 + f.cancel(mayInterruptIfRunning);
375 + }
376 + return true;
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;
377 } 396 }
378 - return new CompletedBatchOperation(); 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);
404 + }
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);
429 + }
430 + return finalizeBatchOperation(success, failed);
431 + }
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 (this) {
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());
392 } 476 }
393 - return new CompletedBatchOperation();
394 } 477 }
395 478
396 } 479 }
480 + }
481 +
482 +
397 483
398 484
399 } 485 }
......
...@@ -19,8 +19,11 @@ import java.util.Map; ...@@ -19,8 +19,11 @@ import java.util.Map;
19 import java.util.Objects; 19 import java.util.Objects;
20 import java.util.concurrent.ConcurrentHashMap; 20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ConcurrentMap; 21 import java.util.concurrent.ConcurrentMap;
22 +import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.ExecutorService; 23 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Future; 24 import java.util.concurrent.Future;
25 +import java.util.concurrent.TimeUnit;
26 +import java.util.concurrent.TimeoutException;
24 27
25 import org.apache.felix.scr.annotations.Activate; 28 import org.apache.felix.scr.annotations.Activate;
26 import org.apache.felix.scr.annotations.Component; 29 import org.apache.felix.scr.annotations.Component;
...@@ -516,9 +519,14 @@ public class IntentManager ...@@ -516,9 +519,14 @@ public class IntentManager
516 public void run() { 519 public void run() {
517 for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) { 520 for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
518 Future<CompletedBatchOperation> future = i.next(); 521 Future<CompletedBatchOperation> future = i.next();
519 - if (future.isDone()) { 522 + try {
520 - // TODO: we may want to get the future here 523 + // TODO: we may want to get the future here and go back to the future.
524 + CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
525 + // TODO check if future succeeded and if not report fail items
521 i.remove(); 526 i.remove();
527 +
528 + } catch (TimeoutException | InterruptedException | ExecutionException te) {
529 + log.debug("Intallations of intent {} is still pending", intent);
522 } 530 }
523 } 531 }
524 if (futures.isEmpty()) { 532 if (futures.isEmpty()) {
......
...@@ -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)
......
...@@ -2,6 +2,7 @@ package org.onlab.onos.provider.of.flow.impl; ...@@ -2,6 +2,7 @@ package org.onlab.onos.provider.of.flow.impl;
2 2
3 import static org.slf4j.LoggerFactory.getLogger; 3 import static org.slf4j.LoggerFactory.getLogger;
4 4
5 +import java.util.HashMap;
5 import java.util.HashSet; 6 import java.util.HashSet;
6 import java.util.List; 7 import java.util.List;
7 import java.util.Map; 8 import java.util.Map;
...@@ -21,9 +22,12 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -21,9 +22,12 @@ import org.apache.felix.scr.annotations.Reference;
21 import org.apache.felix.scr.annotations.ReferenceCardinality; 22 import org.apache.felix.scr.annotations.ReferenceCardinality;
22 import org.onlab.onos.ApplicationId; 23 import org.onlab.onos.ApplicationId;
23 import org.onlab.onos.net.DeviceId; 24 import org.onlab.onos.net.DeviceId;
25 +import org.onlab.onos.net.flow.CompletedBatchOperation;
26 +import org.onlab.onos.net.flow.DefaultFlowEntry;
24 import org.onlab.onos.net.flow.FlowEntry; 27 import org.onlab.onos.net.flow.FlowEntry;
25 import org.onlab.onos.net.flow.FlowRule; 28 import org.onlab.onos.net.flow.FlowRule;
26 import org.onlab.onos.net.flow.FlowRuleBatchEntry; 29 import org.onlab.onos.net.flow.FlowRuleBatchEntry;
30 +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
27 import org.onlab.onos.net.flow.FlowRuleProvider; 31 import org.onlab.onos.net.flow.FlowRuleProvider;
28 import org.onlab.onos.net.flow.FlowRuleProviderRegistry; 32 import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
29 import org.onlab.onos.net.flow.FlowRuleProviderService; 33 import org.onlab.onos.net.flow.FlowRuleProviderService;
...@@ -40,6 +44,7 @@ import org.onlab.onos.openflow.controller.RoleState; ...@@ -40,6 +44,7 @@ import org.onlab.onos.openflow.controller.RoleState;
40 import org.projectfloodlight.openflow.protocol.OFActionType; 44 import org.projectfloodlight.openflow.protocol.OFActionType;
41 import org.projectfloodlight.openflow.protocol.OFBarrierRequest; 45 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
42 import org.projectfloodlight.openflow.protocol.OFErrorMsg; 46 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
47 +import org.projectfloodlight.openflow.protocol.OFFlowMod;
43 import org.projectfloodlight.openflow.protocol.OFFlowRemoved; 48 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
44 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; 49 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
45 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; 50 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
...@@ -52,6 +57,11 @@ import org.projectfloodlight.openflow.protocol.OFStatsType; ...@@ -52,6 +57,11 @@ import org.projectfloodlight.openflow.protocol.OFStatsType;
52 import org.projectfloodlight.openflow.protocol.OFVersion; 57 import org.projectfloodlight.openflow.protocol.OFVersion;
53 import org.projectfloodlight.openflow.protocol.action.OFAction; 58 import org.projectfloodlight.openflow.protocol.action.OFAction;
54 import org.projectfloodlight.openflow.protocol.action.OFActionOutput; 59 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
60 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
61 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
62 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
63 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
64 +import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
55 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; 65 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
56 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; 66 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
57 import org.projectfloodlight.openflow.types.OFPort; 67 import org.projectfloodlight.openflow.types.OFPort;
...@@ -70,6 +80,8 @@ import com.google.common.collect.Multimap; ...@@ -70,6 +80,8 @@ import com.google.common.collect.Multimap;
70 @Component(immediate = true) 80 @Component(immediate = true)
71 public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider { 81 public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
72 82
83 + enum BatchState { STARTED, FINISHED, CANCELLED };
84 +
73 private final Logger log = getLogger(getClass()); 85 private final Logger log = getLogger(getClass());
74 86
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -88,6 +100,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -88,6 +100,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
88 private final Map<Long, InstallationFuture> pendingFutures = 100 private final Map<Long, InstallationFuture> pendingFutures =
89 new ConcurrentHashMap<Long, InstallationFuture>(); 101 new ConcurrentHashMap<Long, InstallationFuture>();
90 102
103 + private final Map<Long, InstallationFuture> pendingFMs =
104 + new ConcurrentHashMap<Long, InstallationFuture>();
105 +
91 /** 106 /**
92 * Creates an OpenFlow host provider. 107 * Creates an OpenFlow host provider.
93 */ 108 */
...@@ -143,9 +158,47 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -143,9 +158,47 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
143 removeFlowRule(flowRules); 158 removeFlowRule(flowRules);
144 } 159 }
145 160
161 + @Override
162 + public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
163 + final Set<Dpid> sws = new HashSet<Dpid>();
164 + final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>();
165 + OFFlowMod mod = null;
166 + for (FlowRuleBatchEntry fbe : batch.getOperations()) {
167 + FlowRule flowRule = fbe.getTarget();
168 + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
169 + sws.add(new Dpid(sw.getId()));
170 + FlowModBuilder builder = new FlowModBuilder(flowRule, sw.factory());
171 + switch (fbe.getOperator()) {
172 + case ADD:
173 + mod = builder.buildFlowAdd();
174 + break;
175 + case REMOVE:
176 + mod = builder.buildFlowDel();
177 + break;
178 + case MODIFY:
179 + mod = builder.buildFlowMod();
180 + break;
181 + default:
182 + log.error("Unsupported batch operation {}", fbe.getOperator());
183 + }
184 + if (mod != null) {
185 + sw.sendMsg(mod);
186 + fmXids.put(mod.getXid(), fbe);
187 + } else {
188 + log.error("Conversion of flowrule {} failed.", flowRule);
189 + }
190 +
191 + }
192 + InstallationFuture installation = new InstallationFuture(sws, fmXids);
193 + for (Long xid : fmXids.keySet()) {
194 + pendingFMs.put(xid, installation);
195 + }
196 + pendingFutures.put(U32.f(batch.hashCode()), installation);
197 + installation.verify(batch.hashCode());
198 + return installation;
199 + }
200 +
146 201
147 - //TODO: InternalFlowRuleProvider listening to stats and error and flowremoved.
148 - // possibly barriers as well. May not be internal at all...
149 private class InternalFlowProvider 202 private class InternalFlowProvider
150 implements OpenFlowSwitchListener, OpenFlowEventListener { 203 implements OpenFlowSwitchListener, OpenFlowEventListener {
151 204
...@@ -175,7 +228,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -175,7 +228,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
175 InstallationFuture future = null; 228 InstallationFuture future = null;
176 switch (msg.getType()) { 229 switch (msg.getType()) {
177 case FLOW_REMOVED: 230 case FLOW_REMOVED:
178 - //TODO: make this better
179 OFFlowRemoved removed = (OFFlowRemoved) msg; 231 OFFlowRemoved removed = (OFFlowRemoved) msg;
180 232
181 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build(); 233 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
...@@ -191,7 +243,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -191,7 +243,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
191 } 243 }
192 break; 244 break;
193 case ERROR: 245 case ERROR:
194 - future = pendingFutures.get(msg.getXid()); 246 + future = pendingFMs.get(msg.getXid());
195 if (future != null) { 247 if (future != null) {
196 future.fail((OFErrorMsg) msg, dpid); 248 future.fail((OFErrorMsg) msg, dpid);
197 } 249 }
...@@ -203,10 +255,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -203,10 +255,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
203 } 255 }
204 256
205 @Override 257 @Override
206 - public void roleAssertFailed(Dpid dpid, RoleState role) { 258 + public void roleAssertFailed(Dpid dpid, RoleState role) {}
207 - // TODO Auto-generated method stub
208 -
209 - }
210 259
211 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) { 260 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
212 if (stats.getStatsType() != OFStatsType.FLOW) { 261 if (stats.getStatsType() != OFStatsType.FLOW) {
...@@ -230,7 +279,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -230,7 +279,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
230 } 279 }
231 280
232 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) { 281 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
233 - // TODO NEED TO FIND A BETTER WAY TO AVOID DOING THIS
234 if (reply.getVersion().equals(OFVersion.OF_10) || 282 if (reply.getVersion().equals(OFVersion.OF_10) ||
235 reply.getMatch().getMatchFields().iterator().hasNext()) { 283 reply.getMatch().getMatchFields().iterator().hasNext()) {
236 return false; 284 return false;
...@@ -251,104 +299,91 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -251,104 +299,91 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
251 } 299 }
252 return false; 300 return false;
253 } 301 }
254 -
255 - }
256 -
257 -
258 - @Override
259 - public Future<Void> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
260 - final Set<Dpid> sws = new HashSet<Dpid>();
261 -
262 - for (FlowRuleBatchEntry fbe : batch.getOperations()) {
263 - FlowRule flowRule = fbe.getTarget();
264 - OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
265 - sws.add(new Dpid(sw.getId()));
266 - switch (fbe.getOperator()) {
267 - case ADD:
268 - //TODO: Track XID for each flowmod
269 - sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowAdd());
270 - break;
271 - case REMOVE:
272 - //TODO: Track XID for each flowmod
273 - sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
274 - break;
275 - case MODIFY:
276 - //TODO: Track XID for each flowmod
277 - sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowMod());
278 - break;
279 - default:
280 - log.error("Unsupported batch operation {}", fbe.getOperator());
281 - }
282 - }
283 - InstallationFuture installation = new InstallationFuture(sws);
284 - pendingFutures.put(U32.f(batch.hashCode()), installation);
285 - installation.verify(batch.hashCode());
286 - return installation;
287 } 302 }
288 303
289 - private class InstallationFuture implements Future<Void> { 304 + private class InstallationFuture implements Future<CompletedBatchOperation> {
290 305
291 private final Set<Dpid> sws; 306 private final Set<Dpid> sws;
292 private final AtomicBoolean ok = new AtomicBoolean(true); 307 private final AtomicBoolean ok = new AtomicBoolean(true);
308 + private final Map<Long, FlowRuleBatchEntry> fms;
309 +
293 private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList(); 310 private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList();
294 311
295 private final CountDownLatch countDownLatch; 312 private final CountDownLatch countDownLatch;
313 + private Integer pendingXid;
314 + private BatchState state;
296 315
297 - public InstallationFuture(Set<Dpid> sws) { 316 + public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
317 + this.state = BatchState.STARTED;
298 this.sws = sws; 318 this.sws = sws;
319 + this.fms = fmXids;
299 countDownLatch = new CountDownLatch(sws.size()); 320 countDownLatch = new CountDownLatch(sws.size());
300 } 321 }
301 322
302 public void fail(OFErrorMsg msg, Dpid dpid) { 323 public void fail(OFErrorMsg msg, Dpid dpid) {
303 ok.set(false); 324 ok.set(false);
304 - //TODO add reason to flowentry 325 + FlowEntry fe = null;
326 + FlowRuleBatchEntry fbe = fms.get(msg.getXid());
327 + FlowRule offending = fbe.getTarget();
305 //TODO handle specific error msgs 328 //TODO handle specific error msgs
306 - //offendingFlowMods.add(new FlowEntryBuilder(dpid, msg.));
307 switch (msg.getErrType()) { 329 switch (msg.getErrType()) {
308 case BAD_ACTION: 330 case BAD_ACTION:
331 + OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
332 + fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
333 + bad.getCode().ordinal());
309 break; 334 break;
310 case BAD_INSTRUCTION: 335 case BAD_INSTRUCTION:
336 + OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
337 + fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
338 + badins.getCode().ordinal());
311 break; 339 break;
312 case BAD_MATCH: 340 case BAD_MATCH:
341 + OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
342 + fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
343 + badMatch.getCode().ordinal());
313 break; 344 break;
314 case BAD_REQUEST: 345 case BAD_REQUEST:
315 - break; 346 + OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
316 - case EXPERIMENTER: 347 + fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
348 + badReq.getCode().ordinal());
317 break; 349 break;
318 case FLOW_MOD_FAILED: 350 case FLOW_MOD_FAILED:
351 + OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
352 + fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
353 + fmFail.getCode().ordinal());
319 break; 354 break;
355 + case EXPERIMENTER:
320 case GROUP_MOD_FAILED: 356 case GROUP_MOD_FAILED:
321 - break;
322 case HELLO_FAILED: 357 case HELLO_FAILED:
323 - break;
324 case METER_MOD_FAILED: 358 case METER_MOD_FAILED:
325 - break;
326 case PORT_MOD_FAILED: 359 case PORT_MOD_FAILED:
327 - break;
328 case QUEUE_OP_FAILED: 360 case QUEUE_OP_FAILED:
329 - break;
330 case ROLE_REQUEST_FAILED: 361 case ROLE_REQUEST_FAILED:
331 - break;
332 case SWITCH_CONFIG_FAILED: 362 case SWITCH_CONFIG_FAILED:
333 - break;
334 case TABLE_FEATURES_FAILED: 363 case TABLE_FEATURES_FAILED:
335 - break;
336 case TABLE_MOD_FAILED: 364 case TABLE_MOD_FAILED:
365 + fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
337 break; 366 break;
338 default: 367 default:
339 - break; 368 + log.error("Unknown error type {}", msg.getErrType());
340 369
341 } 370 }
371 + offendingFlowMods.add(fe);
342 372
343 } 373 }
344 374
375 +
345 public void satisfyRequirement(Dpid dpid) { 376 public void satisfyRequirement(Dpid dpid) {
346 log.warn("Satisfaction from switch {}", dpid); 377 log.warn("Satisfaction from switch {}", dpid);
347 sws.remove(dpid); 378 sws.remove(dpid);
348 countDownLatch.countDown(); 379 countDownLatch.countDown();
380 + cleanUp();
381 +
349 } 382 }
350 383
384 +
351 public void verify(Integer id) { 385 public void verify(Integer id) {
386 + pendingXid = id;
352 for (Dpid dpid : sws) { 387 for (Dpid dpid : sws) {
353 OpenFlowSwitch sw = controller.getSwitch(dpid); 388 OpenFlowSwitch sw = controller.getSwitch(dpid);
354 OFBarrierRequest.Builder builder = sw.factory() 389 OFBarrierRequest.Builder builder = sw.factory()
...@@ -356,41 +391,59 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -356,41 +391,59 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
356 .setXid(id); 391 .setXid(id);
357 sw.sendMsg(builder.build()); 392 sw.sendMsg(builder.build());
358 } 393 }
359 -
360 -
361 } 394 }
362 395
363 @Override 396 @Override
364 public boolean cancel(boolean mayInterruptIfRunning) { 397 public boolean cancel(boolean mayInterruptIfRunning) {
365 - // TODO Auto-generated method stub 398 + this.state = BatchState.CANCELLED;
366 - return false; 399 + cleanUp();
400 + for (FlowRuleBatchEntry fbe : fms.values()) {
401 + if (fbe.getOperator() == FlowRuleOperation.ADD ||
402 + fbe.getOperator() == FlowRuleOperation.MODIFY) {
403 + removeFlowRule(fbe.getTarget());
404 + } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
405 + applyRule(fbe.getTarget());
406 + }
407 +
408 + }
409 + return isCancelled();
367 } 410 }
368 411
369 @Override 412 @Override
370 public boolean isCancelled() { 413 public boolean isCancelled() {
371 - // TODO Auto-generated method stub 414 + return this.state == BatchState.CANCELLED;
372 - return false;
373 } 415 }
374 416
375 @Override 417 @Override
376 public boolean isDone() { 418 public boolean isDone() {
377 - return sws.isEmpty(); 419 + return this.state == BatchState.FINISHED;
378 } 420 }
379 421
380 @Override 422 @Override
381 - public Void get() throws InterruptedException, ExecutionException { 423 + public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
382 countDownLatch.await(); 424 countDownLatch.await();
383 - //return offendingFlowMods; 425 + this.state = BatchState.FINISHED;
384 - return null; 426 + return new CompletedBatchOperation(ok.get(), offendingFlowMods);
385 } 427 }
386 428
387 @Override 429 @Override
388 - public Void get(long timeout, TimeUnit unit) 430 + public CompletedBatchOperation get(long timeout, TimeUnit unit)
389 throws InterruptedException, ExecutionException, 431 throws InterruptedException, ExecutionException,
390 TimeoutException { 432 TimeoutException {
391 - countDownLatch.await(timeout, unit); 433 + if (countDownLatch.await(timeout, unit)) {
392 - //return offendingFlowMods; 434 + this.state = BatchState.FINISHED;
393 - return null; 435 + return new CompletedBatchOperation(ok.get(), offendingFlowMods);
436 + }
437 + throw new TimeoutException();
438 + }
439 +
440 + private void cleanUp() {
441 + if (sws.isEmpty()) {
442 + pendingFutures.remove(pendingXid);
443 + for (Long xid : fms.keySet()) {
444 + pendingFMs.remove(xid);
445 + }
446 + }
394 } 447 }
395 448
396 } 449 }
......