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