Showing
27 changed files
with
525 additions
and
108 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. | ... | ... |
... | @@ -12,6 +12,7 @@ public interface ClockProviderService { | ... | @@ -12,6 +12,7 @@ public interface ClockProviderService { |
12 | 12 | ||
13 | /** | 13 | /** |
14 | * Updates the mastership term for the specified deviceId. | 14 | * Updates the mastership term for the specified deviceId. |
15 | + * | ||
15 | * @param deviceId device identifier. | 16 | * @param deviceId device identifier. |
16 | * @param term mastership term. | 17 | * @param term mastership term. |
17 | */ | 18 | */ | ... | ... |
... | @@ -144,6 +144,10 @@ public class DeviceManager | ... | @@ -144,6 +144,10 @@ public class DeviceManager |
144 | private void applyRole(DeviceId deviceId, MastershipRole newRole) { | 144 | private void applyRole(DeviceId deviceId, MastershipRole newRole) { |
145 | if (newRole != MastershipRole.NONE) { | 145 | if (newRole != MastershipRole.NONE) { |
146 | Device device = store.getDevice(deviceId); | 146 | Device device = store.getDevice(deviceId); |
147 | + // FIXME: Device might not be there yet. (eventual consistent) | ||
148 | + if (device == null) { | ||
149 | + return; | ||
150 | + } | ||
147 | DeviceProvider provider = getProvider(device.providerId()); | 151 | DeviceProvider provider = getProvider(device.providerId()); |
148 | if (provider != null) { | 152 | if (provider != null) { |
149 | provider.roleChanged(device, newRole); | 153 | provider.roleChanged(device, newRole); |
... | @@ -193,16 +197,38 @@ public class DeviceManager | ... | @@ -193,16 +197,38 @@ public class DeviceManager |
193 | checkNotNull(deviceId, DEVICE_ID_NULL); | 197 | checkNotNull(deviceId, DEVICE_ID_NULL); |
194 | checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL); | 198 | checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL); |
195 | checkValidity(); | 199 | checkValidity(); |
200 | + | ||
201 | + log.info("Device {} connected", deviceId); | ||
202 | + // check my Role | ||
203 | + MastershipRole role = mastershipService.requestRoleFor(deviceId); | ||
204 | + | ||
205 | + if (role != MastershipRole.MASTER) { | ||
206 | + // TODO: Do we need to tell the Provider that | ||
207 | + // I am no longer the MASTER? | ||
208 | + return; | ||
209 | + } | ||
210 | + | ||
211 | + // Master: | ||
212 | + MastershipTerm term = mastershipService.requestTermService() | ||
213 | + .getMastershipTerm(deviceId); | ||
214 | + if (!term.master().equals(clusterService.getLocalNode().id())) { | ||
215 | + // I've lost mastership after I thought I was MASTER. | ||
216 | + return; | ||
217 | + } | ||
218 | + clockProviderService.setMastershipTerm(deviceId, term); | ||
219 | + | ||
196 | DeviceEvent event = store.createOrUpdateDevice(provider().id(), | 220 | DeviceEvent event = store.createOrUpdateDevice(provider().id(), |
197 | deviceId, deviceDescription); | 221 | deviceId, deviceDescription); |
198 | 222 | ||
199 | - // If there was a change of any kind, trigger role selection | 223 | + // If there was a change of any kind, tell the provider |
200 | - // process. | 224 | + // I am the master. |
225 | + // Note: can be null, if mastership was lost. | ||
201 | if (event != null) { | 226 | if (event != null) { |
202 | - log.info("Device {} connected", deviceId); | 227 | + // TODO: Check switch reconnected case, is it assured that |
203 | - mastershipService.requestRoleFor(deviceId); | 228 | + // event will not be null? |
204 | - provider().roleChanged(event.subject(), | 229 | + |
205 | - mastershipService.requestRoleFor(deviceId)); | 230 | + // FIXME: 1st argument should be deviceId |
231 | + provider().roleChanged(event.subject(), role); | ||
206 | post(event); | 232 | post(event); |
207 | } | 233 | } |
208 | } | 234 | } |
... | @@ -211,6 +237,10 @@ public class DeviceManager | ... | @@ -211,6 +237,10 @@ public class DeviceManager |
211 | public void deviceDisconnected(DeviceId deviceId) { | 237 | public void deviceDisconnected(DeviceId deviceId) { |
212 | checkNotNull(deviceId, DEVICE_ID_NULL); | 238 | checkNotNull(deviceId, DEVICE_ID_NULL); |
213 | checkValidity(); | 239 | checkValidity(); |
240 | + if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { | ||
241 | + log.debug("Device {} disconnected, but I am not the master", deviceId); | ||
242 | + return; | ||
243 | + } | ||
214 | DeviceEvent event = store.markOffline(deviceId); | 244 | DeviceEvent event = store.markOffline(deviceId); |
215 | 245 | ||
216 | //we're no longer capable of mastership. | 246 | //we're no longer capable of mastership. |
... | @@ -272,9 +302,15 @@ public class DeviceManager | ... | @@ -272,9 +302,15 @@ public class DeviceManager |
272 | @Override | 302 | @Override |
273 | public void event(MastershipEvent event) { | 303 | public void event(MastershipEvent event) { |
274 | if (event.master().equals(clusterService.getLocalNode().id())) { | 304 | if (event.master().equals(clusterService.getLocalNode().id())) { |
305 | + | ||
275 | MastershipTerm term = mastershipService.requestTermService() | 306 | MastershipTerm term = mastershipService.requestTermService() |
276 | .getMastershipTerm(event.subject()); | 307 | .getMastershipTerm(event.subject()); |
277 | - clockProviderService.setMastershipTerm(event.subject(), term); | 308 | + |
309 | + if (term.master().equals(clusterService.getLocalNode().id())) { | ||
310 | + // only set if I am the master | ||
311 | + clockProviderService.setMastershipTerm(event.subject(), term); | ||
312 | + } | ||
313 | + | ||
278 | applyRole(event.subject(), MastershipRole.MASTER); | 314 | applyRole(event.subject(), MastershipRole.MASTER); |
279 | } else { | 315 | } else { |
280 | applyRole(event.subject(), MastershipRole.STANDBY); | 316 | applyRole(event.subject(), MastershipRole.STANDBY); | ... | ... |
... | @@ -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 | ... | ... |
... | @@ -45,4 +45,9 @@ public class MessageSubject { | ... | @@ -45,4 +45,9 @@ public class MessageSubject { |
45 | MessageSubject that = (MessageSubject) obj; | 45 | MessageSubject that = (MessageSubject) obj; |
46 | return Objects.equals(this.value, that.value); | 46 | return Objects.equals(this.value, that.value); |
47 | } | 47 | } |
48 | + | ||
49 | + // for serializer | ||
50 | + protected MessageSubject() { | ||
51 | + this.value = ""; | ||
52 | + } | ||
48 | } | 53 | } | ... | ... |
... | @@ -3,11 +3,11 @@ package org.onlab.onos.store.cluster.messaging.impl; | ... | @@ -3,11 +3,11 @@ package org.onlab.onos.store.cluster.messaging.impl; |
3 | import static com.google.common.base.Preconditions.checkArgument; | 3 | import static com.google.common.base.Preconditions.checkArgument; |
4 | 4 | ||
5 | import java.io.IOException; | 5 | import java.io.IOException; |
6 | -import java.util.HashMap; | ||
7 | -import java.util.Map; | ||
8 | import java.util.Set; | 6 | import java.util.Set; |
9 | import java.util.Timer; | 7 | import java.util.Timer; |
10 | import java.util.TimerTask; | 8 | import java.util.TimerTask; |
9 | +import java.util.concurrent.TimeUnit; | ||
10 | +import java.util.concurrent.TimeoutException; | ||
11 | 11 | ||
12 | import org.apache.felix.scr.annotations.Activate; | 12 | import org.apache.felix.scr.annotations.Activate; |
13 | import org.apache.felix.scr.annotations.Component; | 13 | import org.apache.felix.scr.annotations.Component; |
... | @@ -26,6 +26,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; | ... | @@ -26,6 +26,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; |
26 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; | 26 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; |
27 | import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; | 27 | import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; |
28 | import org.onlab.onos.store.cluster.messaging.MessageSubject; | 28 | import org.onlab.onos.store.cluster.messaging.MessageSubject; |
29 | +import org.onlab.onos.store.serializers.ClusterMessageSerializer; | ||
29 | import org.onlab.onos.store.serializers.KryoPoolUtil; | 30 | import org.onlab.onos.store.serializers.KryoPoolUtil; |
30 | import org.onlab.onos.store.serializers.KryoSerializer; | 31 | import org.onlab.onos.store.serializers.KryoSerializer; |
31 | import org.onlab.util.KryoPool; | 32 | import org.onlab.util.KryoPool; |
... | @@ -34,6 +35,7 @@ import org.onlab.netty.Message; | ... | @@ -34,6 +35,7 @@ import org.onlab.netty.Message; |
34 | import org.onlab.netty.MessageHandler; | 35 | import org.onlab.netty.MessageHandler; |
35 | import org.onlab.netty.MessagingService; | 36 | import org.onlab.netty.MessagingService; |
36 | import org.onlab.netty.NettyMessagingService; | 37 | import org.onlab.netty.NettyMessagingService; |
38 | +import org.onlab.netty.Response; | ||
37 | import org.slf4j.Logger; | 39 | import org.slf4j.Logger; |
38 | import org.slf4j.LoggerFactory; | 40 | import org.slf4j.LoggerFactory; |
39 | 41 | ||
... | @@ -50,8 +52,6 @@ public class ClusterCommunicationManager | ... | @@ -50,8 +52,6 @@ public class ClusterCommunicationManager |
50 | private ClusterService clusterService; | 52 | private ClusterService clusterService; |
51 | 53 | ||
52 | private ClusterNodesDelegate nodesDelegate; | 54 | private ClusterNodesDelegate nodesDelegate; |
53 | - // FIXME: `members` should go away and should be using ClusterService | ||
54 | - private Map<NodeId, ControllerNode> members = new HashMap<>(); | ||
55 | private final Timer timer = new Timer("onos-controller-heatbeats"); | 55 | private final Timer timer = new Timer("onos-controller-heatbeats"); |
56 | public static final long HEART_BEAT_INTERVAL_MILLIS = 1000L; | 56 | public static final long HEART_BEAT_INTERVAL_MILLIS = 1000L; |
57 | 57 | ||
... | @@ -59,11 +59,14 @@ public class ClusterCommunicationManager | ... | @@ -59,11 +59,14 @@ public class ClusterCommunicationManager |
59 | private MessagingService messagingService; | 59 | private MessagingService messagingService; |
60 | 60 | ||
61 | private static final KryoSerializer SERIALIZER = new KryoSerializer() { | 61 | private static final KryoSerializer SERIALIZER = new KryoSerializer() { |
62 | + @Override | ||
62 | protected void setupKryoPool() { | 63 | protected void setupKryoPool() { |
63 | serializerPool = KryoPool.newBuilder() | 64 | serializerPool = KryoPool.newBuilder() |
64 | .register(KryoPoolUtil.API) | 65 | .register(KryoPoolUtil.API) |
65 | - .register(ClusterMessage.class) | 66 | + .register(ClusterMessage.class, new ClusterMessageSerializer()) |
66 | .register(ClusterMembershipEvent.class) | 67 | .register(ClusterMembershipEvent.class) |
68 | + .register(byte[].class) | ||
69 | + .register(MessageSubject.class) | ||
67 | .build() | 70 | .build() |
68 | .populate(1); | 71 | .populate(1); |
69 | } | 72 | } |
... | @@ -73,7 +76,15 @@ public class ClusterCommunicationManager | ... | @@ -73,7 +76,15 @@ public class ClusterCommunicationManager |
73 | @Activate | 76 | @Activate |
74 | public void activate() { | 77 | public void activate() { |
75 | localNode = clusterService.getLocalNode(); | 78 | localNode = clusterService.getLocalNode(); |
76 | - messagingService = new NettyMessagingService(localNode.tcpPort()); | 79 | + NettyMessagingService netty = new NettyMessagingService(localNode.tcpPort()); |
80 | + // FIXME: workaround until it becomes a service. | ||
81 | + try { | ||
82 | + netty.activate(); | ||
83 | + } catch (Exception e) { | ||
84 | + // TODO Auto-generated catch block | ||
85 | + log.error("NettyMessagingService#activate", e); | ||
86 | + } | ||
87 | + messagingService = netty; | ||
77 | log.info("Started"); | 88 | log.info("Started"); |
78 | } | 89 | } |
79 | 90 | ||
... | @@ -86,7 +97,7 @@ public class ClusterCommunicationManager | ... | @@ -86,7 +97,7 @@ public class ClusterCommunicationManager |
86 | @Override | 97 | @Override |
87 | public boolean broadcast(ClusterMessage message) { | 98 | public boolean broadcast(ClusterMessage message) { |
88 | boolean ok = true; | 99 | boolean ok = true; |
89 | - for (ControllerNode node : members.values()) { | 100 | + for (ControllerNode node : clusterService.getNodes()) { |
90 | if (!node.equals(localNode)) { | 101 | if (!node.equals(localNode)) { |
91 | ok = unicast(message, node.id()) && ok; | 102 | ok = unicast(message, node.id()) && ok; |
92 | } | 103 | } |
... | @@ -107,13 +118,16 @@ public class ClusterCommunicationManager | ... | @@ -107,13 +118,16 @@ public class ClusterCommunicationManager |
107 | 118 | ||
108 | @Override | 119 | @Override |
109 | public boolean unicast(ClusterMessage message, NodeId toNodeId) { | 120 | public boolean unicast(ClusterMessage message, NodeId toNodeId) { |
110 | - ControllerNode node = members.get(toNodeId); | 121 | + ControllerNode node = clusterService.getNode(toNodeId); |
111 | checkArgument(node != null, "Unknown nodeId: %s", toNodeId); | 122 | checkArgument(node != null, "Unknown nodeId: %s", toNodeId); |
112 | Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort()); | 123 | Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort()); |
113 | try { | 124 | try { |
114 | - messagingService.sendAsync(nodeEp, message.subject().value(), SERIALIZER.encode(message)); | 125 | + log.info("sending..."); |
126 | + Response resp = messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message)); | ||
127 | + resp.get(1, TimeUnit.SECONDS); | ||
128 | + log.info("sent..."); | ||
115 | return true; | 129 | return true; |
116 | - } catch (IOException e) { | 130 | + } catch (IOException | TimeoutException e) { |
117 | log.error("Failed to send cluster message to nodeId: " + toNodeId, e); | 131 | log.error("Failed to send cluster message to nodeId: " + toNodeId, e); |
118 | } | 132 | } |
119 | 133 | ||
... | @@ -137,7 +151,7 @@ public class ClusterCommunicationManager | ... | @@ -137,7 +151,7 @@ public class ClusterCommunicationManager |
137 | 151 | ||
138 | @Override | 152 | @Override |
139 | public void addNode(ControllerNode node) { | 153 | public void addNode(ControllerNode node) { |
140 | - members.put(node.id(), node); | 154 | + //members.put(node.id(), node); |
141 | } | 155 | } |
142 | 156 | ||
143 | @Override | 157 | @Override |
... | @@ -146,7 +160,7 @@ public class ClusterCommunicationManager | ... | @@ -146,7 +160,7 @@ public class ClusterCommunicationManager |
146 | localNode.id(), | 160 | localNode.id(), |
147 | new MessageSubject("CLUSTER_MEMBERSHIP_EVENT"), | 161 | new MessageSubject("CLUSTER_MEMBERSHIP_EVENT"), |
148 | SERIALIZER.encode(new ClusterMembershipEvent(ClusterMembershipEventType.LEAVING_MEMBER, node)))); | 162 | SERIALIZER.encode(new ClusterMembershipEvent(ClusterMembershipEventType.LEAVING_MEMBER, node)))); |
149 | - members.remove(node.id()); | 163 | + //members.remove(node.id()); |
150 | } | 164 | } |
151 | 165 | ||
152 | // Sends a heart beat to all peers. | 166 | // Sends a heart beat to all peers. |
... | @@ -181,7 +195,8 @@ public class ClusterCommunicationManager | ... | @@ -181,7 +195,8 @@ public class ClusterCommunicationManager |
181 | } | 195 | } |
182 | } | 196 | } |
183 | 197 | ||
184 | - private static class InternalClusterMessageHandler implements MessageHandler { | 198 | + // FIXME: revert static |
199 | + private class InternalClusterMessageHandler implements MessageHandler { | ||
185 | 200 | ||
186 | private final ClusterMessageHandler handler; | 201 | private final ClusterMessageHandler handler; |
187 | 202 | ||
... | @@ -191,8 +206,18 @@ public class ClusterCommunicationManager | ... | @@ -191,8 +206,18 @@ public class ClusterCommunicationManager |
191 | 206 | ||
192 | @Override | 207 | @Override |
193 | public void handle(Message message) { | 208 | public void handle(Message message) { |
194 | - ClusterMessage clusterMessage = SERIALIZER.decode(message.payload()); | 209 | + // FIXME: remove me |
195 | - handler.handle(clusterMessage); | 210 | + log.info("InternalClusterMessageHandler.handle({})", message); |
211 | + try { | ||
212 | + log.info("before decode"); | ||
213 | + ClusterMessage clusterMessage = SERIALIZER.decode(message.payload()); | ||
214 | + log.info("Subject:({}), Sender:({})", clusterMessage.subject(), clusterMessage.sender()); | ||
215 | + handler.handle(clusterMessage); | ||
216 | + message.respond("ACK".getBytes()); | ||
217 | + } catch (Exception e) { | ||
218 | + // TODO Auto-generated catch block | ||
219 | + log.error("failed", e); | ||
220 | + } | ||
196 | } | 221 | } |
197 | } | 222 | } |
198 | } | 223 | } | ... | ... |
... | @@ -113,6 +113,7 @@ public class GossipDeviceStore | ... | @@ -113,6 +113,7 @@ public class GossipDeviceStore |
113 | protected ClusterService clusterService; | 113 | protected ClusterService clusterService; |
114 | 114 | ||
115 | private static final KryoSerializer SERIALIZER = new KryoSerializer() { | 115 | private static final KryoSerializer SERIALIZER = new KryoSerializer() { |
116 | + @Override | ||
116 | protected void setupKryoPool() { | 117 | protected void setupKryoPool() { |
117 | serializerPool = KryoPool.newBuilder() | 118 | serializerPool = KryoPool.newBuilder() |
118 | .register(KryoPoolUtil.API) | 119 | .register(KryoPoolUtil.API) | ... | ... |
... | @@ -35,4 +35,11 @@ public class InternalDeviceEvent { | ... | @@ -35,4 +35,11 @@ public class InternalDeviceEvent { |
35 | public Timestamped<DeviceDescription> deviceDescription() { | 35 | public Timestamped<DeviceDescription> deviceDescription() { |
36 | return deviceDescription; | 36 | return deviceDescription; |
37 | } | 37 | } |
38 | + | ||
39 | + // for serializer | ||
40 | + protected InternalDeviceEvent() { | ||
41 | + this.providerId = null; | ||
42 | + this.deviceId = null; | ||
43 | + this.deviceDescription = null; | ||
44 | + } | ||
38 | } | 45 | } | ... | ... |
... | @@ -37,4 +37,11 @@ public class InternalPortEvent { | ... | @@ -37,4 +37,11 @@ public class InternalPortEvent { |
37 | public Timestamped<List<PortDescription>> portDescriptions() { | 37 | public Timestamped<List<PortDescription>> portDescriptions() { |
38 | return portDescriptions; | 38 | return portDescriptions; |
39 | } | 39 | } |
40 | + | ||
41 | + // for serializer | ||
42 | + protected InternalPortEvent() { | ||
43 | + this.providerId = null; | ||
44 | + this.deviceId = null; | ||
45 | + this.portDescriptions = null; | ||
46 | + } | ||
40 | } | 47 | } | ... | ... |
... | @@ -35,4 +35,11 @@ public class InternalPortStatusEvent { | ... | @@ -35,4 +35,11 @@ public class InternalPortStatusEvent { |
35 | public Timestamped<PortDescription> portDescription() { | 35 | public Timestamped<PortDescription> portDescription() { |
36 | return portDescription; | 36 | return portDescription; |
37 | } | 37 | } |
38 | + | ||
39 | + // for serializer | ||
40 | + protected InternalPortStatusEvent() { | ||
41 | + this.providerId = null; | ||
42 | + this.deviceId = null; | ||
43 | + this.portDescription = null; | ||
44 | + } | ||
38 | } | 45 | } | ... | ... |
... | @@ -119,8 +119,8 @@ implements MastershipStore { | ... | @@ -119,8 +119,8 @@ implements MastershipStore { |
119 | 119 | ||
120 | @Override | 120 | @Override |
121 | public MastershipTerm getTermFor(DeviceId deviceId) { | 121 | public MastershipTerm getTermFor(DeviceId deviceId) { |
122 | - // TODO Auto-generated method stub | 122 | + // FIXME: implement this |
123 | - return null; | 123 | + return MastershipTerm.of(getMaster(deviceId), 1); |
124 | } | 124 | } |
125 | 125 | ||
126 | @Override | 126 | @Override | ... | ... |
... | @@ -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 | + } | ||
229 | 359 | ||
230 | 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 | + } | ||
395 | + | ||
396 | + } | ||
397 | + | ||
231 | } | 398 | } | ... | ... |
... | @@ -8,11 +8,16 @@ import io.netty.handler.codec.ReplayingDecoder; | ... | @@ -8,11 +8,16 @@ import io.netty.handler.codec.ReplayingDecoder; |
8 | import java.util.Arrays; | 8 | import java.util.Arrays; |
9 | import java.util.List; | 9 | import java.util.List; |
10 | 10 | ||
11 | +import org.slf4j.Logger; | ||
12 | +import org.slf4j.LoggerFactory; | ||
13 | + | ||
11 | /** | 14 | /** |
12 | * Decoder for inbound messages. | 15 | * Decoder for inbound messages. |
13 | */ | 16 | */ |
14 | public class MessageDecoder extends ReplayingDecoder<DecoderState> { | 17 | public class MessageDecoder extends ReplayingDecoder<DecoderState> { |
15 | 18 | ||
19 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
20 | + | ||
16 | private final NettyMessagingService messagingService; | 21 | private final NettyMessagingService messagingService; |
17 | 22 | ||
18 | private static final KryoSerializer SERIALIZER = new KryoSerializer(); | 23 | private static final KryoSerializer SERIALIZER = new KryoSerializer(); |
... | @@ -57,4 +62,10 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { | ... | @@ -57,4 +62,10 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { |
57 | checkState(false, "Must not be here"); | 62 | checkState(false, "Must not be here"); |
58 | } | 63 | } |
59 | } | 64 | } |
65 | + | ||
66 | + @Override | ||
67 | + public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { | ||
68 | + log.error("Exception inside channel handling pipeline.", cause); | ||
69 | + context.close(); | ||
70 | + } | ||
60 | } | 71 | } | ... | ... |
1 | package org.onlab.netty; | 1 | package org.onlab.netty; |
2 | 2 | ||
3 | +import org.slf4j.Logger; | ||
4 | +import org.slf4j.LoggerFactory; | ||
5 | + | ||
3 | import io.netty.buffer.ByteBuf; | 6 | import io.netty.buffer.ByteBuf; |
4 | import io.netty.channel.ChannelHandler.Sharable; | 7 | import io.netty.channel.ChannelHandler.Sharable; |
5 | import io.netty.channel.ChannelHandlerContext; | 8 | import io.netty.channel.ChannelHandlerContext; |
... | @@ -11,6 +14,8 @@ import io.netty.handler.codec.MessageToByteEncoder; | ... | @@ -11,6 +14,8 @@ import io.netty.handler.codec.MessageToByteEncoder; |
11 | @Sharable | 14 | @Sharable |
12 | public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { | 15 | public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { |
13 | 16 | ||
17 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
18 | + | ||
14 | // onosiscool in ascii | 19 | // onosiscool in ascii |
15 | public static final byte[] PREAMBLE = "onosiscool".getBytes(); | 20 | public static final byte[] PREAMBLE = "onosiscool".getBytes(); |
16 | public static final int HEADER_VERSION = 1; | 21 | public static final int HEADER_VERSION = 1; |
... | @@ -47,4 +52,10 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { | ... | @@ -47,4 +52,10 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { |
47 | // write payload. | 52 | // write payload. |
48 | out.writeBytes(payload); | 53 | out.writeBytes(payload); |
49 | } | 54 | } |
55 | + | ||
56 | + @Override | ||
57 | + public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { | ||
58 | + log.error("Exception inside channel handling pipeline.", cause); | ||
59 | + context.close(); | ||
60 | + } | ||
50 | } | 61 | } | ... | ... |
... | @@ -248,6 +248,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -248,6 +248,7 @@ public class NettyMessagingService implements MessagingService { |
248 | 248 | ||
249 | @Override | 249 | @Override |
250 | public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { | 250 | public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { |
251 | + log.error("Exception inside channel handling pipeline.", cause); | ||
251 | context.close(); | 252 | context.close(); |
252 | } | 253 | } |
253 | } | 254 | } | ... | ... |
1 | -package org.onlab.netty; | ||
2 | - | ||
3 | -import java.util.concurrent.TimeUnit; | ||
4 | - | ||
5 | -import org.onlab.metrics.MetricsComponent; | ||
6 | -import org.onlab.metrics.MetricsFeature; | ||
7 | -import org.onlab.metrics.MetricsManager; | ||
8 | - | ||
9 | -import com.codahale.metrics.Timer; | ||
10 | - | ||
11 | -// FIXME: Should be move out to test or app | ||
12 | -public final class SimpleClient { | ||
13 | - private SimpleClient() { | ||
14 | - } | ||
15 | - | ||
16 | - public static void main(String... args) throws Exception { | ||
17 | - NettyMessagingService messaging = new TestNettyMessagingService(9081); | ||
18 | - MetricsManager metrics = new MetricsManager(); | ||
19 | - messaging.activate(); | ||
20 | - metrics.activate(); | ||
21 | - MetricsFeature feature = new MetricsFeature("timers"); | ||
22 | - MetricsComponent component = metrics.registerComponent("NettyMessaging"); | ||
23 | - Timer sendAsyncTimer = metrics.createTimer(component, feature, "AsyncSender"); | ||
24 | - final int warmup = 100; | ||
25 | - for (int i = 0; i < warmup; i++) { | ||
26 | - Timer.Context context = sendAsyncTimer.time(); | ||
27 | - messaging.sendAsync(new Endpoint("localhost", 8080), "simple", "Hello World".getBytes()); | ||
28 | - context.stop(); | ||
29 | - } | ||
30 | - metrics.registerMetric(component, feature, "AsyncTimer", sendAsyncTimer); | ||
31 | - | ||
32 | - Timer sendAndReceiveTimer = metrics.createTimer(component, feature, "SendAndReceive"); | ||
33 | - final int iterations = 1000000; | ||
34 | - for (int i = 0; i < iterations; i++) { | ||
35 | - Timer.Context context = sendAndReceiveTimer.time(); | ||
36 | - Response response = messaging | ||
37 | - .sendAndReceive(new Endpoint("localhost", 8080), "echo", | ||
38 | - "Hello World".getBytes()); | ||
39 | - System.out.println("Got back:" + new String(response.get(2, TimeUnit.SECONDS))); | ||
40 | - context.stop(); | ||
41 | - } | ||
42 | - metrics.registerMetric(component, feature, "AsyncTimer", sendAndReceiveTimer); | ||
43 | - } | ||
44 | - | ||
45 | - public static class TestNettyMessagingService extends NettyMessagingService { | ||
46 | - public TestNettyMessagingService(int port) throws Exception { | ||
47 | - super(port); | ||
48 | - } | ||
49 | - } | ||
50 | -} |
1 | -package org.onlab.netty; | ||
2 | - | ||
3 | -//FIXME: Should be move out to test or app | ||
4 | -public final class SimpleServer { | ||
5 | - private SimpleServer() {} | ||
6 | - | ||
7 | - public static void main(String... args) throws Exception { | ||
8 | - NettyMessagingService server = new NettyMessagingService(8080); | ||
9 | - server.activate(); | ||
10 | - server.registerHandler("simple", new LoggingHandler()); | ||
11 | - server.registerHandler("echo", new EchoHandler()); | ||
12 | - } | ||
13 | -} |
-
Please register or login to post a comment