blob: 379426ffcc8015e1deca0e7ca1c1df3463d8aea8 [file] [log] [blame]
package net.onrc.onos.core.intent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.core.intent.IntentOperation.Operator;
import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
import org.projectfloodlight.openflow.protocol.match.Match.Builder;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.U64;
/**
* A class to represent an OpenFlow FlowMod. <br>
* It is OpenFlow v.1.0-centric and contains a Match and an Action.
*/
public class FlowEntry {
public static final int PRIORITY_DEFAULT = 32768; // Default Flow Priority
protected long sw;
protected Match match;
protected Set<Action> actions;
protected Operator operator;
protected int hardTimeout = 0;
protected int idleTimeout = 0;
protected long flowEntryId;
/**
* Constructor.
*
* @param sw switch's DPID
* @param srcPort source port on switch
* @param dstPort output port on switch
* @param srcMac source Ethernet MAC address
* @param dstMac destination Ethernet MAC address
* @param srcIpAddress source IP address
* @param dstIpAddress destination IP address
* @param operator OpenFlow operation/command (add, remove, etc.)
*/
public FlowEntry(long sw, long srcPort, long dstPort,
MACAddress srcMac, MACAddress dstMac,
int srcIpAddress, int dstIpAddress,
Operator operator) {
this.sw = sw;
this.match = new Match(sw, srcPort, srcMac, dstMac, srcIpAddress, dstIpAddress);
this.actions = new HashSet<Action>();
this.actions.add(new ForwardAction(dstPort));
this.operator = operator;
this.flowEntryId = hashCode();
}
/**
* Gets the switch for this FlowEntry.
*
* @return the switch's DPID
*/
public long getSwitch() {
return sw;
}
/**
* Gets the operator (i.e. add, remove, error).
*
* @return the operator
*/
public Operator getOperator() {
return operator;
}
/**
* Sets the FlowMod operation (i.e. add, remove, error).
*
* @param op the operator
*/
public void setOperator(Operator op) {
operator = op;
}
/**
* Gets hard timeout value in seconds.
*
* @return the hard timeout value in seconds
*/
public int getHardTimeout() {
return hardTimeout;
}
/**
* Sets hard timeout value in seconds.
*
* @param hardTimeout hard timeout value in seconds
*/
public void setHardTimeout(int hardTimeout) {
this.hardTimeout = hardTimeout;
}
/**
* Gets idle timeout value in seconds.
*
* @return the idle timeout value in seconds
*/
public int getIdleTimeout() {
return idleTimeout;
}
/**
* Sets idle timeout value in seconds.
*
* @param idleTimeout idle timeout value in seconds
*/
public void setIdleTimeout(int idleTimeout) {
this.idleTimeout = idleTimeout;
}
/**
* Gets flowEntryId.
*
* @return the flowEntryId to be set in cookie
*/
public long getFlowEntryId() {
return flowEntryId;
}
/**
* Sets flowEntryId.
*
* @param flowEntryId flowEntryId to be set in cookie
*/
public void setFlowEntryId(long flowEntryId) {
this.flowEntryId = flowEntryId;
}
/**
* Builds and returns an OFFlowMod given an OFFactory.
*
* @param factory the OFFactory to use for building
* @return the OFFlowMod
*/
public OFFlowMod buildFlowMod(OFFactory factory) {
OFFlowMod.Builder builder = null;
switch (operator) {
case ADD:
// XXX Workaround for semantic differences between OF1.0 and 1.3.
// The original code for 1.0 used MODIFY_STRICT but in 1.3 a
// MODIFY* command won't create the flow entry if it doesn't
// already exist.
builder = factory.buildFlowAdd();
break;
case REMOVE:
builder = factory.buildFlowDeleteStrict();
break;
default:
// TODO throw error?
return null;
}
// Build OFMatch
Builder matchBuilder = match.getOFMatchBuilder(factory);
// Build OFAction Set
List<OFAction> actionList = new ArrayList<>(actions.size());
for (Action action : actions) {
actionList.add(action.getOFAction(factory));
}
OFPort outp = OFPort.of((short) 0xffff); // OF1.0 OFPP.NONE
if (operator == Operator.REMOVE) {
if (actionList.size() == 1) {
if (actionList.get(0).getType() == OFActionType.OUTPUT) {
OFActionOutput oa = (OFActionOutput) actionList.get(0);
outp = oa.getPort();
}
}
}
// Build OFFlowMod
builder.setMatch(matchBuilder.build())
.setActions(actionList)
.setIdleTimeout(idleTimeout)
.setHardTimeout(hardTimeout)
.setCookie(U64.of(flowEntryId))
.setBufferId(OFBufferId.NO_BUFFER)
.setPriority(PRIORITY_DEFAULT)
.setOutPort(outp);
/* Note: The following are NOT USED.
* builder.setFlags()
* builder.setInstructions()
* builder.setOutGroup()
* builder.setTableId()
* builder.setXid()
*/
// TODO from Flow Pusher
// Set the OFPFF_SEND_FLOW_REM flag if the Flow Entry is not
// permanent.
//
// if ((flowEntry.idleTimeout() != 0) ||
// (flowEntry.hardTimeout() != 0)) {
// fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
// }
// TODO do we care?
// fm.setOutPort(OFPort.OFPP_NONE.getValue());
// if ((flowModCommand == OFFlowMod.OFPFC_DELETE)
// || (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
// if (actionOutputPort.portNumber != null) {
// fm.setOutPort(actionOutputPort.portNumber);
// }
// }
// TODO
// Set the OFPFF_SEND_FLOW_REM flag if the Flow Entry is not
// permanent.
//
// if ((flowEntry.idleTimeout() != 0) ||
// (flowEntry.hardTimeout() != 0)) {
// fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
// }
return builder.build();
}
/**
* Returns a String representation of this FlowEntry.
*
* @return the FlowEntry as a String
*/
@Override
public String toString() {
return match + "->" + actions;
}
/**
* Generates hash using Objects.hash() on the match and actions.
*/
@Override
public final int hashCode() {
return Objects.hash(match, actions);
}
/**
* Flow Entries are equal if their matches and action sets are equal.
*
* @return true if equal, false otherwise
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof FlowEntry)) {
return false;
}
FlowEntry other = (FlowEntry) o;
// Note: we should not consider the operator for this comparison
return this.match.equals(other.match)
&& this.actions.containsAll(other.actions)
&& other.actions.containsAll(this.actions);
}
}