blob: 5377862738e2fe784bbf490d791909038db5547f [file] [log] [blame]
package net.onrc.onos.api.flowmanager;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import net.onrc.onos.api.flowmanager.FlowBatchOperation.Operator;
import net.onrc.onos.core.matchaction.MatchAction;
import net.onrc.onos.core.matchaction.MatchActionId;
import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
import net.onrc.onos.core.matchaction.MatchActionOperations;
import net.onrc.onos.core.matchaction.MatchActionOperationsId;
import net.onrc.onos.core.matchaction.action.Action;
import net.onrc.onos.core.matchaction.action.OutputAction;
import net.onrc.onos.core.matchaction.match.PacketMatch;
import net.onrc.onos.core.util.IdGenerator;
import net.onrc.onos.core.util.PortNumber;
import net.onrc.onos.core.util.SwitchPort;
/**
* Flow object representing a packet path.
* <p>
* TODO: Think this: Do we need a bandwidth constraint?
*/
public class PacketPathFlow extends PathFlow {
private final PacketMatch match;
private final int hardTimeout;
private final int idleTimeout;
/**
* Default constructor for Kryo deserialization.
*/
@Deprecated
protected PacketPathFlow() {
match = null;
hardTimeout = 0;
idleTimeout = 0;
}
/**
* Constructor.
*
* @param id ID for this new Flow object
* @param match the Match object at the source node of the path
* @param ingressPort the Ingress port number at the ingress edge node
* @param path the Path between ingress and egress edge node
* @param egressActions the list of Action objects at the egress edge node
* @param hardTimeout the hard-timeout value in seconds, or 0 for no timeout
* @param idleTimeout the idle-timeout value in seconds, or 0 for no timeout
*/
public PacketPathFlow(FlowId id,
PacketMatch match, PortNumber ingressPort, Path path,
List<Action> egressActions,
int hardTimeout, int idleTimeout) {
super(id, ingressPort, path, egressActions);
this.match = checkNotNull(match);
this.hardTimeout = hardTimeout;
this.idleTimeout = idleTimeout;
}
/**
* Gets idle-timeout value.
*
* @return Idle-timeout value (seconds)
*/
public int getIdleTimeout() {
return idleTimeout;
}
/**
* Gets hard-timeout value.
*
* @return Hard-timeout value (seconds)
*/
public int getHardTimeout() {
return hardTimeout;
}
@Override
public PacketMatch getMatch() {
return match;
}
@Override
public List<MatchActionOperations> compile(Operator op,
IdGenerator<MatchActionId> maIdGenerator,
IdGenerator<MatchActionOperationsId> maoIdGenerator) {
switch (op) {
case ADD:
return compileAddOperation(maIdGenerator, maoIdGenerator);
case REMOVE:
return compileRemoveOperation(maIdGenerator, maoIdGenerator);
default:
throw new UnsupportedOperationException("Unknown operation.");
}
}
/**
* Creates the next {@link MatchAction} object using iterators.
*
* @param portIterator the iterator for {@link SwitchPort} objects
* @param actionsIterator the iterator for the lists of {@link Action}
* @param maIdGenerator the ID generator of {@link MatchAction}
* @return {@link MatchAction} object based on the specified iterators
*/
private MatchAction createNextMatchAction(Iterator<SwitchPort> portIterator,
Iterator<List<Action>> actionsIterator,
IdGenerator<MatchActionId> maIdGenerator) {
if (portIterator == null || actionsIterator == null ||
!portIterator.hasNext() || !actionsIterator.hasNext()) {
return null;
}
// TODO: Update this after merging the new MatchAction API.
return new MatchAction(
maIdGenerator.getNewId(),
portIterator.next(),
getMatch(), actionsIterator.next());
}
/**
* Generates the list of {@link MatchActionOperations} objects with
* add-operation.
*
* @return the list of {@link MatchActionOperations} objects
*/
private List<MatchActionOperations> compileAddOperation(
IdGenerator<MatchActionId> maIdGenerator,
IdGenerator<MatchActionOperationsId> maoIdGenerator) {
Path path = checkNotNull(getPath());
checkState(path.size() > 0, "Path object has no link.");
// Preparing each actions and ingress port for each switch
List<List<Action>> actionsList = new LinkedList<>();
List<SwitchPort> portList = new LinkedList<>();
for (FlowLink link : path) {
portList.add(link.getDstSwitchPort());
List<Action> l = new ArrayList<Action>();
l.add(new OutputAction(link.getSrcPortNumber()));
actionsList.add(l);
// Arrays.asList(
// (Action) new OutputAction(link.getSrcPortNumber())));
}
// The head switch's ingress port
portList.add(0, new SwitchPort(path.getSrcDpid(), getIngressPortNumber()));
// The tail switch's action
actionsList.add(getEgressActions());
Iterator<SwitchPort> portIterator = portList.iterator();
Iterator<List<Action>> actionsIterator = actionsList.iterator();
// Creates the second phase operation
// using the head switch's match action
MatchAction headMatchAction = createNextMatchAction(portIterator,
actionsIterator, maIdGenerator);
if (headMatchAction == null) {
return null;
}
MatchActionOperations secondOp = new MatchActionOperations(
maoIdGenerator.getNewId());
secondOp.addOperation(new MatchActionOperationEntry(
MatchActionOperations.Operator.ADD, headMatchAction));
// Creates the first phase operation
// using the remaining switches' match actions
MatchActionOperations firstOp = new MatchActionOperations(
maoIdGenerator.getNewId());
MatchAction ma;
while ((ma = createNextMatchAction(portIterator, actionsIterator, maIdGenerator)) != null) {
firstOp.addOperation(new MatchActionOperationEntry(
MatchActionOperations.Operator.ADD, ma));
}
return Arrays.asList(firstOp, secondOp);
}
/**
* Generates the list of {@link MatchActionOperations} objects with
* remote-operation.
*
* @return the list of {@link MatchActionOperations} objects
*/
private List<MatchActionOperations> compileRemoveOperation(
IdGenerator<MatchActionId> maIdGenerator,
IdGenerator<MatchActionOperationsId> maoIdGenerator) {
// TODO implement it
throw new UnsupportedOperationException(
"REMOVE operation is not implemented yet.");
}
}