Xin Jin
Committed by Brian O'Connor

Adding experimental Flow Objective composition

Change-Id: I35e4414845ad5034145157ab83f933e40f75a1d9
/*
* 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.cli.net;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.flowobjective.FlowObjectiveService;
/**
* Manages FlowObjectiveComposition policy.
*/
@Command(scope = "onos", name = "policy",
description = "Manages FlowObjectiveComposition policy")
public class FlowObjectiveCompositionCommand extends AbstractShellCommand {
@Argument(index = 0, name = "command",
description = "Command name (install)",
required = true, multiValued = false)
String command = null;
@Argument(index = 1, name = "names", description = "policy string",
required = true, multiValued = true)
String[] policies = null;
@Override
protected void execute() {
FlowObjectiveService service = get(FlowObjectiveService.class);
service.initPolicy(policies[0]);
print("Policy %s installed", policies[0]);
}
}
......@@ -30,6 +30,10 @@
</command>
<command>
<action class="org.onosproject.cli.net.FlowObjectiveCompositionCommand"/>
</command>
<command>
<action class="org.onosproject.cli.app.ApplicationsListCommand"/>
</command>
......
......@@ -56,4 +56,10 @@ public interface FlowObjectiveService {
*/
int allocateNextId();
/**
* Installs the filtering rules onto the specified device.
*
* @param policy policy expression
*/
void initPolicy(String policy);
}
......
......@@ -218,6 +218,9 @@ public class FlowObjectiveManager implements FlowObjectiveService {
return flowObjectiveStore.allocateNextId();
}
@Override
public void initPolicy(String policy) {}
private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) {
if (fwd.nextId() != null &&
flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
......
/*
* 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.flowobjective.impl.composition;
import org.onosproject.net.flowobjective.FilteringObjective;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Provides a table to store Fitler.
*/
public class FilterTable {
protected Map<Integer, FilteringObjective> filterMap;
public FilterTable() {
this.filterMap = new HashMap<>();
}
public List<FilteringObjective> updateFilter(FilteringObjective filteringObjective) {
List<FilteringObjective> updates = new ArrayList<>();
switch (filteringObjective.op()) {
case ADD:
this.filterMap.put(filteringObjective.id(), filteringObjective);
updates.add(filteringObjective);
break;
case REMOVE:
this.filterMap.remove(filteringObjective.id());
updates.add(filteringObjective);
break;
default:
break;
}
return updates;
}
public List<FilteringObjective> updateFilter(List<FilteringObjective> filteringObjectives) {
List<FilteringObjective> updates = new ArrayList<>();
for (FilteringObjective filteringObjective : filteringObjectives) {
updates.addAll(this.updateFilter(filteringObjective));
}
return updates;
}
}
/*
* 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.flowobjective.impl.composition;
import com.google.common.collect.Maps;
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;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.cluster.ClusterService;
import org.onosproject.core.Permission;
import org.onosproject.mastership.MastershipEvent;
import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DefaultDriverProviderService;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.FlowObjectiveStore;
import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.flowobjective.ObjectiveEvent;
import org.onosproject.net.group.GroupService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.security.AppGuard.checkPermission;
/**
* Provides implementation of the flow objective programming service with composition feature.
*
* Note: This is an experimental, alternative implementation of the FlowObjectiveManager
* that supports composition. It can be enabled by setting the enable flag below to true,
* and you should also add "enabled = false" to the FlowObjectiveManager.
*
* The implementation relies a FlowObjectiveCompositionTree that is not yet distributed,
* so it will not have high availability and may break if device mastership changes.
* Therefore, it is safest to use this component in a single instance scenario.
* This comment will be removed when a distributed implementation is available.
*/
@Component(immediate = true, enabled = false)
@Service
public class FlowObjectiveCompositionManager implements FlowObjectiveService {
public enum PolicyOperator {
Parallel,
Sequential,
Override,
Application
}
public static final int INSTALL_RETRY_ATTEMPTS = 5;
public static final long INSTALL_RETRY_INTERVAL = 1000; // ms
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
// Note: The following dependencies are added on behalf of the pipeline
// driver behaviours to assure these services are available for their
// initialization.
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected GroupService groupService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveStore flowObjectiveStore;
// Note: This must remain an optional dependency to allow re-install of default drivers.
// Note: For now disabled until we can move to OPTIONAL_UNARY dependency
// @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC)
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DefaultDriverProviderService defaultDriverService;
private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate();
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 Map<Integer, Set<PendingNext>> pendingForwards = Maps.newConcurrentMap();
private ExecutorService executorService;
private String policy;
private Map<DeviceId, FlowObjectiveCompositionTree> deviceCompositionTreeMap;
@Activate
protected void activate() {
executorService = newFixedThreadPool(4, groupedThreads("onos/objective-installer", "%d"));
flowObjectiveStore.setDelegate(delegate);
mastershipService.addListener(mastershipListener);
deviceService.addListener(deviceListener);
deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id()));
deviceCompositionTreeMap = Maps.newConcurrentMap();
log.info("Started");
}
@Deactivate
protected void deactivate() {
flowObjectiveStore.unsetDelegate(delegate);
mastershipService.removeListener(mastershipListener);
deviceService.removeListener(deviceListener);
executorService.shutdown();
pipeliners.clear();
driverHandlers.clear();
deviceCompositionTreeMap.clear();
log.info("Stopped");
}
/**
* Task that passes the flow objective down to the driver. The task will
* make a few attempts to find the appropriate driver, then eventually give
* up and report an error if no suitable driver could be found.
*/
private class ObjectiveInstaller implements Runnable {
private final DeviceId deviceId;
private final Objective objective;
private final int numAttempts;
public ObjectiveInstaller(DeviceId deviceId, Objective objective) {
this(deviceId, objective, 1);
}
public ObjectiveInstaller(DeviceId deviceId, Objective objective, int attemps) {
this.deviceId = checkNotNull(deviceId);
this.objective = checkNotNull(objective);
this.numAttempts = checkNotNull(attemps);
}
@Override
public void run() {
try {
Pipeliner pipeliner = getDevicePipeliner(deviceId);
if (pipeliner != null) {
if (objective instanceof NextObjective) {
pipeliner.next((NextObjective) objective);
} else if (objective instanceof ForwardingObjective) {
pipeliner.forward((ForwardingObjective) objective);
} else {
pipeliner.filter((FilteringObjective) objective);
}
} else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
Thread.sleep(INSTALL_RETRY_INTERVAL);
executorService.submit(new ObjectiveInstaller(deviceId, objective, numAttempts + 1));
} else {
// Otherwise we've tried a few times and failed, report an
// error back to the user.
objective.context().ifPresent(
c -> c.onError(objective, ObjectiveError.DEVICEMISSING));
}
} catch (Exception e) {
log.warn("Exception while installing flow objective", e);
}
}
}
@Override
public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
checkPermission(Permission.FLOWRULE_WRITE);
List<FilteringObjective> filteringObjectives
= this.deviceCompositionTreeMap.get(deviceId).updateFilter(filteringObjective);
for (FilteringObjective tmp : filteringObjectives) {
executorService.submit(new ObjectiveInstaller(deviceId, tmp));
}
}
@Override
public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
checkPermission(Permission.FLOWRULE_WRITE);
if (queueObjective(deviceId, forwardingObjective)) {
return;
}
List<ForwardingObjective> forwardingObjectives
= this.deviceCompositionTreeMap.get(deviceId).updateForward(forwardingObjective);
for (ForwardingObjective tmp : forwardingObjectives) {
executorService.submit(new ObjectiveInstaller(deviceId, tmp));
}
}
@Override
public void next(DeviceId deviceId, NextObjective nextObjective) {
checkPermission(Permission.FLOWRULE_WRITE);
List<NextObjective> nextObjectives = this.deviceCompositionTreeMap.get(deviceId).updateNext(nextObjective);
for (NextObjective tmp : nextObjectives) {
executorService.submit(new ObjectiveInstaller(deviceId, tmp));
}
}
@Override
public int allocateNextId() {
checkPermission(Permission.FLOWRULE_WRITE);
return flowObjectiveStore.allocateNextId();
}
private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) {
if (fwd.nextId() != null &&
flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
log.trace("Queuing forwarding objective for nextId {}", fwd.nextId());
if (pendingForwards.putIfAbsent(fwd.nextId(),
Sets.newHashSet(new PendingNext(deviceId, fwd))) != null) {
Set<PendingNext> pending = pendingForwards.get(fwd.nextId());
pending.add(new PendingNext(deviceId, fwd));
}
return true;
}
return false;
}
@Override
public void initPolicy(String policy) {
this.policy = policy;
deviceService.getDevices().forEach(device ->
this.deviceCompositionTreeMap.put(device.id(), FlowObjectiveCompositionUtil.parsePolicyString(policy)));
log.info("Initialize policy {}", policy);
}
// Retrieves the device pipeline behaviour from the cache.
private Pipeliner getDevicePipeliner(DeviceId deviceId) {
Pipeliner pipeliner = pipeliners.get(deviceId);
return pipeliner;
}
private void setupPipelineHandler(DeviceId deviceId) {
if (defaultDriverService == null) {
// We're not ready to go to work yet.
return;
}
// Attempt to lookup the handler in the cache
DriverHandler handler = driverHandlers.get(deviceId);
if (handler == null) {
try {
// Otherwise create it and if it has pipeline behaviour, cache it
handler = driverService.createHandler(deviceId);
if (!handler.driver().hasBehaviour(Pipeliner.class)) {
log.warn("Pipeline behaviour not supported for device {}",
deviceId);
return;
}
} catch (ItemNotFoundException e) {
log.warn("No applicable driver for device {}", deviceId);
return;
}
driverHandlers.put(deviceId, handler);
}
// Always (re)initialize the pipeline behaviour
log.info("Driver {} bound to device {} ... initializing driver",
handler.driver().name(), deviceId);
Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
pipeliner.init(deviceId, context);
pipeliners.putIfAbsent(deviceId, pipeliner);
}
// Triggers driver setup when the local node becomes a device master.
private class InnerMastershipListener implements MastershipListener {
@Override
public void event(MastershipEvent event) {
switch (event.type()) {
case MASTER_CHANGED:
log.debug("mastership changed on device {}", event.subject());
if (deviceService.isAvailable(event.subject())) {
setupPipelineHandler(event.subject());
}
break;
case BACKUPS_CHANGED:
break;
default:
break;
}
}
}
// Triggers driver setup when a device is (re)detected.
private class InnerDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
switch (event.type()) {
case DEVICE_ADDED:
case DEVICE_AVAILABILITY_CHANGED:
log.debug("Device either added or availability changed {}",
event.subject().id());
if (deviceService.isAvailable(event.subject().id())) {
log.debug("Device is now available {}", event.subject().id());
setupPipelineHandler(event.subject().id());
}
break;
case DEVICE_UPDATED:
break;
case DEVICE_REMOVED:
break;
case DEVICE_SUSPENDED:
break;
case PORT_ADDED:
break;
case PORT_UPDATED:
break;
case PORT_REMOVED:
break;
default:
break;
}
}
}
// Processing context for initializing pipeline driver behaviours.
private class InnerPipelineContext implements PipelinerContext {
@Override
public ServiceDirectory directory() {
return serviceDirectory;
}
@Override
public FlowObjectiveStore store() {
return flowObjectiveStore;
}
}
private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
@Override
public void notify(ObjectiveEvent event) {
log.debug("Received notification of obj event {}", event);
Set<PendingNext> pending = pendingForwards.remove(event.subject());
if (pending == null) {
log.debug("Nothing pending for this obj event");
return;
}
log.debug("Processing pending forwarding objectives {}", pending.size());
pending.forEach(p -> getDevicePipeliner(p.deviceId())
.forward(p.forwardingObjective()));
}
}
/**
* Data class used to hold a pending forwarding objective that could not
* be processed because the associated next object was not present.
*/
private class PendingNext {
private final DeviceId deviceId;
private final ForwardingObjective fwd;
public PendingNext(DeviceId deviceId, ForwardingObjective fwd) {
this.deviceId = deviceId;
this.fwd = fwd;
}
public DeviceId deviceId() {
return deviceId;
}
public ForwardingObjective forwardingObjective() {
return fwd;
}
}
public static String forwardingObjectiveToString(ForwardingObjective forwardingObjective) {
String str = forwardingObjective.priority() + " ";
str += "selector( ";
for (Criterion criterion : forwardingObjective.selector().criteria()) {
str += criterion + " ";
}
str += ") treatment( ";
for (Instruction instruction : forwardingObjective.treatment().allInstructions()) {
str += instruction + " ";
}
str += ")";
return str;
}
}
/*
* 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.flowobjective.impl.composition;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Provides a policy tree to store all flow tables for each device.
*
* Note: This class uses in-memory structures and is not yet distributed.
*/
public class FlowObjectiveCompositionTree {
public FlowObjectiveCompositionManager.PolicyOperator operator;
public FlowObjectiveCompositionTree leftChild;
public FlowObjectiveCompositionTree rightChild;
public short applicationId;
protected FilterTable filterTable;
protected ForwardTable forwardTable;
protected NextTable nextTable;
protected int priorityMultiplier;
protected int priorityAddend;
public FlowObjectiveCompositionTree(short applicationId) {
this.operator = FlowObjectiveCompositionManager.PolicyOperator.Application;
this.leftChild = null;
this.rightChild = null;
this.applicationId = applicationId;
this.filterTable = new FilterTable();
this.forwardTable = new ForwardTable();
this.nextTable = new NextTable();
this.priorityMultiplier = 10;
this.priorityAddend = 10;
}
public FlowObjectiveCompositionTree(Character ch) {
switch (ch) {
case '+':
this.operator = FlowObjectiveCompositionManager.PolicyOperator.Parallel;
break;
case '>':
this.operator = FlowObjectiveCompositionManager.PolicyOperator.Sequential;
break;
case '/':
this.operator = FlowObjectiveCompositionManager.PolicyOperator.Override;
break;
default:
this.operator = FlowObjectiveCompositionManager.PolicyOperator.Application;
break;
}
this.leftChild = null;
this.rightChild = null;
this.applicationId = (short) -1;
this.filterTable = new FilterTable();
this.forwardTable = new ForwardTable();
this.nextTable = new NextTable();
this.priorityMultiplier = 10;
this.priorityAddend = 10;
}
protected List<FilteringObjective> updateFilter(FilteringObjective filteringObjective) {
switch (this.operator) {
case Parallel:
return updateFilterParallel(filteringObjective);
case Sequential:
return updateFilterSequential(filteringObjective);
case Override:
return updateFilterOverride(filteringObjective);
case Application:
if (filteringObjective.appId().id() == this.applicationId) {
return this.filterTable.updateFilter(filteringObjective);
} else {
return new ArrayList<>();
}
default:
return new ArrayList<>();
}
}
// Parallel composition: the filter set is the union of the children
protected List<FilteringObjective> updateFilterParallel(FilteringObjective filteringObjective) {
List<FilteringObjective> leftUpdates = this.leftChild.updateFilter(filteringObjective);
List<FilteringObjective> rightUpdates = this.rightChild.updateFilter(filteringObjective);
List<FilteringObjective> updates = new ArrayList<>();
updates.addAll(leftUpdates);
updates.addAll(rightUpdates);
return this.filterTable.updateFilter(updates);
}
// Sequential composition: the filter set is the filter set of the left child
protected List<FilteringObjective> updateFilterSequential(FilteringObjective filteringObjective) {
List<FilteringObjective> leftUpdates = this.leftChild.updateFilter(filteringObjective);
List<FilteringObjective> rightUpdates = this.rightChild.updateFilter(filteringObjective);
return this.filterTable.updateFilter(leftUpdates);
}
// Override composition: the filter set is the filter set of the left child
protected List<FilteringObjective> updateFilterOverride(FilteringObjective filteringObjective) {
List<FilteringObjective> leftUpdates = this.leftChild.updateFilter(filteringObjective);
List<FilteringObjective> rightUpdates = this.rightChild.updateFilter(filteringObjective);
return this.filterTable.updateFilter(leftUpdates);
}
public List<ForwardingObjective> updateForward(ForwardingObjective forwardingObjective) {
return this.updateForwardNode(forwardingObjective).toForwardingObjectiveList();
}
public ForwardUpdateTable updateForwardNode(ForwardingObjective forwardingObjective) {
switch (this.operator) {
case Parallel:
case Sequential:
case Override:
return updateForwardComposition(forwardingObjective);
case Application:
if (forwardingObjective.appId().id() == this.applicationId) {
return this.forwardTable.updateForward(forwardingObjective);
} else {
return (new ForwardUpdateTable());
}
default:
return (new ForwardUpdateTable());
}
}
protected ForwardUpdateTable updateForwardComposition(ForwardingObjective forwardingObjective) {
ForwardUpdateTable leftUpdates = this.leftChild.updateForwardNode(forwardingObjective);
ForwardUpdateTable rightUpdates = this.rightChild.updateForwardNode(forwardingObjective);
List<ForwardingObjective> addUpdates = new ArrayList<>();
List<ForwardingObjective> removeUpdates = new ArrayList<>();
// Handle ADD
if (this.operator == FlowObjectiveCompositionManager.PolicyOperator.Parallel
|| this.operator == FlowObjectiveCompositionManager.PolicyOperator.Sequential) {
for (ForwardingObjective fo1 : leftUpdates.addObjectives) {
for (ForwardingObjective fo2 : this.rightChild.forwardTable.getForwardingObjectives()) {
ForwardingObjective composedFo = null;
if (this.operator == FlowObjectiveCompositionManager.PolicyOperator.Parallel) {
composedFo = FlowObjectiveCompositionUtil.composeParallel(fo1, fo2);
} else {
composedFo = FlowObjectiveCompositionUtil.composeSequential(fo1, fo2, this.priorityMultiplier);
}
if (composedFo != null) {
addUpdates.add(composedFo);
this.leftChild.forwardTable.addGeneratedParentForwardingObjective(fo1, composedFo);
this.rightChild.forwardTable.addGeneratedParentForwardingObjective(fo2, composedFo);
}
}
}
Collection<ForwardingObjective> leftTableWithoutAdd = FlowObjectiveCompositionUtil
.minusForwardingObjectives(this.leftChild.forwardTable.getForwardingObjectives(),
leftUpdates.addObjectives);
for (ForwardingObjective fo1 : leftTableWithoutAdd) {
for (ForwardingObjective fo2 : rightUpdates.addObjectives) {
ForwardingObjective composedFo = null;
if (this.operator == FlowObjectiveCompositionManager.PolicyOperator.Parallel) {
composedFo = FlowObjectiveCompositionUtil.composeParallel(fo1, fo2);
} else {
composedFo = FlowObjectiveCompositionUtil.composeSequential(fo1, fo2, this.priorityMultiplier);
}
if (composedFo != null) {
addUpdates.add(composedFo);
this.leftChild.forwardTable.addGeneratedParentForwardingObjective(fo1, composedFo);
this.rightChild.forwardTable.addGeneratedParentForwardingObjective(fo2, composedFo);
}
}
}
} else {
for (ForwardingObjective fo : leftUpdates.addObjectives) {
ForwardingObjective composedFo = FlowObjectiveCompositionUtil.composeOverride(fo, this.priorityAddend);
addUpdates.add(composedFo);
this.leftChild.forwardTable.addGeneratedParentForwardingObjective(fo, composedFo);
}
for (ForwardingObjective fo : rightUpdates.addObjectives) {
ForwardingObjective composedFo = FlowObjectiveCompositionUtil.composeOverride(fo, 0);
addUpdates.add(composedFo);
this.rightChild.forwardTable.addGeneratedParentForwardingObjective(fo, composedFo);
}
}
// Handle REMOVE
for (ForwardingObjective fo : leftUpdates.removeObjectives) {
List<ForwardingObjective> fos = this.leftChild.forwardTable
.getGeneratedParentForwardingObjectiveForRemove(fo);
removeUpdates.addAll(fos);
}
this.leftChild.forwardTable.deleteGeneratedParentForwardingObjective(leftUpdates.removeObjectives);
for (ForwardingObjective fo : rightUpdates.removeObjectives) {
List<ForwardingObjective> fos = this.rightChild.forwardTable
.getGeneratedParentForwardingObjectiveForRemove(fo);
removeUpdates.addAll(fos);
}
this.rightChild.forwardTable.deleteGeneratedParentForwardingObjective(rightUpdates.removeObjectives);
ForwardUpdateTable updates = new ForwardUpdateTable();
updates.addUpdateTable(this.forwardTable.updateForward(addUpdates));
updates.addUpdateTable(this.forwardTable.updateForward(removeUpdates));
return updates;
}
public List<NextObjective> updateNext(NextObjective nextObjective) {
switch (this.operator) {
case Parallel:
case Sequential:
case Override:
return updateNextComposition(nextObjective);
case Application:
if (nextObjective.appId().id() == this.applicationId) {
return this.nextTable.updateNext(nextObjective);
} else {
return new ArrayList<>();
}
default:
return new ArrayList<>();
}
}
// Next: the union of the children
protected List<NextObjective> updateNextComposition(NextObjective nextObjective) {
List<NextObjective> leftUpdates = this.leftChild.updateNext(nextObjective);
List<NextObjective> rightUpdates = this.rightChild.updateNext(nextObjective);
List<NextObjective> updates = new ArrayList<>();
updates.addAll(leftUpdates);
updates.addAll(rightUpdates);
return this.nextTable.updateNext(updates);
}
@Override
public String toString() {
String str = null;
switch (this.operator) {
case Parallel:
str = "(" + this.leftChild + "+" + this.rightChild + ")";
break;
case Sequential:
str = "(" + this.leftChild + ">" + this.rightChild + ")";
break;
case Override:
str = "(" + this.leftChild + "/" + this.rightChild + ")";
break;
default:
str = " " + applicationId + " ";
break;
}
return str;
}
}
/*
* 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.flowobjective.impl.composition;
import org.onlab.packet.IpPrefix;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.LambdaCriterion;
import org.onosproject.net.flow.criteria.OchSignalCriterion;
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.criteria.VlanPcpCriterion;
import org.onosproject.net.flow.criteria.MplsCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.L0ModificationInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flow.instructions.L3ModificationInstruction;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
/**
* Provide util functions for FlowObjectiveComposition.
*/
public final class FlowObjectiveCompositionUtil {
private FlowObjectiveCompositionUtil() {}
// only work with VERSATILE
public static ForwardingObjective composeParallel(ForwardingObjective fo1, ForwardingObjective fo2) {
TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), fo2.selector());
if (trafficSelector == null) {
return null;
}
TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
return DefaultForwardingObjective.builder()
.fromApp(fo1.appId())
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(fo1.priority() + fo2.priority())
.withSelector(trafficSelector)
.withTreatment(trafficTreatment)
.add();
}
public static ForwardingObjective composeSequential(ForwardingObjective fo1,
ForwardingObjective fo2,
int priorityMultiplier) {
TrafficSelector revertTrafficSelector = revertTreatmentSelector(fo1.treatment(), fo2.selector());
if (revertTrafficSelector == null) {
return null;
}
TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), revertTrafficSelector);
if (trafficSelector == null) {
return null;
}
TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
return DefaultForwardingObjective.builder()
.fromApp(fo1.appId())
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(fo1.priority() * priorityMultiplier + fo2.priority())
.withSelector(trafficSelector)
.withTreatment(trafficTreatment)
.add();
}
public static ForwardingObjective composeOverride(ForwardingObjective fo, int priorityAddend) {
return DefaultForwardingObjective.builder()
.fromApp(fo.appId())
.makePermanent()
.withFlag(fo.flag())
.withPriority(fo.priority() + priorityAddend)
.withSelector(fo.selector())
.withTreatment(fo.treatment())
.add();
}
public static TrafficSelector intersectTrafficSelector(TrafficSelector ts1, TrafficSelector ts2) {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
Set<Criterion.Type> ts1IntersectTs2 = getTypeSet(ts1);
ts1IntersectTs2.retainAll(getTypeSet(ts2));
for (Criterion.Type type : ts1IntersectTs2) {
Criterion criterion = intersectCriterion(ts1.getCriterion(type), ts2.getCriterion(type));
if (criterion == null) {
return null;
} else {
selectorBuilder.add(criterion);
}
}
Set<Criterion.Type> ts1MinusTs2 = getTypeSet(ts1);
ts1MinusTs2.removeAll(getTypeSet(ts2));
for (Criterion.Type type : ts1MinusTs2) {
selectorBuilder.add(ts1.getCriterion(type));
}
Set<Criterion.Type> ts2MinusTs1 = getTypeSet(ts2);
ts2MinusTs1.removeAll(getTypeSet(ts1));
for (Criterion.Type type : ts2MinusTs1) {
selectorBuilder.add(ts2.getCriterion(type));
}
return selectorBuilder.build();
}
public static TrafficTreatment unionTrafficTreatment(TrafficTreatment tt1, TrafficTreatment tt2) {
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
for (Instruction instruction : tt1.allInstructions()) {
treatmentBuilder.add(instruction);
}
for (Instruction instruction : tt2.allInstructions()) {
treatmentBuilder.add(instruction);
}
return treatmentBuilder.build();
}
public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment,
TrafficSelector trafficSelector) {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
Map<Criterion.Type, Criterion> criterionMap = new HashMap<>();
for (Criterion criterion : trafficSelector.criteria()) {
criterionMap.put(criterion.type(), criterion);
}
for (Instruction instruction : trafficTreatment.allInstructions()) {
switch (instruction.type()) {
case DROP:
return null;
case OUTPUT:
break;
case GROUP:
break;
case L0MODIFICATION: {
L0ModificationInstruction l0 = (L0ModificationInstruction) instruction;
switch (l0.subtype()) {
case LAMBDA:
if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
if (((LambdaCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
== ((L0ModificationInstruction.ModLambdaInstruction) l0).lambda()) {
criterionMap.remove(Criterion.Type.OCH_SIGID);
} else {
return null;
}
} else {
break;
}
case OCH:
if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
.equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) {
criterionMap.remove(Criterion.Type.OCH_SIGID);
} else {
return null;
}
} else {
break;
}
default:
break;
}
break;
}
case L2MODIFICATION: {
L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
switch (l2.subtype()) {
case ETH_SRC:
if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) {
if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac()
.equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
criterionMap.remove(Criterion.Type.ETH_SRC);
} else {
return null;
}
} else {
break;
}
case ETH_DST:
if (criterionMap.containsKey(Criterion.Type.ETH_DST)) {
if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac()
.equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
criterionMap.remove(Criterion.Type.ETH_DST);
} else {
return null;
}
} else {
break;
}
case VLAN_ID:
if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) {
if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId()
.equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) {
criterionMap.remove(Criterion.Type.VLAN_VID);
} else {
return null;
}
} else {
break;
}
case VLAN_PCP:
if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) {
if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority()
== ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) {
criterionMap.remove(Criterion.Type.VLAN_PCP);
} else {
return null;
}
} else {
break;
}
case MPLS_LABEL:
if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) {
if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label()
.equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).label())) {
criterionMap.remove(Criterion.Type.ETH_DST);
} else {
return null;
}
} else {
break;
}
default:
break;
}
break;
}
case TABLE:
break;
case L3MODIFICATION: {
L3ModificationInstruction l3 = (L3ModificationInstruction) instruction;
switch (l3.subtype()) {
case IPV4_SRC:
if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) {
if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip()
.contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
criterionMap.remove(Criterion.Type.IPV4_SRC);
} else {
return null;
}
} else {
break;
}
case IPV4_DST:
if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) {
if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip()
.contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
criterionMap.remove(Criterion.Type.IPV4_DST);
} else {
return null;
}
} else {
break;
}
case IPV6_SRC:
if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) {
if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip()
.contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
criterionMap.remove(Criterion.Type.IPV6_SRC);
} else {
return null;
}
} else {
break;
}
case IPV6_DST:
if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) {
if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip()
.contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
criterionMap.remove(Criterion.Type.IPV6_DST);
} else {
return null;
}
} else {
break;
}
case IPV6_FLABEL:
if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) {
if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).ip()
.equals(((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3)
.flowLabel())) {
criterionMap.remove(Criterion.Type.IPV4_SRC);
} else {
return null;
}
} else {
break;
}
default:
break;
}
break;
}
case METADATA:
break;
default:
break;
}
}
for (Criterion criterion : criterionMap.values()) {
selectorBuilder.add(criterion);
}
return selectorBuilder.build();
}
public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
Set<Criterion.Type> typeSet = new HashSet<>();
for (Criterion criterion : trafficSelector.criteria()) {
typeSet.add(criterion.type());
}
return typeSet;
}
public static Criterion intersectCriterion(Criterion c1, Criterion c2) {
switch (c1.type()) {
case IPV4_SRC: {
IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
if (ipPrefix == null) {
return null;
} else {
return Criteria.matchIPSrc(ipPrefix);
}
}
case IPV4_DST: {
IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
if (ipPrefix == null) {
return null;
} else {
return Criteria.matchIPDst(ipPrefix);
}
}
case IPV6_SRC: {
IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
if (ipPrefix == null) {
return null;
} else {
return Criteria.matchIPv6Src(ipPrefix);
}
}
case IPV6_DST: {
IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
if (ipPrefix == null) {
return null;
} else {
return Criteria.matchIPv6Dst(ipPrefix);
}
}
default:
if (!c1.equals(c2)) {
return null;
} else {
return c1;
}
}
}
public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) {
if (ip1.contains(ip2)) {
return ip1;
} else if (ip2.contains(ip1)) {
return ip2;
} else {
return null;
}
}
public static FlowObjectiveCompositionTree parsePolicyString(String policy) {
List<FlowObjectiveCompositionTree> postfix = transformToPostfixForm(policy);
return buildPolicyTree(postfix);
}
private static List<FlowObjectiveCompositionTree> transformToPostfixForm(String policy) {
Stack<Character> stack = new Stack<>();
List<FlowObjectiveCompositionTree> postfix = new ArrayList<>();
for (int i = 0; i < policy.length(); i++) {
Character ch = policy.charAt(i);
if (Character.isDigit(ch)) {
int applicationId = ch - '0';
while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) {
i++;
applicationId = applicationId * 10 + policy.charAt(i) - '0';
}
postfix.add(new FlowObjectiveCompositionTree((short) applicationId));
} else if (ch == '(') {
stack.push(ch);
} else if (ch == ')') {
while (stack.peek() != '(') {
postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
}
stack.pop();
} else {
while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) {
postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
}
stack.push(ch);
}
}
while (!stack.isEmpty()) {
postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
}
return postfix;
}
private static boolean compareOperatorPriority(char peek, char cur) {
if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) {
return true;
} else if (peek == '>' && (cur == '+' || cur == '>')) {
return true;
} else if (peek == '+' && cur == '+') {
return true;
}
return false;
}
private static FlowObjectiveCompositionTree buildPolicyTree(List<FlowObjectiveCompositionTree> postfix) {
Stack<FlowObjectiveCompositionTree> stack = new Stack<>();
for (FlowObjectiveCompositionTree node : postfix) {
if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) {
stack.push(node);
} else {
node.rightChild = stack.pop();
node.leftChild = stack.pop();
stack.push(node);
}
}
return stack.pop();
}
public static Collection<ForwardingObjective> minusForwardingObjectives(Collection<ForwardingObjective> fo1,
Collection<ForwardingObjective> fo2) {
Map<Integer, ForwardingObjective> map = new HashMap<>();
for (ForwardingObjective fo : fo1) {
map.put(fo.id(), fo);
}
for (ForwardingObjective fo : fo2) {
map.remove(fo.id());
}
return map.values();
}
}
/*
* 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.flowobjective.impl.composition;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Provides a table to store Forward.
*/
public class ForwardTable {
protected Map<Integer, ForwardingObjective> forwardMap;
protected Map<Integer, List<ForwardingObjective>> generatedParentForwardingObjectiveMap;
public ForwardTable() {
this.forwardMap = new HashMap<>();
this.generatedParentForwardingObjectiveMap = new HashMap<>();
}
public ForwardUpdateTable updateForward(ForwardingObjective forwardingObjective) {
ForwardUpdateTable updates = new ForwardUpdateTable();
switch (forwardingObjective.op()) {
case ADD:
this.forwardMap.put(forwardingObjectiveHash(forwardingObjective), forwardingObjective);
this.generatedParentForwardingObjectiveMap
.put(forwardingObjectiveHash(forwardingObjective), new ArrayList<>());
updates.addObjectives.add(forwardingObjective);
break;
case REMOVE:
if (this.forwardMap.remove(forwardingObjectiveHash(forwardingObjective)) != null) {
updates.removeObjectives.add(forwardingObjective);
}
break;
default:
break;
}
return updates;
}
public ForwardUpdateTable updateForward(List<ForwardingObjective> forwardingObjectives) {
ForwardUpdateTable updates = new ForwardUpdateTable();
for (ForwardingObjective forwardingObjective : forwardingObjectives) {
updates.addUpdateTable(this.updateForward(forwardingObjective));
}
return updates;
}
public void addGeneratedParentForwardingObjective(ForwardingObjective child, ForwardingObjective parent) {
this.generatedParentForwardingObjectiveMap.get(forwardingObjectiveHash(child)).add(parent);
}
public void deleteGeneratedParentForwardingObjective(List<ForwardingObjective> children) {
for (ForwardingObjective fo : children) {
this.generatedParentForwardingObjectiveMap.remove(forwardingObjectiveHash(fo));
}
}
private List<ForwardingObjective> getGeneratedParentForwardingObjective(ForwardingObjective child) {
return this.generatedParentForwardingObjectiveMap.get(forwardingObjectiveHash(child));
}
public List<ForwardingObjective> getGeneratedParentForwardingObjectiveForRemove(ForwardingObjective child) {
List<ForwardingObjective> fos = this.generatedParentForwardingObjectiveMap.get(forwardingObjectiveHash(child));
List<ForwardingObjective> removeFos = new ArrayList<>();
for (ForwardingObjective fo : fos) {
removeFos.add(DefaultForwardingObjective.builder()
.fromApp(fo.appId())
.makePermanent()
.withFlag(fo.flag())
.withPriority(fo.priority())
.withSelector(fo.selector())
.withTreatment(fo.treatment())
.remove());
}
return removeFos;
}
public Collection<ForwardingObjective> getForwardingObjectives() {
return this.forwardMap.values();
}
public static int forwardingObjectiveHash(ForwardingObjective forwardingObjective) {
return Objects.hash(forwardingObjective.selector(), forwardingObjective.flag(),
forwardingObjective.permanent(), forwardingObjective.timeout(),
forwardingObjective.appId(), forwardingObjective.priority(),
forwardingObjective.nextId(), forwardingObjective.treatment());
}
}
/*
* 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.flowobjective.impl.composition;
import org.onosproject.net.flowobjective.ForwardingObjective;
import java.util.ArrayList;
import java.util.List;
/**
* Provides an update table for Forward.
*/
public class ForwardUpdateTable {
public List<ForwardingObjective> addObjectives;
public List<ForwardingObjective> removeObjectives;
public ForwardUpdateTable() {
this.addObjectives = new ArrayList<>();
this.removeObjectives = new ArrayList<>();
}
public void addUpdateTable(ForwardUpdateTable updateTable) {
this.addObjectives.addAll(updateTable.addObjectives);
this.removeObjectives.addAll(updateTable.removeObjectives);
}
public List<ForwardingObjective> toForwardingObjectiveList() {
List<ForwardingObjective> forwardingObjectives = new ArrayList<>();
forwardingObjectives.addAll(this.addObjectives);
forwardingObjectives.addAll(this.removeObjectives);
return forwardingObjectives;
}
}
/*
* 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.flowobjective.impl.composition;
import org.onosproject.net.flowobjective.NextObjective;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Provides a table to store Next.
*/
public class NextTable {
protected Map<Integer, NextObjective> nextMap;
public NextTable() {
this.nextMap = new HashMap<>();
}
public List<NextObjective> updateNext(NextObjective nextObjective) {
List<NextObjective> updates = new ArrayList<>();
switch (nextObjective.op()) {
case ADD:
this.nextMap.put(nextObjective.id(), nextObjective);
updates.add(nextObjective);
break;
case REMOVE:
this.nextMap.remove(nextObjective.id());
updates.add(nextObjective);
break;
default:
break;
}
return updates;
}
public List<NextObjective> updateNext(List<NextObjective> nextObjectives) {
List<NextObjective> updates = new ArrayList<>();
for (NextObjective nextObjective : nextObjectives) {
updates.addAll(this.updateNext(nextObjective));
}
return updates;
}
}
/*
* Copyright 2014-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.flowobjective.impl;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Test FlowObjectiveCompositionTree.
*/
@Ignore
public class FlowObjectiveCompositionTreeTest {
private final Logger log = LoggerFactory.getLogger(getClass());
@Before
public void setUp() {}
@After
public void tearDown() {}
/*@Test
public void testParallelComposition() {
FlowObjectiveCompositionTree policyTree = FlowObjectiveCompositionUtil.parsePolicyString("31+32");
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPSrc(IpPrefix.valueOf("1.0.0.0/24"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(0)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(1))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.2/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(2))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(0)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Parallel ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(3))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Parallel ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(3))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.remove();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPSrc(IpPrefix.valueOf("1.0.0.0/24"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.remove();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(0)
.withSelector(selector)
.withTreatment(treatment)
.remove();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Parallel ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
}
@Test
public void testSequentialComposition() {
FlowObjectiveCompositionTree policyTree = FlowObjectiveCompositionUtil.parsePolicyString("31>32");
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPSrc(IpPrefix.valueOf("0.0.0.0/2"))
.matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setIpDst(IpAddress.valueOf("2.0.0.1"))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(3)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setIpDst(IpAddress.valueOf("2.0.0.2"))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(0)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(1))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.2/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(2))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(0)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Sequential ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(3))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPSrc(IpPrefix.valueOf("0.0.0.0/1"))
.matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setIpDst(IpAddress.valueOf("2.0.0.3"))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(3)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Sequential ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(3))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.remove();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPSrc(IpPrefix.valueOf("0.0.0.0/1"))
.matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setIpDst(IpAddress.valueOf("2.0.0.3"))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(3)
.withSelector(selector)
.withTreatment(treatment)
.remove();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Sequential ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
}
@Test
public void testOverrideComposition() {
FlowObjectiveCompositionTree policyTree = FlowObjectiveCompositionUtil.parsePolicyString("31/32");
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPSrc(IpPrefix.valueOf("1.0.0.0/32"))
.matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(3))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(31, "a"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(1))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.2/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(2))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
{
TrafficSelector selector = DefaultTrafficSelector.builder().build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(0)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Override ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(3))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.add();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Override ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
{
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(3))
.build();
ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
.fromApp(new DefaultApplicationId(32, "b"))
.makePermanent()
.withFlag(ForwardingObjective.Flag.VERSATILE)
.withPriority(1)
.withSelector(selector)
.withTreatment(treatment)
.remove();
helper(policyTree, forwardingObjective);
}
System.out.println("---------- Override ----------");
for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
System.out.println(forwardingObjectiveToString(fo));
}
}
private void helper(FlowObjectiveCompositionTree policyTree, ForwardingObjective forwardingObjective) {
log.info("before composition");
log.info("\t{}", forwardingObjectiveToString(forwardingObjective));
List<ForwardingObjective> forwardingObjectives
= policyTree.updateForward(forwardingObjective);
log.info("after composition");
for (ForwardingObjective fo : forwardingObjectives) {
log.info("\t{}", forwardingObjectiveToString(fo));
}
}*/
}