alshabib

WIP: Initial implementation of filterObjectives using driver subsystem.

Incomplete implementation

Change-Id: I3745d481027659d4ca44b72139e5461c02e8c3ef
......@@ -26,4 +26,9 @@ public class AbstractBehaviour implements Behaviour {
public void setData(DriverData data) {
this.data = data;
}
@Override
public DriverData data() {
return data;
}
}
......
......@@ -29,4 +29,11 @@ public interface Behaviour {
*/
void setData(DriverData data);
/**
* Obtains the driver data.
*
* @return driver data
*/
DriverData data();
}
......
......@@ -32,7 +32,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public final class DefaultFilteringObjective implements FilteringObjective {
private final Criterion key;
private final Type type;
private final boolean permanent;
private final int timeout;
private final ApplicationId appId;
......@@ -41,10 +41,10 @@ public final class DefaultFilteringObjective implements FilteringObjective {
private final int id;
private final Operation op;
private DefaultFilteringObjective(Criterion key, boolean permanent, int timeout,
private DefaultFilteringObjective(Type type, boolean permanent, int timeout,
ApplicationId appId, int priority,
List<Criterion> conditions, Operation op) {
this.key = key;
this.type = type;
this.permanent = permanent;
this.timeout = timeout;
this.appId = appId;
......@@ -52,14 +52,13 @@ public final class DefaultFilteringObjective implements FilteringObjective {
this.conditions = conditions;
this.op = op;
this.id = Objects.hash(key, conditions, permanent,
this.id = Objects.hash(type, conditions, permanent,
timeout, appId, priority);
}
@Override
public Criterion key() {
return key;
public Type type() {
return this.type;
}
@Override
......@@ -111,7 +110,7 @@ public final class DefaultFilteringObjective implements FilteringObjective {
private final ImmutableList.Builder<Criterion> listBuilder
= ImmutableList.builder();
private Criterion key;
private Type type;
private boolean permanent = DEFAULT_PERMANENT;
private int timeout = DEFAULT_TIMEOUT;
private ApplicationId appId;
......@@ -124,8 +123,14 @@ public final class DefaultFilteringObjective implements FilteringObjective {
}
@Override
public Builder withKey(Criterion criterion) {
key = criterion;
public Builder permit() {
this.type = Type.PERMIT;
return this;
}
@Override
public Builder deny() {
this.type = Type.DENY;
return this;
}
......@@ -157,11 +162,11 @@ public final class DefaultFilteringObjective implements FilteringObjective {
@Override
public FilteringObjective add() {
List<Criterion> conditions = listBuilder.build();
checkNotNull(key, "Must have a key.");
checkNotNull(type, "Must have a type.");
checkArgument(!conditions.isEmpty(), "Must have at least one condition.");
checkNotNull(appId, "Must supply an application id");
return new DefaultFilteringObjective(key, permanent, timeout,
return new DefaultFilteringObjective(type, permanent, timeout,
appId, priority, conditions,
Operation.ADD);
......@@ -170,11 +175,11 @@ public final class DefaultFilteringObjective implements FilteringObjective {
@Override
public FilteringObjective remove() {
List<Criterion> conditions = listBuilder.build();
checkNotNull(key, "Must have a key.");
checkNotNull(type, "Must have a type.");
checkArgument(!conditions.isEmpty(), "Must have at least one condition.");
checkNotNull(appId, "Must supply an application id");
return new DefaultFilteringObjective(key, permanent, timeout,
return new DefaultFilteringObjective(type, permanent, timeout,
appId, priority, conditions,
Operation.REMOVE);
......
......@@ -15,6 +15,7 @@
*/
package org.onosproject.net.flowobjective;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.flow.criteria.Criterion;
import java.util.Collection;
......@@ -27,12 +28,23 @@ import java.util.Collection;
*/
public interface FilteringObjective extends Objective {
enum Type {
/**
* Enables the filtering condition.
*/
PERMIT,
/**
* Disables the filtering condition.
*/
DENY
}
/**
* Represents filtering key used in this filter.
*
* @return a criterion
* Obtain this filtering type.
* @return the type
*/
Criterion key();
public Type type();
/**
* The set of conditions the filter must provision at the device.
......@@ -55,12 +67,23 @@ public interface FilteringObjective extends Objective {
public Builder addCondition(Criterion criterion);
/**
* Add a filtering key.
*
* @param criterion new criterion
* @return a filtering builder.
* Permit this filtering condition set.
* @return a filtering builder
*/
public Builder permit();
/**
* Deny this filtering condition set.
* @return a filtering builder
*/
public Builder deny();
/**
* Assigns an application id.
* @param appId an application id
* @return a filtering builder
*/
public Builder withKey(Criterion criterion);
public Builder fromApp(ApplicationId appId);
/**
* Builds the filtering objective that will be added.
......
......@@ -15,7 +15,9 @@
*/
package org.onosproject.net.flowobjective.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Futures;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -43,11 +45,13 @@ import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.group.GroupService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Future;
......@@ -87,12 +91,16 @@ public class FlowObjectiveManager implements FlowObjectiveService {
private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap();
private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
private final PipelinerContext context = new InnerPipelineContext();
private final MastershipListener mastershipListener = new InnerMastershipListener();
private final DeviceListener deviceListener = new InnerDeviceListener();
protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
private final Map<DeviceId, Collection<Objective>> pendingObjectives =
Maps.newConcurrentMap();
private NodeId localNode;
@Activate
......@@ -114,26 +122,51 @@ public class FlowObjectiveManager implements FlowObjectiveService {
@Override
public Future<Boolean> filter(DeviceId deviceId,
Collection<FilteringObjective> filteringObjectives) {
return getDevicePipeliner(deviceId).filter(filteringObjectives);
if (deviceService.isAvailable(deviceId)) {
return getDevicePipeliner(deviceId).filter(filteringObjectives);
} else {
filteringObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
}
return Futures.immediateFuture(true);
}
@Override
public Future<Boolean> forward(DeviceId deviceId,
Collection<ForwardingObjective> forwardingObjectives) {
return getDevicePipeliner(deviceId).forward(forwardingObjectives);
if (deviceService.isAvailable(deviceId)) {
return getDevicePipeliner(deviceId).forward(forwardingObjectives);
} else {
forwardingObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
}
return Futures.immediateFuture(true);
}
@Override
public Future<Boolean> next(DeviceId deviceId,
Collection<NextObjective> nextObjectives) {
return getDevicePipeliner(deviceId).next(nextObjectives);
if (deviceService.isAvailable(deviceId)) {
return getDevicePipeliner(deviceId).next(nextObjectives);
} else {
nextObjectives.forEach(obj -> updatePendingMap(deviceId, obj));
}
return Futures.immediateFuture(true);
}
// Retrieves the device handler pipeline behaviour from the cache.
private void updatePendingMap(DeviceId deviceId, Objective pending) {
if (pendingObjectives.putIfAbsent(deviceId, Lists.newArrayList(pending)) != null) {
Collection<Objective> objectives = pendingObjectives.get(deviceId);
objectives.add(pending);
}
}
// Retrieves the device pipeline behaviour from the cache.
private Pipeliner getDevicePipeliner(DeviceId deviceId) {
DriverHandler handler = driverHandlers.get(deviceId);
checkState(handler != null, NOT_INITIALIZED);
return handler != null ? handler.behaviour(Pipeliner.class) : null;
Pipeliner pipeliner = pipeliners.get(deviceId);
checkState(pipeliner != null, NOT_INITIALIZED);
return pipeliner;
}
......@@ -164,6 +197,7 @@ public class FlowObjectiveManager implements FlowObjectiveService {
case DEVICE_AVAILABILITY_CHANGED:
if (deviceService.isAvailable(event.subject().id())) {
setupPipelineHandler(event.subject().id());
processPendingObjectives(event.subject().id());
}
break;
case DEVICE_UPDATED:
......@@ -182,6 +216,21 @@ public class FlowObjectiveManager implements FlowObjectiveService {
break;
}
}
private void processPendingObjectives(DeviceId deviceId) {
pendingObjectives.get(deviceId).forEach(obj -> {
if (obj instanceof NextObjective) {
getDevicePipeliner(deviceId)
.next(Collections.singletonList((NextObjective) obj));
} else if (obj instanceof ForwardingObjective) {
getDevicePipeliner(deviceId)
.forward(Collections.singletonList((ForwardingObjective) obj));
} else {
getDevicePipeliner(deviceId)
.filter(Collections.singletonList((FilteringObjective) obj));
}
});
}
}
private void setupPipelineHandler(DeviceId deviceId) {
......@@ -205,7 +254,9 @@ public class FlowObjectiveManager implements FlowObjectiveService {
}
// Always (re)initialize the pipeline behaviour
handler.behaviour(Pipeliner.class).init(deviceId, context);
Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
pipeliner.init(deviceId, context);
pipeliners.putIfAbsent(deviceId, pipeliner);
log.info("Driver {} bound to device {}", handler.driver().name(), deviceId);
}
}
......
......@@ -15,6 +15,8 @@
*/
package org.onosproject.driver.pipeline;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.SettableFuture;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
......@@ -34,9 +36,12 @@ 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.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.Objective;
import org.slf4j.Logger;
import java.util.Collection;
......@@ -79,7 +84,54 @@ public class OVSCorsaPipeline extends AbstractBehaviour implements Pipeliner {
@Override
public Future<Boolean> filter(Collection<FilteringObjective> filteringObjectives) {
return null;
Collection<Future<Boolean>> results =
Sets.newHashSet();
filteringObjectives.stream()
.filter(obj -> obj.type() == FilteringObjective.Type.PERMIT)
.forEach(obj -> obj.conditions()
.forEach(condition ->
results.add(processCondition(condition,
obj.op() == Objective.Operation.ADD,
obj.appId()))
));
//TODO: return something more helpful/sensible in the future (no pun intended)
return results.iterator().next();
}
private Future<Boolean> processCondition(Criterion c, boolean install,
ApplicationId applicationId) {
SettableFuture<Boolean> result = SettableFuture.create();
if (c.type() == Criterion.Type.ETH_DST) {
Criteria.EthCriterion e = (Criteria.EthCriterion) c;
log.debug("adding rule for MAC: {}", e.mac());
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
selector.matchEthDst(e.mac());
treatment.transition(FlowRule.Type.VLAN_MPLS);
FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
treatment.build(),
CONTROLLER_PRIORITY, applicationId, 0,
true, FlowRule.Type.FIRST);
FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
ops = install ? ops.add(rule) : ops.remove(rule);
flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
@Override
public void onSuccess(FlowRuleOperations ops) {
result.set(true);
log.info("Provisioned default table for bgp router");
}
@Override
public void onError(FlowRuleOperations ops) {
result.set(false);
log.info("Failed to provision default table for bgp router");
}
}));
}
return result;
}
@Override
......