Brian O'Connor
Committed by Gerrit Code Review

Implementation of new Flow Subsystem:

The subsystem no longer returns futures for tracking completion of work.
Notifications are explicitely returned via a call back mechanism. Also, the
subsystem is now asynchronous.

Change-Id: I1a4cef931c24820f9ae9ed9a5398f163f05dfbc9

more flowservice improvements

Change-Id: I5c9c1b6be4b2ebfa523b64f6f52e7634b7d3e05f

more flowservice impl

Change-Id: I05f6774460effb53ced8c36844bcda2f8f6c096f

Manager to store functional (at least i believe it)

Change-Id: I09b04989bd1004c98fe0bafed4c76714b9155d53

flow subsystem functional: need to fix unit tests

Change-Id: I1667f25b91320f625a03e5e1d5e92823184d9de0

flow subsystem functional

Change-Id: I429b3335c16d4fc16f5d55f233dd37c4d1d6111d

finished refactor of flow subsystem

Change-Id: I1899abc6ff6a974a2018d936cc555049c70a6804

fix for null flow provider to use new api

Change-Id: If2fd9bd5baf74d9c61c5c8085cef8bc2d204cbdc
Showing 34 changed files with 656 additions and 236 deletions
......@@ -19,29 +19,30 @@ package org.onosproject.cli.net;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.packet.MacAddress;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.Device;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchOperation;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onlab.packet.MacAddress;
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Installs many many flows.
......@@ -50,6 +51,8 @@ import java.util.concurrent.Future;
description = "Installs a number of test flow rules - for testing only")
public class AddFlowsCommand extends AbstractShellCommand {
private CountDownLatch latch;
@Argument(index = 0, name = "flowPerDevice", description = "Number of flows to add per device",
required = true, multiValued = false)
String flows = null;
......@@ -63,6 +66,9 @@ public class AddFlowsCommand extends AbstractShellCommand {
FlowRuleService flowService = get(FlowRuleService.class);
DeviceService deviceService = get(DeviceService.class);
CoreService coreService = get(CoreService.class);
ApplicationId appId = coreService.registerApplication("onos.test.flow.installer");
int flowsPerDevice = Integer.parseInt(flows);
int num = Integer.parseInt(numOfRuns);
......@@ -70,49 +76,73 @@ public class AddFlowsCommand extends AbstractShellCommand {
ArrayList<Long> results = Lists.newArrayList();
Iterable<Device> devices = deviceService.getDevices();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(1)).build();
.setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build();
TrafficSelector.Builder sbuilder;
Set<FlowRuleBatchEntry> rules = Sets.newHashSet();
Set<FlowRuleBatchEntry> remove = Sets.newHashSet();
FlowRuleOperations.Builder rules = FlowRuleOperations.builder();
FlowRuleOperations.Builder remove = FlowRuleOperations.builder();
for (Device d : devices) {
for (int i = 0; i < flowsPerDevice; i++) {
sbuilder = DefaultTrafficSelector.builder();
sbuilder.matchEthSrc(MacAddress.valueOf(i))
.matchEthDst(MacAddress.valueOf(Integer.MAX_VALUE - i));
rules.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.ADD,
new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
100, (long) 0, 10, false)));
remove.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.REMOVE,
new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
100, (long) 0, 10, false)));
sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i))
.matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt()));
int randomPriority = RandomUtils.nextInt();
rules.add(new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
randomPriority, appId, 10, false));
remove.remove(new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
randomPriority, appId, 10, false));
}
}
boolean isSuccess = true;
for (int i = 0; i < num; i++) {
long startTime = System.currentTimeMillis();
Future<CompletedBatchOperation> op = flowService.applyBatch(
new FlowRuleBatchOperation(rules));
latch = new CountDownLatch(2);
flowService.apply(rules.build(new FlowRuleOperationsContext() {
private final Stopwatch timer = Stopwatch.createStarted();
@Override
public void onSuccess(FlowRuleOperations ops) {
timer.stop();
results.add(timer.elapsed(TimeUnit.MILLISECONDS));
if (results.size() == num) {
if (outputJson()) {
print("%s", json(new ObjectMapper(), true, results));
} else {
printTime(true, results);
}
}
latch.countDown();
}
}));
flowService.apply(remove.build(new FlowRuleOperationsContext() {
@Override
public void onSuccess(FlowRuleOperations ops) {
latch.countDown();
}
}));
try {
isSuccess &= op.get().isSuccess();
} catch (InterruptedException | ExecutionException e) {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
results.add(endTime - startTime);
flowService.applyBatch(
new FlowRuleBatchOperation(remove));
}
if (outputJson()) {
print("%s", json(new ObjectMapper(), isSuccess, results));
} else {
printTime(isSuccess, results);
}
}
private Object json(ObjectMapper mapper, boolean isSuccess, ArrayList<Long> elapsed) {
ObjectNode result = mapper.createObjectNode();
result.put("Success", isSuccess);
......
......@@ -21,6 +21,7 @@ import java.util.Set;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import org.onosproject.net.DeviceId;
/**
* Representation of a completed flow rule batch operation.
......@@ -30,19 +31,22 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
private final boolean success;
private final Set<FlowRule> failures;
private final Set<Long> failedIds;
private final DeviceId deviceId;
/**
* Creates a new batch completion result.
*
* @param success indicates whether the completion is successful.
* @param success indicates whether the completion is successful
* @param failures set of any failures encountered
* @param failedIds (optional) set of failed operation ids
* @param deviceId the device this operation completed for
*/
public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures,
Set<Long> failedIds) {
Set<Long> failedIds, DeviceId deviceId) {
this.success = success;
this.failures = ImmutableSet.copyOf(failures);
this.failedIds = ImmutableSet.copyOf(failedIds);
this.deviceId = deviceId;
}
/**
......@@ -51,10 +55,12 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
* @param success indicates whether the completion is successful.
* @param failures set of any failures encountered
*/
public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures) {
public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures,
DeviceId deviceId) {
this.success = success;
this.failures = ImmutableSet.copyOf(failures);
this.failedIds = Collections.emptySet();
this.deviceId = deviceId;
}
......@@ -73,12 +79,17 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
return failedIds;
}
public DeviceId deviceId() {
return this.deviceId;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("success?", success)
.add("failedItems", failures)
.add("failedIds", failedIds)
.add("deviceId", deviceId)
.toString();
}
}
......
......@@ -16,12 +16,14 @@
package org.onosproject.net.flow;
import org.onosproject.event.AbstractEvent;
import org.onosproject.net.DeviceId;
/**
* Describes flow rule batch event.
*/
public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> {
/**
* Type of flow rule events.
*/
......@@ -42,14 +44,17 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T
}
private final CompletedBatchOperation result;
private final DeviceId deviceId;
/**
* Constructs a new FlowRuleBatchEvent.
* @param request batch operation request.
*
* @param request batch operation request
* @param deviceId the device this batch will be processed on
* @return event.
*/
public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request) {
FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, null);
public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request, DeviceId deviceId) {
FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, deviceId);
return event;
}
......@@ -73,13 +78,36 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T
}
/**
* Returns the deviceId for this batch.
* @return device id
*/
public DeviceId deviceId() {
return deviceId;
}
/**
* Creates an event of a given type and for the specified flow rule batch.
*
* @param type flow rule batch event type
* @param batch event flow rule batch subject
* @param request event flow rule batch subject
* @param result the result of the batch operation
*/
private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) {
super(type, request);
this.result = result;
this.deviceId = result.deviceId();
}
/**
* Creates an event of a given type and for the specified flow rule batch.
*
* @param type flow rule batch event type
* @param request event flow rule batch subject
* @param deviceId the device id for this batch
*/
private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, DeviceId deviceId) {
super(type, request);
this.result = null;
this.deviceId = deviceId;
}
}
......
......@@ -15,12 +15,37 @@
*/
package org.onosproject.net.flow;
import org.onosproject.net.DeviceId;
import java.util.Collection;
/**
* Class used with the flow subsystem to process per device
* batches.
*/
public class FlowRuleBatchOperation
extends BatchOperation<FlowRuleBatchEntry> {
public FlowRuleBatchOperation(Collection<FlowRuleBatchEntry> operations) {
/**
* This id is used to cary to id of the original
* FlowOperations and track where this batch operation
* came from. The id is unique cluster wide.
*/
private final long id;
private final DeviceId deviceId;
public FlowRuleBatchOperation(Collection<FlowRuleBatchEntry> operations,
DeviceId deviceId, long flowOperationId) {
super(operations);
this.id = flowOperationId;
this.deviceId = deviceId;
}
public DeviceId deviceId() {
return this.deviceId;
}
public long id() {
return id;
}
}
......
......@@ -15,59 +15,43 @@
*/
package org.onosproject.net.flow;
import com.google.common.collect.Lists;
import org.onosproject.net.DeviceId;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
public class FlowRuleBatchRequest {
/**
* This id is used to cary to id of the original
* FlowOperations and track where this batch operation
* came from. The id is unique cluster wide.
*/
private final long batchId;
private final Set<FlowRuleBatchEntry> ops;
import com.google.common.collect.Lists;
public class FlowRuleBatchRequest {
private final int batchId;
private final List<FlowRuleBatchEntry> toAdd;
private final List<FlowRuleBatchEntry> toRemove;
public FlowRuleBatchRequest(int batchId, List<FlowRuleBatchEntry> toAdd,
List<FlowRuleBatchEntry> toRemove) {
public FlowRuleBatchRequest(long batchId, Set<FlowRuleBatchEntry> ops) {
this.batchId = batchId;
this.toAdd = Collections.unmodifiableList(toAdd);
this.toRemove = Collections.unmodifiableList(toRemove);
}
this.ops = Collections.unmodifiableSet(ops);
public List<FlowRule> toAdd() {
return FluentIterable.from(toAdd).transform(
new Function<FlowRuleBatchEntry, FlowRule>() {
@Override
public FlowRule apply(FlowRuleBatchEntry input) {
return input.target();
}
}).toList();
}
public List<FlowRule> toRemove() {
return FluentIterable.from(toRemove).transform(
new Function<FlowRuleBatchEntry, FlowRule>() {
@Override
public FlowRule apply(FlowRuleBatchEntry input) {
return input.target();
}
}).toList();
public Set<FlowRuleBatchEntry> ops() {
return ops;
}
public FlowRuleBatchOperation asBatchOperation() {
public FlowRuleBatchOperation asBatchOperation(DeviceId deviceId) {
List<FlowRuleBatchEntry> entries = Lists.newArrayList();
entries.addAll(toAdd);
entries.addAll(toRemove);
return new FlowRuleBatchOperation(entries);
entries.addAll(ops);
return new FlowRuleBatchOperation(entries, deviceId, batchId);
}
public int batchId() {
public long batchId() {
return batchId;
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.flow;
import com.google.common.base.MoreObjects;
/**
* Representation of an operation on a flow rule table.
*/
public class FlowRuleOperation {
/**
* Type of flow table operations.
*/
public enum Type {
ADD,
MODIFY,
REMOVE
}
private final FlowRule rule;
private final Type type;
public FlowRuleOperation(FlowRule rule, Type type) {
this.rule = rule;
this.type = type;
}
/**
* Returns the type of operation.
*
* @return type
*/
public Type type() {
return type;
}
/**
* Returns the flow rule.
*
* @return flow rule
*/
public FlowRule rule() {
return rule;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("rule", rule)
.add("type", type)
.toString();
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.flow;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Set;
import static org.onosproject.net.flow.FlowRuleOperation.Type.*;
/**
* A batch of flow rule operations that are broken into stages.
* TODO move this up to parent's package
*/
public class FlowRuleOperations {
private final List<Set<FlowRuleOperation>> stages;
private final FlowRuleOperationsContext callback; // TODO consider Optional
private FlowRuleOperations(List<Set<FlowRuleOperation>> stages,
FlowRuleOperationsContext cb) {
this.stages = stages;
this.callback = cb;
}
// kryo-constructor
protected FlowRuleOperations() {
this.stages = Lists.newArrayList();
this.callback = null;
}
/**
* Returns the flow rule operations as sets of stages that should be
* executed sequentially.
*
* @return flow rule stages
*/
public List<Set<FlowRuleOperation>> stages() {
return stages;
}
/**
* Returns the callback for this batch of operations.
*
* @return callback
*/
public FlowRuleOperationsContext callback() {
return callback;
}
/**
* Returns a new builder.
*
* @return new builder
*/
public static Builder builder() {
return new Builder();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("stages", stages)
.toString();
}
/**
* A builder for constructing flow rule operations.
*/
public static final class Builder {
private final ImmutableList.Builder<Set<FlowRuleOperation>> listBuilder = ImmutableList.builder();
private ImmutableSet.Builder<FlowRuleOperation> currentStage = ImmutableSet.builder();
// prevent use of the default constructor outside of this file; use the above method
private Builder() {}
/**
* Appends a flow rule add to the current stage.
*
* @param flowRule flow rule
* @return this
*/
public Builder add(FlowRule flowRule) {
currentStage.add(new FlowRuleOperation(flowRule, ADD));
return this;
}
/**
* Appends a flow rule modify to the current stage.
*
* @param flowRule flow rule
* @return this
*/
public Builder modify(FlowRule flowRule) {
currentStage.add(new FlowRuleOperation(flowRule, MODIFY));
return this;
}
/**
* Appends a flow rule remove to the current stage.
*
* @param flowRule flow rule
* @return this
*/
// FIXME this is confusing, consider renaming
public Builder remove(FlowRule flowRule) {
currentStage.add(new FlowRuleOperation(flowRule, REMOVE));
return this;
}
/**
* Closes the current stage.
*/
private void closeStage() {
ImmutableSet<FlowRuleOperation> stage = currentStage.build();
if (!stage.isEmpty()) {
listBuilder.add(stage);
}
}
/**
* Closes the current stage and starts a new one.
*
* @return this
*/
public Builder newStage() {
closeStage();
currentStage = ImmutableSet.builder();
return this;
}
/**
* Builds the immutable flow rule operations.
*
* @return flow rule operations
*/
public FlowRuleOperations build() {
return build(null);
}
/**
* Builds the immutable flow rule operations.
*
* @param cb the callback to call when this operation completes
* @return flow rule operations
*/
public FlowRuleOperations build(FlowRuleOperationsContext cb) {
closeStage();
return new FlowRuleOperations(listBuilder.build(), cb);
}
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.flow;
/**
* The context of a flow rule operations that will become the subject of
* the notification.
*
* Implementations of this class must be serializable.
*/
public interface FlowRuleOperationsContext {
// TODO we might also want to execute a method on behalf of the app
default void onSuccess(FlowRuleOperations ops){}
default void onError(FlowRuleOperations ops){}
}
......@@ -18,8 +18,6 @@ package org.onosproject.net.flow;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.provider.Provider;
import java.util.concurrent.Future;
/**
* Abstraction of a flow rule provider.
*/
......@@ -56,8 +54,7 @@ public interface FlowRuleProvider extends Provider {
* Installs a batch of flow rules. Each flowrule is associated to an
* operation which results in either addition, removal or modification.
* @param batch a batch of flow rules
* @return a future indicating the status of this execution
*/
Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch);
void executeBatch(FlowRuleBatchOperation batch);
}
......
......@@ -40,4 +40,13 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide
*/
void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries);
/**
* Indicates to the core that the requested batch operation has
* been completed.
*
* @param batchId the batch which was processed
* @param operation the resulting outcome of the operation
*/
void batchOperationCompleted(long batchId, CompletedBatchOperation operation);
}
......
......@@ -15,11 +15,11 @@
*/
package org.onosproject.net.flow;
import java.util.concurrent.Future;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import java.util.concurrent.Future;
/**
* Service for injecting flow rules into the environment and for obtaining
* information about flow rules already in the environment. This implements
......@@ -30,6 +30,11 @@ import org.onosproject.net.DeviceId;
public interface FlowRuleService {
/**
* The topic used for obtaining globally unique ids.
*/
static String FLOW_OP_TOPIC = "flow-ops-ids";
/**
* Returns the number of flow rules in the system.
*
* @return flow rule count
......@@ -96,11 +101,20 @@ public interface FlowRuleService {
* Applies a batch operation of FlowRules.
*
* @param batch batch operation to apply
* @return future indicating the state of the batch operation
* @return future indicating the state of the batch operation, due to the
* deprecation of this api the future will immediately return
*/
@Deprecated
Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch);
/**
* Applies a batch operation of FlowRules.
*
* @param ops batch operation to apply
*/
void apply(FlowRuleOperations ops);
/**
* Adds the specified flow rule listener.
*
* @param listener flow rule listener
......
......@@ -15,8 +15,6 @@
*/
package org.onosproject.net.flow;
import java.util.concurrent.Future;
import org.onosproject.net.DeviceId;
import org.onosproject.store.Store;
......@@ -54,6 +52,7 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
*
* @param rule the flow rule to add
*/
@Deprecated
void storeFlowRule(FlowRule rule);
/**
......@@ -61,10 +60,9 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
*
* @param batchOperation batch of flow rules.
* A batch can contain flow rules for a single device only.
* @return Future response indicating success/failure of the batch operation
* all the way down to the device.
*
*/
Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation batchOperation);
void storeBatch(FlowRuleBatchOperation batchOperation);
/**
* Invoked on the completion of a storeBatch operation.
......
......@@ -46,10 +46,10 @@ public class FlowRuleBatchOperationTest {
final LinkedList<FlowRuleBatchEntry> ops3 = new LinkedList<>();
ops3.add(entry3);
final FlowRuleBatchOperation operation1 = new FlowRuleBatchOperation(ops1);
final FlowRuleBatchOperation sameAsOperation1 = new FlowRuleBatchOperation(ops1);
final FlowRuleBatchOperation operation2 = new FlowRuleBatchOperation(ops2);
final FlowRuleBatchOperation operation3 = new FlowRuleBatchOperation(ops3);
final FlowRuleBatchOperation operation1 = new FlowRuleBatchOperation(ops1, null, 0);
final FlowRuleBatchOperation sameAsOperation1 = new FlowRuleBatchOperation(ops1, null, 0);
final FlowRuleBatchOperation operation2 = new FlowRuleBatchOperation(ops2, null, 0);
final FlowRuleBatchOperation operation3 = new FlowRuleBatchOperation(ops3, null, 0);
new EqualsTester()
.addEqualityGroup(operation1, sameAsOperation1)
......
......@@ -15,17 +15,18 @@
*/
package org.onosproject.net.flow;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.onosproject.net.intent.IntentTestsMocks;
import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.ADD;
import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.REMOVE;
/**
* Unit tests for the FlowRuleBatchRequest class.
......@@ -40,22 +41,19 @@ public class FlowRuleBatchRequestTest {
public void testConstruction() {
final FlowRule rule1 = new IntentTestsMocks.MockFlowRule(1);
final FlowRule rule2 = new IntentTestsMocks.MockFlowRule(2);
final List<FlowRuleBatchEntry> toAdd = new LinkedList<>();
toAdd.add(new FlowRuleBatchEntry(ADD, rule1));
final List<FlowRuleBatchEntry> toRemove = new LinkedList<>();
toRemove.add(new FlowRuleBatchEntry(REMOVE, rule2));
final Set<FlowRuleBatchEntry> batch = new HashSet<>();
batch.add(new FlowRuleBatchEntry(ADD, rule1));
batch.add(new FlowRuleBatchEntry(REMOVE, rule2));
final FlowRuleBatchRequest request =
new FlowRuleBatchRequest(1, toAdd, toRemove);
new FlowRuleBatchRequest(1, batch);
assertThat(request.toAdd(), hasSize(1));
assertThat(request.toAdd().get(0), is(rule1));
assertThat(request.toRemove(), hasSize(1));
assertThat(request.toRemove().get(0), is(rule2));
assertThat(request.batchId(), is(1));
assertThat(request.ops(), hasSize(2));
assertThat(request.batchId(), is(1L));
final FlowRuleBatchOperation op = request.asBatchOperation();
final FlowRuleBatchOperation op = request.asBatchOperation(rule1.deviceId());
assertThat(op.size(), is(2));
final List<FlowRuleBatchEntry> ops = op.getOperations();
......
......@@ -66,6 +66,11 @@ public class FlowRuleServiceAdapter implements FlowRuleService {
}
@Override
public void apply(FlowRuleOperations ops) {
}
@Override
public void addListener(FlowRuleListener listener) {
}
......
......@@ -1151,6 +1151,7 @@ public class IntentManager
*/
protected Future<CompletedBatchOperation> applyNextBatch(List<CompletedIntentUpdate> updates) {
//TODO test this. (also, maybe save this batch)
FlowRuleBatchOperation batch = createFlowRuleBatchOperation(updates);
if (batch.size() > 0) {
//FIXME apply batch might throw an exception
......@@ -1165,7 +1166,7 @@ public class IntentManager
}
private FlowRuleBatchOperation createFlowRuleBatchOperation(List<CompletedIntentUpdate> intentUpdates) {
FlowRuleBatchOperation batch = new FlowRuleBatchOperation(Collections.emptyList());
FlowRuleBatchOperation batch = new FlowRuleBatchOperation(Collections.emptyList(), null, 0);
for (CompletedIntentUpdate update : intentUpdates) {
FlowRuleBatchOperation currentBatch = update.currentBatch();
if (currentBatch != null) {
......
......@@ -98,6 +98,7 @@ public class LinkCollectionIntentInstaller
outputPorts.put(egressPoint.deviceId(), egressPoint.port());
}
//FIXME change to new api
FlowRuleBatchOperation batchOperation =
new FlowRuleBatchOperation(outputPorts
.keys()
......@@ -105,7 +106,7 @@ public class LinkCollectionIntentInstaller
.map(deviceId -> createBatchEntry(operation,
intent, deviceId,
outputPorts.get(deviceId)))
.collect(Collectors.toList()));
.collect(Collectors.toList()), null, 0);
return Collections.singletonList(batchOperation);
}
......
......@@ -181,6 +181,7 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
true);
rules.add(new FlowRuleBatchEntry(operation, rule));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
//FIXME change to new api
return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0));
}
}
......
......@@ -108,7 +108,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
intent.id().fingerprint()));
prev = link.dst();
}
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
//FIXME this should change to new api.
return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0));
}
@Override
......@@ -138,7 +139,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
intent.id().fingerprint()));
prev = link.dst();
}
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
// FIXME this should change to new api
return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0));
}
@Override
......
......@@ -31,7 +31,7 @@ public class TestEventDispatcher extends DefaultEventSinkRegistry
@Override
@SuppressWarnings("unchecked")
public void post(Event event) {
public synchronized void post(Event event) {
EventSink sink = getSink(event.getClass());
checkState(sink != null, "No sink for event %s", event);
sink.process(event);
......
......@@ -20,12 +20,15 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.core.IdGenerator;
import org.onosproject.core.Version;
import org.onosproject.event.impl.TestEventDispatcher;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.Device;
......@@ -36,7 +39,6 @@ import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.flow.BatchOperation;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.DefaultFlowRule;
......@@ -72,6 +74,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.*;
import static org.onosproject.net.flow.FlowRuleEvent.Type.*;
......@@ -97,12 +100,16 @@ public class FlowRuleManagerTest {
protected TestListener listener = new TestListener();
private ApplicationId appId;
@Before
public void setUp() {
mgr = new FlowRuleManager();
mgr.store = new SimpleFlowRuleStore();
mgr.eventDispatcher = new TestEventDispatcher();
mgr.deviceService = new TestDeviceService();
mgr.coreService = new TestCoreService();
mgr.operationsService = MoreExecutors.newDirectExecutorService();
mgr.deviceInstallers = MoreExecutors.newDirectExecutorService();
service = mgr;
registry = mgr;
......@@ -246,14 +253,23 @@ public class FlowRuleManagerTest {
@Test
public void flowRemoved() {
FlowRule f1 = addFlowRule(1);
FlowRule f2 = addFlowRule(2);
StoredFlowEntry fe1 = new DefaultFlowEntry(f1);
FlowEntry fe2 = new DefaultFlowEntry(f2);
providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
service.removeFlowRules(f1);
fe1.setState(FlowEntryState.REMOVED);
providerService.flowRemoved(fe1);
validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED,
RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED);
......@@ -263,11 +279,13 @@ public class FlowRuleManagerTest {
FlowRule f3 = flowRule(3, 3);
FlowEntry fe3 = new DefaultFlowEntry(f3);
service.applyFlowRules(f3);
providerService.pushFlowMetrics(DID, Collections.singletonList(fe3));
validateEvents(RULE_ADD_REQUESTED, RULE_ADDED);
providerService.flowRemoved(fe3);
validateEvents();
}
@Test
......@@ -281,7 +299,6 @@ public class FlowRuleManagerTest {
FlowEntry fe1 = new DefaultFlowEntry(f1);
FlowEntry fe2 = new DefaultFlowEntry(f2);
//FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
//FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
......@@ -388,7 +405,7 @@ public class FlowRuleManagerTest {
FlowRuleBatchEntry.FlowRuleOperation.ADD, f2);
FlowRuleBatchOperation fbo = new FlowRuleBatchOperation(
Lists.newArrayList(fbe1, fbe2));
Lists.newArrayList(fbe1, fbe2), null, 0);
Future<CompletedBatchOperation> future = mgr.applyBatch(fbo);
assertTrue("Entries in wrong state",
validateState(ImmutableMap.of(
......@@ -406,53 +423,6 @@ public class FlowRuleManagerTest {
}
@Test
public void cancelBatch() {
FlowRule f1 = flowRule(1, 1);
FlowRule f2 = flowRule(2, 2);
mgr.applyFlowRules(f1);
assertTrue("Entries in wrong state",
validateState(ImmutableMap.of(
f1, FlowEntryState.PENDING_ADD)));
FlowEntry fe1 = new DefaultFlowEntry(f1);
providerService.pushFlowMetrics(DID, Collections.<FlowEntry>singletonList(fe1));
assertTrue("Entries in wrong state",
validateState(ImmutableMap.of(
f1, FlowEntryState.ADDED)));
FlowRuleBatchEntry fbe1 = new FlowRuleBatchEntry(
FlowRuleBatchEntry.FlowRuleOperation.REMOVE, f1);
FlowRuleBatchEntry fbe2 = new FlowRuleBatchEntry(
FlowRuleBatchEntry.FlowRuleOperation.ADD, f2);
FlowRuleBatchOperation fbo = new FlowRuleBatchOperation(
Lists.newArrayList(fbe1, fbe2));
Future<CompletedBatchOperation> future = mgr.applyBatch(fbo);
future.cancel(true);
assertTrue(flowCount() == 2);
/*
* Rule f1 should be re-added to the list and therefore be in a pending add
* state.
*/
assertTrue("Entries in wrong state",
validateState(ImmutableMap.of(
f2, FlowEntryState.PENDING_REMOVE,
f1, FlowEntryState.PENDING_ADD)));
}
private static class TestListener implements FlowRuleListener {
final List<FlowRuleEvent> events = new ArrayList<>();
......@@ -528,9 +498,8 @@ public class FlowRuleManagerTest {
}
@Override
public ListenableFuture<CompletedBatchOperation> executeBatch(
BatchOperation<FlowRuleBatchEntry> batch) {
return new TestInstallationFuture();
public void executeBatch(FlowRuleBatchOperation batch) {
// TODO: need to call batchOperationComplete
}
private class TestInstallationFuture
......@@ -554,14 +523,14 @@ public class FlowRuleManagerTest {
@Override
public CompletedBatchOperation get()
throws InterruptedException, ExecutionException {
return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet());
return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null);
}
@Override
public CompletedBatchOperation get(long timeout, TimeUnit unit)
throws InterruptedException,
ExecutionException, TimeoutException {
return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet());
return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null);
}
@Override
......@@ -644,4 +613,37 @@ public class FlowRuleManagerTest {
}
}
private class TestCoreService implements CoreService {
@Override
public Version version() {
return null;
}
@Override
public Set<ApplicationId> getAppIds() {
return null;
}
@Override
public ApplicationId getAppId(Short id) {
return null;
}
@Override
public ApplicationId registerApplication(String identifier) {
return null;
}
@Override
public IdGenerator getIdGenerator(String topic) {
return new IdGenerator() {
private AtomicLong counter = new AtomicLong(0);
@Override
public long getNewId() {
return counter.getAndIncrement();
}
};
}
}
}
......
......@@ -201,7 +201,7 @@ public class IntentManagerTest {
FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0));
}
@Override
......@@ -209,7 +209,7 @@ public class IntentManagerTest {
FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0));
}
@Override
......@@ -219,7 +219,7 @@ public class IntentManagerTest {
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr2));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0));
}
}
......
......@@ -27,6 +27,7 @@ import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchOperation;
import org.onosproject.net.flow.FlowRuleListener;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleService;
import com.google.common.collect.ImmutableSet;
......@@ -45,11 +46,11 @@ public class MockFlowRuleService implements FlowRuleService {
public void setFuture(boolean success, long intentId) {
if (success) {
future = Futures.immediateFuture(new CompletedBatchOperation(true, Collections.emptySet()));
future = Futures.immediateFuture(new CompletedBatchOperation(true, Collections.emptySet(), null));
} else {
final Set<Long> failedIds = ImmutableSet.of(intentId);
future = Futures.immediateFuture(
new CompletedBatchOperation(false, flows, failedIds));
new CompletedBatchOperation(false, flows, failedIds, null));
}
}
......@@ -74,6 +75,11 @@ public class MockFlowRuleService implements FlowRuleService {
}
@Override
public void apply(FlowRuleOperations ops) {
}
@Override
public int getFlowRuleCount() {
return flows.size();
}
......
......@@ -34,4 +34,7 @@ public final class FlowStoreMessageSubjects {
public static final MessageSubject REMOVE_FLOW_ENTRY
= new MessageSubject("peer-forward-remove-flow-entry");
public static final MessageSubject REMOTE_APPLY_COMPLETED
= new MessageSubject("peer-apply-completed");
}
......
......@@ -59,15 +59,17 @@ import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DefaultPortDescription;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchEvent;
import org.onosproject.net.flow.FlowRuleBatchOperation;
import org.onosproject.net.flow.FlowRuleBatchRequest;
import org.onosproject.net.flow.StoredFlowEntry;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
......@@ -162,6 +164,7 @@ public final class KryoNamespaces {
.register(Collections.emptySet().getClass())
.register(Optional.class)
.register(Collections.emptyList().getClass())
.register(Collections.unmodifiableSet(Collections.emptySet()).getClass())
.build();
/**
......@@ -255,6 +258,9 @@ public final class KryoNamespaces {
L3ModificationInstruction.L3SubType.class,
L3ModificationInstruction.ModIPInstruction.class,
RoleInfo.class,
FlowRuleBatchEvent.class,
FlowRuleBatchEvent.Type.class,
FlowRuleBatchRequest.class,
FlowRuleBatchOperation.class,
CompletedBatchOperation.class,
FlowRuleBatchEntry.class,
......
......@@ -21,13 +21,13 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.FluentIterable;
import com.google.common.util.concurrent.Futures;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.SettableFuture;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.NewConcurrentHashMap;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.DefaultFlowEntry;
......@@ -46,7 +46,6 @@ import org.onosproject.net.flow.FlowRuleStore;
import org.onosproject.net.flow.FlowRuleStoreDelegate;
import org.onosproject.net.flow.StoredFlowEntry;
import org.onosproject.store.AbstractStore;
import org.onlab.util.NewConcurrentHashMap;
import org.slf4j.Logger;
import java.util.ArrayList;
......@@ -56,7 +55,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
......@@ -261,13 +259,14 @@ public class SimpleFlowRuleStore
}
@Override
public Future<CompletedBatchOperation> storeBatch(
FlowRuleBatchOperation batchOperation) {
public void storeBatch(
FlowRuleBatchOperation operation) {
List<FlowRuleBatchEntry> toAdd = new ArrayList<>();
List<FlowRuleBatchEntry> toRemove = new ArrayList<>();
for (FlowRuleBatchEntry entry : batchOperation.getOperations()) {
final FlowRule flowRule = entry.target();
if (entry.operator().equals(FlowRuleOperation.ADD)) {
for (FlowRuleBatchEntry entry : operation.getOperations()) {
final FlowRule flowRule = entry.getTarget();
if (entry.getOperator().equals(FlowRuleOperation.ADD)) {
if (!getFlowEntries(flowRule.deviceId(), flowRule.id()).contains(flowRule)) {
storeFlowRule(flowRule);
toAdd.add(entry);
......@@ -283,21 +282,27 @@ public class SimpleFlowRuleStore
}
if (toAdd.isEmpty() && toRemove.isEmpty()) {
return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowRule>emptySet()));
notifyDelegate(FlowRuleBatchEvent.completed(
new FlowRuleBatchRequest(operation.id(), Collections.emptySet()),
new CompletedBatchOperation(true, Collections.emptySet(),
operation.deviceId())));
return;
}
SettableFuture<CompletedBatchOperation> r = SettableFuture.create();
final int batchId = localBatchIdGen.incrementAndGet();
pendingFutures.put(batchId, r);
notifyDelegate(FlowRuleBatchEvent.requested(new FlowRuleBatchRequest(batchId, toAdd, toRemove)));
return r;
toAdd.addAll(toRemove);
notifyDelegate(FlowRuleBatchEvent.requested(
new FlowRuleBatchRequest(batchId, Sets.newHashSet(toAdd)), operation.deviceId()));
}
@Override
public void batchOperationComplete(FlowRuleBatchEvent event) {
final Integer batchId = event.subject().batchId();
final Long batchId = event.subject().batchId();
SettableFuture<CompletedBatchOperation> future
= pendingFutures.getIfPresent(batchId);
if (future != null) {
......
......@@ -116,7 +116,7 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
@Activate
public void activate(ComponentContext context) {
providerService = providerRegistry.register(this);
if (modified(context)) {
if (!modified(context)) {
deviceBuilder.submit(new DeviceCreator(true));
}
log.info("Started");
......@@ -173,6 +173,9 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
chgd |= true;
}
log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts);
if (chgd) {
deviceBuilder.submit(new DeviceCreator(true));
}
return chgd;
}
......
......@@ -15,9 +15,7 @@
*/
package org.onosproject.provider.nil.flow.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.Futures;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -29,12 +27,12 @@ import org.jboss.netty.util.TimerTask;
import org.onlab.util.Timer;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.BatchOperation;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchOperation;
import org.onosproject.net.flow.FlowRuleProvider;
import org.onosproject.net.flow.FlowRuleProviderRegistry;
import org.onosproject.net.flow.FlowRuleProviderService;
......@@ -43,7 +41,9 @@ import org.onosproject.net.provider.ProviderId;
import org.slf4j.Logger;
import java.util.Collections;
import java.util.concurrent.Future;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -59,7 +59,7 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleProviderRegistry providerRegistry;
private Multimap<DeviceId, FlowEntry> flowTable = HashMultimap.create();
private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>();
private FlowRuleProviderService providerService;
......@@ -88,18 +88,10 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
@Override
public void applyFlowRule(FlowRule... flowRules) {
for (int i = 0; i < flowRules.length; i++) {
flowTable.put(flowRules[i].deviceId(), new DefaultFlowEntry(flowRules[i]));
}
}
public void applyFlowRule(FlowRule... flowRules) {}
@Override
public void removeFlowRule(FlowRule... flowRules) {
for (int i = 0; i < flowRules.length; i++) {
flowTable.remove(flowRules[i].deviceId(), flowRules[i]);
}
}
public void removeFlowRule(FlowRule... flowRules) {}
@Override
public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
......@@ -107,26 +99,32 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
@Override
public Future<CompletedBatchOperation> executeBatch(
BatchOperation<FlowRuleBatchEntry> batch) {
public void executeBatch(
FlowRuleBatchOperation batch) {
Set<FlowEntry> flowRules = flowTable.getOrDefault(batch.deviceId(), Sets.newConcurrentHashSet());
for (FlowRuleBatchEntry fbe : batch.getOperations()) {
switch (fbe.operator()) {
case ADD:
applyFlowRule(fbe.target());
flowRules.add(new DefaultFlowEntry(fbe.target()));
break;
case REMOVE:
removeFlowRule(fbe.target());
flowRules.remove(new DefaultFlowEntry(fbe.target()));
break;
case MODIFY:
removeFlowRule(fbe.target());
applyFlowRule(fbe.target());
FlowEntry entry = new DefaultFlowEntry(fbe.target());
flowRules.remove(entry);
flowRules.add(entry);
break;
default:
log.error("Unknown flow operation: {}", fbe);
}
}
return Futures.immediateFuture(
new CompletedBatchOperation(true, Collections.emptySet()));
flowTable.put(batch.deviceId(), flowRules);
providerService.batchOperationCompleted(batch.id(),
new CompletedBatchOperation(
true,
Collections.emptySet(),
batch.deviceId()));
}
private class StatisticTask implements TimerTask {
......@@ -134,10 +132,11 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr
@Override
public void run(Timeout to) throws Exception {
for (DeviceId devId : flowTable.keySet()) {
providerService.pushFlowMetrics(devId, flowTable.get(devId));
providerService.pushFlowMetrics(devId,
flowTable.getOrDefault(devId, Collections.emptySet()));
}
timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS);
}
}
}
......
......@@ -35,6 +35,7 @@ import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.openflow.controller.Dpid;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFInstructionType;
......@@ -74,13 +75,16 @@ public class FlowEntryBuilder {
private final OFFlowStatsEntry stat;
private final OFFlowRemoved removed;
private final OFFlowMod flowMod;
private final Match match;
private final List<OFAction> actions;
private final Dpid dpid;
private final boolean addedRule;
public enum FlowType { STAT, REMOVED, MOD }
private final FlowType type;
public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) {
......@@ -89,7 +93,8 @@ public class FlowEntryBuilder {
this.actions = getActions(entry);
this.dpid = dpid;
this.removed = null;
this.addedRule = true;
this.flowMod = null;
this.type = FlowType.STAT;
}
public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) {
......@@ -99,26 +104,48 @@ public class FlowEntryBuilder {
this.dpid = dpid;
this.actions = null;
this.stat = null;
this.addedRule = false;
this.flowMod = null;
this.type = FlowType.REMOVED;
}
public FlowEntry build() {
if (addedRule) {
FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), buildTreatment(), stat.getPriority(),
stat.getCookie().getValue(), stat.getIdleTimeout(), false);
return new DefaultFlowEntry(rule, FlowEntryState.ADDED,
stat.getDurationSec(), stat.getPacketCount().getValue(),
stat.getByteCount().getValue());
public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) {
this.match = fm.getMatch();
this.dpid = dpid;
this.actions = fm.getActions();
this.type = FlowType.MOD;
this.flowMod = fm;
this.stat = null;
this.removed = null;
}
} else {
FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), null, removed.getPriority(),
removed.getCookie().getValue(), removed.getIdleTimeout(), false);
return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(),
removed.getPacketCount().getValue(), removed.getByteCount().getValue());
public FlowEntry build(FlowEntryState... state) {
FlowRule rule;
switch (this.type) {
case STAT:
rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), buildTreatment(), stat.getPriority(),
stat.getCookie().getValue(), stat.getIdleTimeout(), false);
return new DefaultFlowEntry(rule, FlowEntryState.ADDED,
stat.getDurationSec(), stat.getPacketCount().getValue(),
stat.getByteCount().getValue());
case REMOVED:
rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), null, removed.getPriority(),
removed.getCookie().getValue(), removed.getIdleTimeout(), false);
return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(),
removed.getPacketCount().getValue(), removed.getByteCount().getValue());
case MOD:
FlowEntryState flowState = state.length > 0 ? state[0] : FlowEntryState.FAILED;
rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), buildTreatment(), flowMod.getPriority(),
flowMod.getCookie().getValue(), flowMod.getIdleTimeout(), false);
return new DefaultFlowEntry(rule, flowState, 0, 0, 0);
default:
log.error("Unknown flow type : {}", this.type);
return null;
}
}
private List<OFAction> getActions(OFFlowStatsEntry entry) {
......
......@@ -2,7 +2,7 @@
# Instance-specific configurations, in this case, the number of
# devices per node.
#
devConfigs = 192.168.56.30:5,192.168.56.40:7
devConfigs = 192.168.97.132:5,192.168.97.131:5
#
# Number of ports per device. This is global to all devices
......
......@@ -9,4 +9,4 @@
#
# Set order of islands to chain together, in a line.
#
neighbors = 192.168.56.20,192.168.56.30,192.168.56.40
neighbors = 192.168.97.132,192.168.97.131
......