initial working impl of batch operations
Change-Id: Ie970543dec1104a394c7bcfa6eec24c0538278d6
Showing
13 changed files
with
389 additions
and
21 deletions
| ... | @@ -2,12 +2,13 @@ package org.onlab.onos.net.flow; | ... | @@ -2,12 +2,13 @@ package org.onlab.onos.net.flow; |
| 2 | 2 | ||
| 3 | import org.onlab.onos.ApplicationId; | 3 | import org.onlab.onos.ApplicationId; |
| 4 | import org.onlab.onos.net.DeviceId; | 4 | import org.onlab.onos.net.DeviceId; |
| 5 | +import org.onlab.onos.net.intent.BatchOperationTarget; | ||
| 5 | 6 | ||
| 6 | /** | 7 | /** |
| 7 | * Represents a generalized match & action pair to be applied to | 8 | * Represents a generalized match & action pair to be applied to |
| 8 | * an infrastucture device. | 9 | * an infrastucture device. |
| 9 | */ | 10 | */ |
| 10 | -public interface FlowRule { | 11 | +public interface FlowRule extends BatchOperationTarget { |
| 11 | 12 | ||
| 12 | static final int MAX_TIMEOUT = 60; | 13 | static final int MAX_TIMEOUT = 60; |
| 13 | static final int MIN_PRIORITY = 0; | 14 | static final int MIN_PRIORITY = 0; | ... | ... |
| 1 | +package org.onlab.onos.net.flow; | ||
| 2 | + | ||
| 3 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
| 4 | +import org.onlab.onos.net.intent.BatchOperationEntry; | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +public class FlowRuleBatchEntry | ||
| 8 | + extends BatchOperationEntry<FlowRuleOperation, FlowRule> { | ||
| 9 | + | ||
| 10 | + public FlowRuleBatchEntry(FlowRuleOperation operator, FlowRule target) { | ||
| 11 | + super(operator, target); | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + public enum FlowRuleOperation { | ||
| 15 | + ADD, | ||
| 16 | + REMOVE, | ||
| 17 | + MODIFY | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | +} |
| 1 | +package org.onlab.onos.net.flow; | ||
| 2 | + | ||
| 3 | +import java.util.Collection; | ||
| 4 | + | ||
| 5 | +import org.onlab.onos.net.intent.BatchOperation; | ||
| 6 | + | ||
| 7 | +public class FlowRuleBatchOperation | ||
| 8 | + extends BatchOperation<FlowRuleBatchEntry> { | ||
| 9 | + | ||
| 10 | + public FlowRuleBatchOperation(Collection<FlowRuleBatchEntry> operations) { | ||
| 11 | + super(operations); | ||
| 12 | + } | ||
| 13 | +} |
| 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; |
| 6 | +import org.onlab.onos.net.intent.BatchOperation; | ||
| 4 | import org.onlab.onos.net.provider.Provider; | 7 | import org.onlab.onos.net.provider.Provider; |
| 5 | 8 | ||
| 6 | /** | 9 | /** |
| ... | @@ -34,4 +37,6 @@ public interface FlowRuleProvider extends Provider { | ... | @@ -34,4 +37,6 @@ public interface FlowRuleProvider extends Provider { |
| 34 | */ | 37 | */ |
| 35 | void removeRulesById(ApplicationId id, FlowRule... flowRules); | 38 | void removeRulesById(ApplicationId id, FlowRule... flowRules); |
| 36 | 39 | ||
| 40 | + Future<Void> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); | ||
| 41 | + | ||
| 37 | } | 42 | } | ... | ... |
| 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 | 7 | ||
| ... | @@ -66,7 +68,12 @@ public interface FlowRuleService { | ... | @@ -66,7 +68,12 @@ public interface FlowRuleService { |
| 66 | */ | 68 | */ |
| 67 | Iterable<FlowRule> getFlowRulesById(ApplicationId id); | 69 | Iterable<FlowRule> getFlowRulesById(ApplicationId id); |
| 68 | 70 | ||
| 69 | - //Future<CompletedBatchOperation> applyBatch(BatchOperation<FlowRuleBatchEntry>) | 71 | + /** |
| 72 | + * Applies a batch operation of FlowRules. | ||
| 73 | + * | ||
| 74 | + * @return future indicating the state of the batch operation | ||
| 75 | + */ | ||
| 76 | + Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch); | ||
| 70 | 77 | ||
| 71 | /** | 78 | /** |
| 72 | * Adds the specified flow rule listener. | 79 | * Adds the specified flow rule listener. | ... | ... |
| 1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
| 2 | //TODO is this the right package? | 2 | //TODO is this the right package? |
| 3 | 3 | ||
| 4 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 5 | + | ||
| 6 | +import java.util.Collection; | ||
| 4 | import java.util.Collections; | 7 | import java.util.Collections; |
| 5 | import java.util.LinkedList; | 8 | import java.util.LinkedList; |
| 6 | import java.util.List; | 9 | import java.util.List; |
| 7 | 10 | ||
| 8 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
| 9 | - | ||
| 10 | /** | 11 | /** |
| 11 | * A list of BatchOperationEntry. | 12 | * A list of BatchOperationEntry. |
| 12 | * | 13 | * |
| ... | @@ -15,7 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -15,7 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
| 15 | */ | 16 | */ |
| 16 | public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { | 17 | public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { |
| 17 | 18 | ||
| 18 | - private List<T> ops; | 19 | + private final List<T> ops; |
| 19 | 20 | ||
| 20 | /** | 21 | /** |
| 21 | * Creates new {@link BatchOperation} object. | 22 | * Creates new {@link BatchOperation} object. |
| ... | @@ -30,7 +31,7 @@ public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { | ... | @@ -30,7 +31,7 @@ public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { |
| 30 | * | 31 | * |
| 31 | * @param batchOperations the list of batch operation entries. | 32 | * @param batchOperations the list of batch operation entries. |
| 32 | */ | 33 | */ |
| 33 | - public BatchOperation(List<T> batchOperations) { | 34 | + public BatchOperation(Collection<T> batchOperations) { |
| 34 | ops = new LinkedList<>(checkNotNull(batchOperations)); | 35 | ops = new LinkedList<>(checkNotNull(batchOperations)); |
| 35 | } | 36 | } |
| 36 | 37 | ||
| ... | @@ -61,6 +62,10 @@ public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { | ... | @@ -61,6 +62,10 @@ public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { |
| 61 | 62 | ||
| 62 | /** | 63 | /** |
| 63 | * Adds an operation. | 64 | * Adds an operation. |
| 65 | + * FIXME: Brian promises that the Intent Framework | ||
| 66 | + * will not modify the batch operation after it has submitted it. | ||
| 67 | + * Ali would prefer immutablity, but trusts brian for better or | ||
| 68 | + * for worse. | ||
| 64 | * | 69 | * |
| 65 | * @param entry the operation to be added | 70 | * @param entry the operation to be added |
| 66 | * @return this object if succeeded, null otherwise | 71 | * @return this object if succeeded, null otherwise | ... | ... |
| ... | @@ -15,14 +15,7 @@ public class BatchOperationEntry<T extends Enum<?>, U extends BatchOperationTarg | ... | @@ -15,14 +15,7 @@ public class BatchOperationEntry<T extends Enum<?>, U extends BatchOperationTarg |
| 15 | private final T operator; | 15 | private final T operator; |
| 16 | private final U target; | 16 | private final U target; |
| 17 | 17 | ||
| 18 | - /** | 18 | + |
| 19 | - * Default constructor for serializer. | ||
| 20 | - */ | ||
| 21 | - @Deprecated | ||
| 22 | - protected BatchOperationEntry() { | ||
| 23 | - this.operator = null; | ||
| 24 | - this.target = null; | ||
| 25 | - } | ||
| 26 | 19 | ||
| 27 | /** | 20 | /** |
| 28 | * Constructs new instance for the entry of the BatchOperation. | 21 | * Constructs new instance for the entry of the BatchOperation. | ... | ... |
| ... | @@ -5,6 +5,10 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,6 +5,10 @@ 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.ExecutionException; | ||
| 9 | +import java.util.concurrent.Future; | ||
| 10 | +import java.util.concurrent.TimeUnit; | ||
| 11 | +import java.util.concurrent.TimeoutException; | ||
| 8 | 12 | ||
| 9 | import org.apache.felix.scr.annotations.Activate; | 13 | import org.apache.felix.scr.annotations.Activate; |
| 10 | import org.apache.felix.scr.annotations.Component; | 14 | import org.apache.felix.scr.annotations.Component; |
| ... | @@ -18,8 +22,11 @@ import org.onlab.onos.event.EventDeliveryService; | ... | @@ -18,8 +22,11 @@ import org.onlab.onos.event.EventDeliveryService; |
| 18 | import org.onlab.onos.net.Device; | 22 | import org.onlab.onos.net.Device; |
| 19 | import org.onlab.onos.net.DeviceId; | 23 | import org.onlab.onos.net.DeviceId; |
| 20 | import org.onlab.onos.net.device.DeviceService; | 24 | import org.onlab.onos.net.device.DeviceService; |
| 25 | +import org.onlab.onos.net.flow.CompletedBatchOperation; | ||
| 21 | import org.onlab.onos.net.flow.FlowEntry; | 26 | import org.onlab.onos.net.flow.FlowEntry; |
| 22 | import org.onlab.onos.net.flow.FlowRule; | 27 | import org.onlab.onos.net.flow.FlowRule; |
| 28 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
| 29 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
| 23 | import org.onlab.onos.net.flow.FlowRuleEvent; | 30 | import org.onlab.onos.net.flow.FlowRuleEvent; |
| 24 | import org.onlab.onos.net.flow.FlowRuleListener; | 31 | import org.onlab.onos.net.flow.FlowRuleListener; |
| 25 | import org.onlab.onos.net.flow.FlowRuleProvider; | 32 | import org.onlab.onos.net.flow.FlowRuleProvider; |
| ... | @@ -32,7 +39,9 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry; | ... | @@ -32,7 +39,9 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry; |
| 32 | import org.onlab.onos.net.provider.AbstractProviderService; | 39 | import org.onlab.onos.net.provider.AbstractProviderService; |
| 33 | import org.slf4j.Logger; | 40 | import org.slf4j.Logger; |
| 34 | 41 | ||
| 42 | +import com.google.common.collect.ArrayListMultimap; | ||
| 35 | import com.google.common.collect.Lists; | 43 | import com.google.common.collect.Lists; |
| 44 | +import com.google.common.collect.Multimap; | ||
| 36 | 45 | ||
| 37 | /** | 46 | /** |
| 38 | * Provides implementation of the flow NB & SB APIs. | 47 | * Provides implementation of the flow NB & SB APIs. |
| ... | @@ -131,6 +140,38 @@ public class FlowRuleManager | ... | @@ -131,6 +140,38 @@ public class FlowRuleManager |
| 131 | } | 140 | } |
| 132 | 141 | ||
| 133 | @Override | 142 | @Override |
| 143 | + public Future<CompletedBatchOperation> applyBatch( | ||
| 144 | + FlowRuleBatchOperation batch) { | ||
| 145 | + Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches = | ||
| 146 | + ArrayListMultimap.create(); | ||
| 147 | + List<Future<Void>> futures = Lists.newArrayList(); | ||
| 148 | + for (FlowRuleBatchEntry fbe : batch.getOperations()) { | ||
| 149 | + final FlowRule f = fbe.getTarget(); | ||
| 150 | + final Device device = deviceService.getDevice(f.deviceId()); | ||
| 151 | + final FlowRuleProvider frp = getProvider(device.providerId()); | ||
| 152 | + batches.put(frp, fbe); | ||
| 153 | + switch (fbe.getOperator()) { | ||
| 154 | + case ADD: | ||
| 155 | + store.storeFlowRule(f); | ||
| 156 | + break; | ||
| 157 | + case REMOVE: | ||
| 158 | + store.deleteFlowRule(f); | ||
| 159 | + break; | ||
| 160 | + case MODIFY: | ||
| 161 | + default: | ||
| 162 | + log.error("Batch operation type {} unsupported.", fbe.getOperator()); | ||
| 163 | + } | ||
| 164 | + } | ||
| 165 | + for (FlowRuleProvider provider : batches.keySet()) { | ||
| 166 | + FlowRuleBatchOperation b = | ||
| 167 | + new FlowRuleBatchOperation(batches.get(provider)); | ||
| 168 | + Future<Void> future = provider.executeBatch(b); | ||
| 169 | + futures.add(future); | ||
| 170 | + } | ||
| 171 | + return new FlowRuleBatchFuture(futures); | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + @Override | ||
| 134 | public void addListener(FlowRuleListener listener) { | 175 | public void addListener(FlowRuleListener listener) { |
| 135 | listenerRegistry.addListener(listener); | 176 | listenerRegistry.addListener(listener); |
| 136 | } | 177 | } |
| ... | @@ -296,4 +337,63 @@ public class FlowRuleManager | ... | @@ -296,4 +337,63 @@ public class FlowRuleManager |
| 296 | eventDispatcher.post(event); | 337 | eventDispatcher.post(event); |
| 297 | } | 338 | } |
| 298 | } | 339 | } |
| 340 | + | ||
| 341 | + private class FlowRuleBatchFuture | ||
| 342 | + implements Future<CompletedBatchOperation> { | ||
| 343 | + | ||
| 344 | + private final List<Future<Void>> futures; | ||
| 345 | + | ||
| 346 | + public FlowRuleBatchFuture(List<Future<Void>> futures) { | ||
| 347 | + this.futures = futures; | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + @Override | ||
| 351 | + public boolean cancel(boolean mayInterruptIfRunning) { | ||
| 352 | + // TODO Auto-generated method stub | ||
| 353 | + return false; | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + @Override | ||
| 357 | + public boolean isCancelled() { | ||
| 358 | + // TODO Auto-generated method stub | ||
| 359 | + return false; | ||
| 360 | + } | ||
| 361 | + | ||
| 362 | + @Override | ||
| 363 | + public boolean isDone() { | ||
| 364 | + boolean isDone = true; | ||
| 365 | + for (Future<Void> future : futures) { | ||
| 366 | + isDone &= future.isDone(); | ||
| 367 | + } | ||
| 368 | + return isDone; | ||
| 369 | + } | ||
| 370 | + | ||
| 371 | + @Override | ||
| 372 | + public CompletedBatchOperation get() throws InterruptedException, | ||
| 373 | + ExecutionException { | ||
| 374 | + // TODO Auto-generated method stub | ||
| 375 | + for (Future<Void> future : futures) { | ||
| 376 | + future.get(); | ||
| 377 | + } | ||
| 378 | + return new CompletedBatchOperation(); | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + @Override | ||
| 382 | + public CompletedBatchOperation get(long timeout, TimeUnit unit) | ||
| 383 | + throws InterruptedException, ExecutionException, | ||
| 384 | + TimeoutException { | ||
| 385 | + // TODO we should decrement the timeout | ||
| 386 | + long start = System.nanoTime(); | ||
| 387 | + long end = start + unit.toNanos(timeout); | ||
| 388 | + for (Future<Void> future : futures) { | ||
| 389 | + long now = System.nanoTime(); | ||
| 390 | + long thisTimeout = end - now; | ||
| 391 | + future.get(thisTimeout, TimeUnit.NANOSECONDS); | ||
| 392 | + } | ||
| 393 | + return new CompletedBatchOperation(); | ||
| 394 | + } | ||
| 395 | + | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + | ||
| 299 | } | 399 | } | ... | ... |
| ... | @@ -4,6 +4,8 @@ import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ... | @@ -4,6 +4,8 @@ import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; |
| 4 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
| 5 | 5 | ||
| 6 | import java.util.Iterator; | 6 | import java.util.Iterator; |
| 7 | +import java.util.List; | ||
| 8 | +import java.util.concurrent.ExecutionException; | ||
| 7 | 9 | ||
| 8 | import org.apache.felix.scr.annotations.Activate; | 10 | import org.apache.felix.scr.annotations.Activate; |
| 9 | import org.apache.felix.scr.annotations.Component; | 11 | import org.apache.felix.scr.annotations.Component; |
| ... | @@ -16,6 +18,9 @@ import org.onlab.onos.net.Link; | ... | @@ -16,6 +18,9 @@ import org.onlab.onos.net.Link; |
| 16 | import org.onlab.onos.net.flow.DefaultFlowRule; | 18 | import org.onlab.onos.net.flow.DefaultFlowRule; |
| 17 | import org.onlab.onos.net.flow.DefaultTrafficSelector; | 19 | import org.onlab.onos.net.flow.DefaultTrafficSelector; |
| 18 | import org.onlab.onos.net.flow.FlowRule; | 20 | import org.onlab.onos.net.flow.FlowRule; |
| 21 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
| 22 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
| 23 | +import org.onlab.onos.net.flow.FlowRuleBatchOperation; | ||
| 19 | import org.onlab.onos.net.flow.FlowRuleService; | 24 | import org.onlab.onos.net.flow.FlowRuleService; |
| 20 | import org.onlab.onos.net.flow.TrafficSelector; | 25 | import org.onlab.onos.net.flow.TrafficSelector; |
| 21 | import org.onlab.onos.net.flow.TrafficTreatment; | 26 | import org.onlab.onos.net.flow.TrafficTreatment; |
| ... | @@ -24,6 +29,8 @@ import org.onlab.onos.net.intent.IntentInstaller; | ... | @@ -24,6 +29,8 @@ import org.onlab.onos.net.intent.IntentInstaller; |
| 24 | import org.onlab.onos.net.intent.PathIntent; | 29 | import org.onlab.onos.net.intent.PathIntent; |
| 25 | import org.slf4j.Logger; | 30 | import org.slf4j.Logger; |
| 26 | 31 | ||
| 32 | +import com.google.common.collect.Lists; | ||
| 33 | + | ||
| 27 | /** | 34 | /** |
| 28 | * Installer for {@link PathIntent path connectivity intents}. | 35 | * Installer for {@link PathIntent path connectivity intents}. |
| 29 | */ | 36 | */ |
| ... | @@ -56,19 +63,27 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -56,19 +63,27 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
| 56 | DefaultTrafficSelector.builder(intent.selector()); | 63 | DefaultTrafficSelector.builder(intent.selector()); |
| 57 | Iterator<Link> links = intent.path().links().iterator(); | 64 | Iterator<Link> links = intent.path().links().iterator(); |
| 58 | ConnectPoint prev = links.next().dst(); | 65 | ConnectPoint prev = links.next().dst(); |
| 59 | - | 66 | + List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); |
| 60 | while (links.hasNext()) { | 67 | while (links.hasNext()) { |
| 61 | builder.matchInport(prev.port()); | 68 | builder.matchInport(prev.port()); |
| 62 | Link link = links.next(); | 69 | Link link = links.next(); |
| 63 | TrafficTreatment treatment = builder() | 70 | TrafficTreatment treatment = builder() |
| 64 | .setOutput(link.src().port()).build(); | 71 | .setOutput(link.src().port()).build(); |
| 72 | + | ||
| 65 | FlowRule rule = new DefaultFlowRule(link.src().deviceId(), | 73 | FlowRule rule = new DefaultFlowRule(link.src().deviceId(), |
| 66 | builder.build(), treatment, | 74 | builder.build(), treatment, |
| 67 | 123, appId, 600); | 75 | 123, appId, 600); |
| 68 | - flowRuleService.applyFlowRules(rule); | 76 | + rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)); |
| 77 | + //flowRuleService.applyFlowRules(rule); | ||
| 69 | prev = link.dst(); | 78 | prev = link.dst(); |
| 70 | } | 79 | } |
| 71 | - | 80 | + FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules); |
| 81 | + try { | ||
| 82 | + flowRuleService.applyBatch(batch).get(); | ||
| 83 | + } catch (InterruptedException | ExecutionException e) { | ||
| 84 | + // TODO Auto-generated catch block | ||
| 85 | + e.printStackTrace(); | ||
| 86 | + } | ||
| 72 | } | 87 | } |
| 73 | 88 | ||
| 74 | @Override | 89 | @Override |
| ... | @@ -77,6 +92,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -77,6 +92,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
| 77 | DefaultTrafficSelector.builder(intent.selector()); | 92 | DefaultTrafficSelector.builder(intent.selector()); |
| 78 | Iterator<Link> links = intent.path().links().iterator(); | 93 | Iterator<Link> links = intent.path().links().iterator(); |
| 79 | ConnectPoint prev = links.next().dst(); | 94 | ConnectPoint prev = links.next().dst(); |
| 95 | + List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); | ||
| 80 | 96 | ||
| 81 | while (links.hasNext()) { | 97 | while (links.hasNext()) { |
| 82 | builder.matchInport(prev.port()); | 98 | builder.matchInport(prev.port()); |
| ... | @@ -86,9 +102,16 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -86,9 +102,16 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
| 86 | FlowRule rule = new DefaultFlowRule(link.src().deviceId(), | 102 | FlowRule rule = new DefaultFlowRule(link.src().deviceId(), |
| 87 | builder.build(), treatment, | 103 | builder.build(), treatment, |
| 88 | 123, appId, 600); | 104 | 123, appId, 600); |
| 89 | - | 105 | + rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)); |
| 90 | - flowRuleService.removeFlowRules(rule); | 106 | + //flowRuleService.removeFlowRules(rule); |
| 91 | prev = link.dst(); | 107 | prev = link.dst(); |
| 92 | } | 108 | } |
| 109 | + FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules); | ||
| 110 | + try { | ||
| 111 | + flowRuleService.applyBatch(batch).get(); | ||
| 112 | + } catch (InterruptedException | ExecutionException e) { | ||
| 113 | + // TODO Auto-generated catch block | ||
| 114 | + e.printStackTrace(); | ||
| 115 | + } | ||
| 93 | } | 116 | } |
| 94 | } | 117 | } | ... | ... |
| ... | @@ -12,6 +12,7 @@ import java.util.ArrayList; | ... | @@ -12,6 +12,7 @@ import java.util.ArrayList; |
| 12 | import java.util.Collections; | 12 | import java.util.Collections; |
| 13 | import java.util.List; | 13 | import java.util.List; |
| 14 | import java.util.Set; | 14 | import java.util.Set; |
| 15 | +import java.util.concurrent.Future; | ||
| 15 | 16 | ||
| 16 | import org.junit.After; | 17 | import org.junit.After; |
| 17 | import org.junit.Before; | 18 | import org.junit.Before; |
| ... | @@ -32,6 +33,7 @@ import org.onlab.onos.net.flow.DefaultFlowRule; | ... | @@ -32,6 +33,7 @@ import org.onlab.onos.net.flow.DefaultFlowRule; |
| 32 | import org.onlab.onos.net.flow.FlowEntry; | 33 | import org.onlab.onos.net.flow.FlowEntry; |
| 33 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; | 34 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; |
| 34 | import org.onlab.onos.net.flow.FlowRule; | 35 | import org.onlab.onos.net.flow.FlowRule; |
| 36 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
| 35 | import org.onlab.onos.net.flow.FlowRuleEvent; | 37 | import org.onlab.onos.net.flow.FlowRuleEvent; |
| 36 | import org.onlab.onos.net.flow.FlowRuleListener; | 38 | import org.onlab.onos.net.flow.FlowRuleListener; |
| 37 | import org.onlab.onos.net.flow.FlowRuleProvider; | 39 | import org.onlab.onos.net.flow.FlowRuleProvider; |
| ... | @@ -42,6 +44,7 @@ import org.onlab.onos.net.flow.TrafficSelector; | ... | @@ -42,6 +44,7 @@ import org.onlab.onos.net.flow.TrafficSelector; |
| 42 | import org.onlab.onos.net.flow.TrafficTreatment; | 44 | import org.onlab.onos.net.flow.TrafficTreatment; |
| 43 | import org.onlab.onos.net.flow.criteria.Criterion; | 45 | import org.onlab.onos.net.flow.criteria.Criterion; |
| 44 | import org.onlab.onos.net.flow.instructions.Instruction; | 46 | import org.onlab.onos.net.flow.instructions.Instruction; |
| 47 | +import org.onlab.onos.net.intent.BatchOperation; | ||
| 45 | import org.onlab.onos.net.provider.AbstractProvider; | 48 | import org.onlab.onos.net.provider.AbstractProvider; |
| 46 | import org.onlab.onos.net.provider.ProviderId; | 49 | import org.onlab.onos.net.provider.ProviderId; |
| 47 | import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; | 50 | import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; |
| ... | @@ -404,6 +407,13 @@ public class FlowRuleManagerTest { | ... | @@ -404,6 +407,13 @@ public class FlowRuleManagerTest { |
| 404 | public void removeRulesById(ApplicationId id, FlowRule... flowRules) { | 407 | public void removeRulesById(ApplicationId id, FlowRule... flowRules) { |
| 405 | } | 408 | } |
| 406 | 409 | ||
| 410 | + @Override | ||
| 411 | + public Future<Void> executeBatch( | ||
| 412 | + BatchOperation<FlowRuleBatchEntry> batch) { | ||
| 413 | + // TODO Auto-generated method stub | ||
| 414 | + return null; | ||
| 415 | + } | ||
| 416 | + | ||
| 407 | 417 | ||
| 408 | } | 418 | } |
| 409 | 419 | ... | ... |
| ... | @@ -68,7 +68,7 @@ public class FlowModBuilder { | ... | @@ -68,7 +68,7 @@ public class FlowModBuilder { |
| 68 | this.cookie = flowRule.id(); | 68 | this.cookie = flowRule.id(); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | - public OFFlowMod buildFlowMod() { | 71 | + public OFFlowMod buildFlowAdd() { |
| 72 | Match match = buildMatch(); | 72 | Match match = buildMatch(); |
| 73 | List<OFAction> actions = buildActions(); | 73 | List<OFAction> actions = buildActions(); |
| 74 | 74 | ||
| ... | @@ -86,6 +86,24 @@ public class FlowModBuilder { | ... | @@ -86,6 +86,24 @@ public class FlowModBuilder { |
| 86 | 86 | ||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | + public OFFlowMod buildFlowMod() { | ||
| 90 | + Match match = buildMatch(); | ||
| 91 | + List<OFAction> actions = buildActions(); | ||
| 92 | + | ||
| 93 | + //TODO: what to do without bufferid? do we assume that there will be a pktout as well? | ||
| 94 | + OFFlowMod fm = factory.buildFlowModify() | ||
| 95 | + .setCookie(U64.of(cookie.value())) | ||
| 96 | + .setBufferId(OFBufferId.NO_BUFFER) | ||
| 97 | + .setActions(actions) | ||
| 98 | + .setMatch(match) | ||
| 99 | + .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) | ||
| 100 | + .setPriority(priority) | ||
| 101 | + .build(); | ||
| 102 | + | ||
| 103 | + return fm; | ||
| 104 | + | ||
| 105 | + } | ||
| 106 | + | ||
| 89 | public OFFlowMod buildFlowDel() { | 107 | public OFFlowMod buildFlowDel() { |
| 90 | Match match = buildMatch(); | 108 | Match match = buildMatch(); |
| 91 | List<OFAction> actions = buildActions(); | 109 | List<OFAction> actions = buildActions(); | ... | ... |
providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
| ... | @@ -2,8 +2,17 @@ package org.onlab.onos.provider.of.flow.impl; | ... | @@ -2,8 +2,17 @@ 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.HashSet; | ||
| 5 | import java.util.List; | 6 | import java.util.List; |
| 6 | import java.util.Map; | 7 | import java.util.Map; |
| 8 | +import java.util.Set; | ||
| 9 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 10 | +import java.util.concurrent.CountDownLatch; | ||
| 11 | +import java.util.concurrent.ExecutionException; | ||
| 12 | +import java.util.concurrent.Future; | ||
| 13 | +import java.util.concurrent.TimeUnit; | ||
| 14 | +import java.util.concurrent.TimeoutException; | ||
| 15 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
| 7 | 16 | ||
| 8 | import org.apache.felix.scr.annotations.Activate; | 17 | import org.apache.felix.scr.annotations.Activate; |
| 9 | import org.apache.felix.scr.annotations.Component; | 18 | import org.apache.felix.scr.annotations.Component; |
| ... | @@ -14,9 +23,11 @@ import org.onlab.onos.ApplicationId; | ... | @@ -14,9 +23,11 @@ import org.onlab.onos.ApplicationId; |
| 14 | import org.onlab.onos.net.DeviceId; | 23 | import org.onlab.onos.net.DeviceId; |
| 15 | import org.onlab.onos.net.flow.FlowEntry; | 24 | import org.onlab.onos.net.flow.FlowEntry; |
| 16 | import org.onlab.onos.net.flow.FlowRule; | 25 | import org.onlab.onos.net.flow.FlowRule; |
| 26 | +import org.onlab.onos.net.flow.FlowRuleBatchEntry; | ||
| 17 | import org.onlab.onos.net.flow.FlowRuleProvider; | 27 | import org.onlab.onos.net.flow.FlowRuleProvider; |
| 18 | import org.onlab.onos.net.flow.FlowRuleProviderRegistry; | 28 | import org.onlab.onos.net.flow.FlowRuleProviderRegistry; |
| 19 | import org.onlab.onos.net.flow.FlowRuleProviderService; | 29 | import org.onlab.onos.net.flow.FlowRuleProviderService; |
| 30 | +import org.onlab.onos.net.intent.BatchOperation; | ||
| 20 | import org.onlab.onos.net.provider.AbstractProvider; | 31 | import org.onlab.onos.net.provider.AbstractProvider; |
| 21 | import org.onlab.onos.net.provider.ProviderId; | 32 | import org.onlab.onos.net.provider.ProviderId; |
| 22 | import org.onlab.onos.net.topology.TopologyService; | 33 | import org.onlab.onos.net.topology.TopologyService; |
| ... | @@ -27,6 +38,8 @@ import org.onlab.onos.openflow.controller.OpenFlowSwitch; | ... | @@ -27,6 +38,8 @@ import org.onlab.onos.openflow.controller.OpenFlowSwitch; |
| 27 | import org.onlab.onos.openflow.controller.OpenFlowSwitchListener; | 38 | import org.onlab.onos.openflow.controller.OpenFlowSwitchListener; |
| 28 | import org.onlab.onos.openflow.controller.RoleState; | 39 | import org.onlab.onos.openflow.controller.RoleState; |
| 29 | import org.projectfloodlight.openflow.protocol.OFActionType; | 40 | import org.projectfloodlight.openflow.protocol.OFActionType; |
| 41 | +import org.projectfloodlight.openflow.protocol.OFBarrierRequest; | ||
| 42 | +import org.projectfloodlight.openflow.protocol.OFErrorMsg; | ||
| 30 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; | 43 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; |
| 31 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; | 44 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; |
| 32 | import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; | 45 | import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; |
| ... | @@ -42,9 +55,11 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput; | ... | @@ -42,9 +55,11 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput; |
| 42 | import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; | 55 | import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; |
| 43 | import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; | 56 | import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; |
| 44 | import org.projectfloodlight.openflow.types.OFPort; | 57 | import org.projectfloodlight.openflow.types.OFPort; |
| 58 | +import org.projectfloodlight.openflow.types.U32; | ||
| 45 | import org.slf4j.Logger; | 59 | import org.slf4j.Logger; |
| 46 | 60 | ||
| 47 | import com.google.common.collect.ArrayListMultimap; | 61 | import com.google.common.collect.ArrayListMultimap; |
| 62 | +import com.google.common.collect.Lists; | ||
| 48 | import com.google.common.collect.Maps; | 63 | import com.google.common.collect.Maps; |
| 49 | import com.google.common.collect.Multimap; | 64 | import com.google.common.collect.Multimap; |
| 50 | 65 | ||
| ... | @@ -70,6 +85,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -70,6 +85,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
| 70 | 85 | ||
| 71 | private final InternalFlowProvider listener = new InternalFlowProvider(); | 86 | private final InternalFlowProvider listener = new InternalFlowProvider(); |
| 72 | 87 | ||
| 88 | + private final Map<Long, InstallationFuture> pendingFutures = | ||
| 89 | + new ConcurrentHashMap<Long, InstallationFuture>(); | ||
| 90 | + | ||
| 73 | /** | 91 | /** |
| 74 | * Creates an OpenFlow host provider. | 92 | * Creates an OpenFlow host provider. |
| 75 | */ | 93 | */ |
| ... | @@ -101,7 +119,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -101,7 +119,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
| 101 | 119 | ||
| 102 | private void applyRule(FlowRule flowRule) { | 120 | private void applyRule(FlowRule flowRule) { |
| 103 | OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri())); | 121 | OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri())); |
| 104 | - sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowMod()); | 122 | + sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowAdd()); |
| 105 | } | 123 | } |
| 106 | 124 | ||
| 107 | 125 | ||
| ... | @@ -154,6 +172,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -154,6 +172,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
| 154 | 172 | ||
| 155 | @Override | 173 | @Override |
| 156 | public void handleMessage(Dpid dpid, OFMessage msg) { | 174 | public void handleMessage(Dpid dpid, OFMessage msg) { |
| 175 | + InstallationFuture future = null; | ||
| 157 | switch (msg.getType()) { | 176 | switch (msg.getType()) { |
| 158 | case FLOW_REMOVED: | 177 | case FLOW_REMOVED: |
| 159 | //TODO: make this better | 178 | //TODO: make this better |
| ... | @@ -166,7 +185,17 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -166,7 +185,17 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
| 166 | pushFlowMetrics(dpid, (OFStatsReply) msg); | 185 | pushFlowMetrics(dpid, (OFStatsReply) msg); |
| 167 | break; | 186 | break; |
| 168 | case BARRIER_REPLY: | 187 | case BARRIER_REPLY: |
| 188 | + future = pendingFutures.get(msg.getXid()); | ||
| 189 | + if (future != null) { | ||
| 190 | + future.satisfyRequirement(dpid); | ||
| 191 | + } | ||
| 192 | + break; | ||
| 169 | case ERROR: | 193 | case ERROR: |
| 194 | + future = pendingFutures.get(msg.getXid()); | ||
| 195 | + if (future != null) { | ||
| 196 | + future.fail((OFErrorMsg) msg, dpid); | ||
| 197 | + } | ||
| 198 | + break; | ||
| 170 | default: | 199 | default: |
| 171 | log.debug("Unhandled message type: {}", msg.getType()); | 200 | log.debug("Unhandled message type: {}", msg.getType()); |
| 172 | } | 201 | } |
| ... | @@ -226,6 +255,144 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -226,6 +255,144 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
| 226 | } | 255 | } |
| 227 | 256 | ||
| 228 | 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 | + } | ||
| 288 | + | ||
| 289 | + private class InstallationFuture implements Future<Void> { | ||
| 290 | + | ||
| 291 | + private final Set<Dpid> sws; | ||
| 292 | + private final AtomicBoolean ok = new AtomicBoolean(true); | ||
| 293 | + private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList(); | ||
| 294 | + | ||
| 295 | + private final CountDownLatch countDownLatch; | ||
| 296 | + | ||
| 297 | + public InstallationFuture(Set<Dpid> sws) { | ||
| 298 | + this.sws = sws; | ||
| 299 | + countDownLatch = new CountDownLatch(sws.size()); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + public void fail(OFErrorMsg msg, Dpid dpid) { | ||
| 303 | + ok.set(false); | ||
| 304 | + //TODO add reason to flowentry | ||
| 305 | + //TODO handle specific error msgs | ||
| 306 | + //offendingFlowMods.add(new FlowEntryBuilder(dpid, msg.)); | ||
| 307 | + switch (msg.getErrType()) { | ||
| 308 | + case BAD_ACTION: | ||
| 309 | + break; | ||
| 310 | + case BAD_INSTRUCTION: | ||
| 311 | + break; | ||
| 312 | + case BAD_MATCH: | ||
| 313 | + break; | ||
| 314 | + case BAD_REQUEST: | ||
| 315 | + break; | ||
| 316 | + case EXPERIMENTER: | ||
| 317 | + break; | ||
| 318 | + case FLOW_MOD_FAILED: | ||
| 319 | + break; | ||
| 320 | + case GROUP_MOD_FAILED: | ||
| 321 | + break; | ||
| 322 | + case HELLO_FAILED: | ||
| 323 | + break; | ||
| 324 | + case METER_MOD_FAILED: | ||
| 325 | + break; | ||
| 326 | + case PORT_MOD_FAILED: | ||
| 327 | + break; | ||
| 328 | + case QUEUE_OP_FAILED: | ||
| 329 | + break; | ||
| 330 | + case ROLE_REQUEST_FAILED: | ||
| 331 | + break; | ||
| 332 | + case SWITCH_CONFIG_FAILED: | ||
| 333 | + break; | ||
| 334 | + case TABLE_FEATURES_FAILED: | ||
| 335 | + break; | ||
| 336 | + case TABLE_MOD_FAILED: | ||
| 337 | + break; | ||
| 338 | + default: | ||
| 339 | + break; | ||
| 340 | + | ||
| 341 | + } | ||
| 342 | + | ||
| 343 | + } | ||
| 344 | + | ||
| 345 | + public void satisfyRequirement(Dpid dpid) { | ||
| 346 | + log.warn("Satisfaction from switch {}", dpid); | ||
| 347 | + sws.remove(controller.getSwitch(dpid)); | ||
| 348 | + countDownLatch.countDown(); | ||
| 349 | + } | ||
| 350 | + | ||
| 351 | + public void verify(Integer id) { | ||
| 352 | + for (Dpid dpid : sws) { | ||
| 353 | + OpenFlowSwitch sw = controller.getSwitch(dpid); | ||
| 354 | + OFBarrierRequest.Builder builder = sw.factory() | ||
| 355 | + .buildBarrierRequest() | ||
| 356 | + .setXid(id); | ||
| 357 | + sw.sendMsg(builder.build()); | ||
| 358 | + } | ||
| 359 | + | ||
| 360 | + | ||
| 361 | + } | ||
| 362 | + | ||
| 363 | + @Override | ||
| 364 | + public boolean cancel(boolean mayInterruptIfRunning) { | ||
| 365 | + // TODO Auto-generated method stub | ||
| 366 | + return false; | ||
| 367 | + } | ||
| 368 | + | ||
| 369 | + @Override | ||
| 370 | + public boolean isCancelled() { | ||
| 371 | + // TODO Auto-generated method stub | ||
| 372 | + return false; | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | + @Override | ||
| 376 | + public boolean isDone() { | ||
| 377 | + return sws.isEmpty(); | ||
| 378 | + } | ||
| 379 | + | ||
| 380 | + @Override | ||
| 381 | + public Void get() throws InterruptedException, ExecutionException { | ||
| 382 | + countDownLatch.await(); | ||
| 383 | + //return offendingFlowMods; | ||
| 384 | + return null; | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + @Override | ||
| 388 | + public Void get(long timeout, TimeUnit unit) | ||
| 389 | + throws InterruptedException, ExecutionException, | ||
| 390 | + TimeoutException { | ||
| 391 | + countDownLatch.await(timeout, unit); | ||
| 392 | + //return offendingFlowMods; | ||
| 393 | + return null; | ||
| 394 | + } | ||
| 229 | 395 | ||
| 396 | + } | ||
| 230 | 397 | ||
| 231 | } | 398 | } | ... | ... |
-
Please register or login to post a comment