Created
June 4, 2013 01:10
-
-
Save hugobenichi/5702858 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2011 Midokura KK | |
*/ | |
package org.midonet.midolman.rules; | |
import java.util.Set; | |
import java.util.UUID; | |
import org.midonet.packets.IPAddr; | |
import org.midonet.packets.IPAddr$; | |
import org.midonet.packets.IPSubnet; | |
import org.midonet.packets.IPv4Addr; | |
import org.midonet.packets.IntIPv4; | |
import org.midonet.packets.MAC; | |
import org.midonet.packets.Unsigned; | |
import org.midonet.sdn.flows.WildcardMatch; | |
import static org.midonet.packets.Unsigned.unsign; | |
/** | |
* Expresses general conditions that a packet has to match ?? (hugo's guess) | |
* TODO: it would be nice to have a description of the meaning of the fields. | |
* Questions ? | |
* 1) aren't boolean fields in java taking a full bytes ? | |
* maybe some fields could be packed together with BitSet | |
* this would also speed up comparison and matches possibly | |
*/ | |
public class Condition { | |
public boolean conjunctionInv; | |
public boolean matchForwardFlow; | |
public boolean matchReturnFlow; | |
public Set<UUID> inPortIds; | |
public boolean inPortInv; | |
public Set<UUID> outPortIds; | |
public boolean outPortInv; | |
public UUID portGroup; | |
public boolean invPortGroup; | |
public Integer dlType = null; | |
public boolean invDlType = false; | |
public MAC dlSrc = null; | |
public boolean invDlSrc = false; | |
public MAC dlDst = null; | |
public boolean invDlDst = false; | |
public Byte nwTos; | |
public boolean nwTosInv; | |
public Byte nwProto; | |
public boolean nwProtoInv; | |
public IPSubnet nwSrcIp; | |
public boolean nwSrcInv; | |
public IPSubnet nwDstIp; | |
public boolean nwDstInv; | |
public int tpSrcStart; | |
public int tpSrcEnd; | |
public boolean tpSrcInv; | |
public int tpDstStart; | |
public int tpDstEnd; | |
public boolean tpDstInv; | |
/** | |
* Default constructor for the Jackson deserialization. | |
*/ | |
public Condition() { super(); } | |
/** | |
* Checks if the Condition matches a set of rules specified by | |
* a WildcardMatch instance in the context given by a | |
* ChainPacketContext instance. | |
* TODO: give a bit more context about callers of this method and | |
* document better in what matches what. | |
* @param fwdInfo ChainPacketContext that the Condition has to match. | |
* @param pkMatch WildcardMatch that the Condition has to match. | |
* @param isPortFilter specify if we re testing a port filter ?? | |
* @return true if the Condition matches. | |
*/ | |
public boolean matches(ChainPacketContext fwdInfo, | |
WildcardMatch pktMatch, | |
boolean isPortFilter) { | |
return this.conjunctionInv ^ ( | |
this.match_context(fwdInfo, isPortFilter) | |
&& this.match_wildcard(pktMatch) | |
); | |
} | |
/** | |
* Helper function for Condition#matches. | |
* @param fwdInfo ChainPacketContext to match. | |
* @return true if the Condition matches the ChainPacketContext. | |
* @see Condition#matches | |
*/ | |
private boolean match_context(ChainPacketContext fwdInfo, | |
boolean isPortFilter) { | |
if ( this.matchForwardFlow && !fwdInfo.isForwardFlow()) | |
return false; | |
if ( this.matchReturnFlow && fwdInfo.isForwardFlow()) | |
return false; | |
Set<UUID> senderGroups = fwdInfo.getPortGroups(); | |
boolean port_match_cond = ( this.portGroup == null ) | |
|| ( | |
this.invPortGroup ^ ( | |
( senderGroups != null ) | |
&& senderGroups.contains( this.portGroup) | |
) | |
); | |
UUID inPortId = null; | |
UUID outPortId = null; | |
if ( !isPortFilter ) { | |
inPortId = fwdInfo.getInPortId(); | |
outPortId = fwdInfo.getOutPortId(); | |
} | |
return port_match_cond | |
&& matchPort(this.inPortIds, inPortId, this.inPortInv) | |
&& matchPort(this.outPortIds, outPortId, this.outPortInv); | |
} | |
/** | |
* Helper function for Condition#matches. | |
* @param pktMatch a Wildcard instance to match. | |
* @return true if the Condition instance matches the wildcard. | |
* @see Condition#matches | |
*/ | |
private boolean match_wildcard(WildcardMatch pktMatch) { | |
// || !matchField(dlType, pktMatch.getEtherType() != null ? | |
// Unsigned.unsign(pktMatch.getEtherType()) : null, invDlType) | |
return matchField(this.dlType, | |
Unsigned.fromBoxedShort(pktMatch.getEtherType()), | |
this.invDlType) | |
&& matchField(this.dlSrc, pktMatch.getEthernetSource(), | |
this.invDlSrc) | |
&& matchField(this.dlDst, pktMatch.getEthernetDestination(), | |
this.invDlDst) | |
&& matchField(this.nwTos, pktMatch.getNetworkTOS(), this.nwTosInv) | |
&& matchField(this.nwProto, pktMatch.getNetworkProtocolObject(), | |
this.nwProtoInv) | |
&& matchIP(this.nwSrcIp, pktMatch.getNetworkSourceIP(), | |
this.nwSrcInv) | |
&& matchIP(this.nwDstIp, pktMatch.getNetworkDestinationIP(), | |
this.nwDstInv) | |
&& matchRange(this.tpSrcStart, this.tpSrcEnd, | |
pktMatch.getTransportSourceObject(), this.tpSrcInv) | |
&& matchRange(this.tpDstStart, this.tpDstEnd, | |
pktMatch.getTransportDestinationObject(), | |
this.tpDstInv); | |
} | |
/** | |
* Static helper function for Condition#matches. It simply checks | |
* if a UUID is in some test, with true by default. | |
* @param condPorts set of ports to look into. Packet matches if empty set. | |
* @param port port to find. Packet matches if null. | |
* @param negate reverses the set presence test into abscence test. | |
* @return true if presence/abscence test passes. | |
* @see Condition#match_context | |
*/ | |
private static boolean matchPort(Set<UUID> condPorts, | |
UUID port, | |
boolean negate) { | |
return ( condPorts == null ) | |
|| ( condPorts.size() == 0 ) | |
|| ( negate ^ condPorts.contains(port) ); | |
} | |
/** | |
* Static helper function for Condition#matches. It simply does equality | |
* check and default to true if input field is null. | |
* @param condField generic field to test from the Condition instance. | |
* @param pktField generic field to match. | |
* @param negate reverse the equality test. Ignored if test field is null. | |
* @return true if the test passes. | |
* @see Condition#match_wildcard | |
*/ | |
private static <T> boolean matchField(T condField, | |
T pktField, | |
boolean negate) { | |
return ( condField == null ) | |
|| ( negate ^ condField.equals(pktField) ); | |
} | |
/** | |
* Static helper function for Condition#matches. It simply does IP matching | |
* check and default to true if input field is null. | |
* what if condSubet is null and pktIp is null, should true be retourned ? | |
* case pktIp null handeld by IPSubnet. | |
* @param condSubnet subnet for the input ip to be into. | |
* @param pktIp Ip address to test. | |
* @param negate reverse the test. Ignored if subnet is null. | |
* @return true if the test passes or subnet is null. | |
* @see Condition#match_wildcard | |
*/ | |
private static boolean matchIP(IPSubnet condSubnet, | |
IPAddr pktIp, | |
boolean negate) { | |
return ( condSubnet == null ) | |
|| ( negate ^ condSubnet.containsAddress(pktIp) ); | |
} | |
/** | |
* Static helper function for Condition#matches. | |
* Simply does a numeric range test. | |
* Packet is considered to match if the condField is not specified. | |
* If the lower bound of the range is specified and the pkt field | |
* is below it, the condition is false. | |
* If the upper bound of the range is specified and the pkt field | |
* is above it, the condition is false. | |
* @param start beginning of range. 0 means it is not set. | |
* @param end end of range. 0 means it is not set. | |
* @param pktField integer field to test. | |
* @param negate reverse the test. Ignored if range is not set. | |
* @return true if the field is in range or the range is empty. | |
* @see Condition#match_wildcard | |
*/ | |
private static boolean matchRange(int start, | |
int end, | |
Integer pktField, | |
boolean negate) { | |
return ( start == 0 && end == 0) | |
|| negate ^ ( | |
( pktField != null ) | |
&& ( start == 0 || start <= unsign(pktField) ) | |
&& ( end == 0 || end >= unsign(pktField) ) | |
); | |
} | |
@Override | |
public String toString() { | |
StringBuilder sb = new StringBuilder("Condition ["); | |
if (conjunctionInv) | |
sb.append("conjunctionInv=true, "); | |
if (matchForwardFlow) | |
sb.append("matchForwardFlow=true, "); | |
if (matchReturnFlow) | |
sb.append("matchReturnFlow=true, "); | |
if (inPortIds != null && inPortIds.size() > 0) { | |
sb.append("inPortIds={"); | |
for (UUID id : inPortIds) { | |
sb.append(id.toString()).append(","); | |
} | |
sb.append("}, "); | |
if (inPortInv) | |
sb.append("inPortInv=").append(inPortInv).append(", "); | |
} | |
if (outPortIds != null && outPortIds.size() > 0) { | |
sb.append("outPortIds={"); | |
for (UUID id : outPortIds) { | |
sb.append(id.toString()).append(","); | |
} | |
sb.append("}, "); | |
if (outPortInv) | |
sb.append("outPortInv=").append(outPortInv).append(", "); | |
} | |
if (portGroup != null) { | |
sb.append("portGroup=").append(portGroup).append(", "); | |
if (invPortGroup) | |
sb.append("invPortGroup=true, "); | |
} | |
if (null != dlType) { | |
sb.append("dlType=").append(dlType.intValue()).append(", "); | |
if(invDlType) | |
sb.append("invDlType").append(invDlType).append(", "); | |
} | |
if (null != dlSrc) { | |
sb.append("dlSrc=").append(dlSrc).append(", "); | |
if(invDlSrc) | |
sb.append("invDlSrc").append(invDlSrc).append(", "); | |
} | |
if (null != dlDst) { | |
sb.append("dlDst=").append(dlDst).append(", "); | |
if(invDlDst) | |
sb.append("invDlDst").append(invDlDst).append(", "); | |
} | |
if (null != nwTos) { | |
sb.append("nwTos=").append(nwTos).append(", "); | |
if(nwTosInv) | |
sb.append("nwTosInv").append(nwTosInv).append(", "); | |
} | |
if (null != nwProto) { | |
sb.append("nwProto=").append(nwProto).append(", "); | |
if(nwProtoInv) | |
sb.append("nwProtoInv").append(nwProtoInv).append(", "); | |
} | |
if (null != nwSrcIp) { | |
sb.append("nwSrcIp=").append(nwSrcIp.toString()).append(", "); | |
if(nwSrcInv) | |
sb.append("nwSrcInv").append(nwSrcInv).append(", "); | |
} | |
if (null != nwDstIp) { | |
sb.append("nwDstIp=").append(nwDstIp.toString()).append(", "); | |
if(nwDstInv) | |
sb.append("nwDstInv").append(nwDstInv).append(", "); | |
} | |
if (0 != tpSrcStart || 0 != tpSrcEnd) { | |
sb.append("tpSrcStart=").append(tpSrcStart).append(", "); | |
sb.append("tpSrcEnd=").append(tpSrcEnd).append(", "); | |
if(tpSrcInv) | |
sb.append("tpSrcInv").append(tpSrcInv).append(", "); | |
} | |
if (0 != tpDstStart || 0 != tpDstEnd) { | |
sb.append("tpDstStart=").append(tpDstStart).append(", "); | |
sb.append("tpDstEnd=").append(tpDstEnd).append(", "); | |
if(tpDstInv) | |
sb.append("tpDstInv").append(tpDstInv).append(", "); | |
} | |
sb.append("]"); | |
return sb.toString(); | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
Condition condition = (Condition) o; | |
if (conjunctionInv != condition.conjunctionInv) return false; | |
if (inPortInv != condition.inPortInv) return false; | |
if (invDlDst != condition.invDlDst) return false; | |
if (invDlSrc != condition.invDlSrc) return false; | |
if (invDlType != condition.invDlType) return false; | |
if (invPortGroup != condition.invPortGroup) return false; | |
if (matchForwardFlow != condition.matchForwardFlow) return false; | |
if (matchReturnFlow != condition.matchReturnFlow) return false; | |
if (nwDstInv != condition.nwDstInv) return false; | |
if (nwProtoInv != condition.nwProtoInv) return false; | |
if (nwSrcInv != condition.nwSrcInv) return false; | |
if (nwTosInv != condition.nwTosInv) return false; | |
if (outPortInv != condition.outPortInv) return false; | |
if (tpDstInv != condition.tpDstInv) return false; | |
if (tpSrcInv != condition.tpSrcInv) return false; | |
if (dlDst != null ? !dlDst.equals(condition.dlDst) : condition.dlDst != null) | |
return false; | |
if (dlSrc != null ? !dlSrc.equals(condition.dlSrc) : condition.dlSrc != null) | |
return false; | |
if (dlType != null ? !dlType.equals(condition.dlType) : condition.dlType != null) | |
return false; | |
if (inPortIds != null ? !inPortIds.equals(condition.inPortIds) : condition.inPortIds != null) | |
return false; | |
if (nwDstIp != null ? !nwDstIp.equals(condition.nwDstIp) : condition.nwDstIp != null) | |
return false; | |
if (nwProto != null ? !nwProto.equals(condition.nwProto) : condition.nwProto != null) | |
return false; | |
if (nwSrcIp != null ? !nwSrcIp.equals(condition.nwSrcIp) : condition.nwSrcIp != null) | |
return false; | |
if (nwTos != null ? !nwTos.equals(condition.nwTos) : condition.nwTos != null) | |
return false; | |
if (outPortIds != null ? !outPortIds.equals(condition.outPortIds) : condition.outPortIds != null) | |
return false; | |
if (portGroup != null ? !portGroup.equals(condition.portGroup) : condition.portGroup != null) | |
return false; | |
if (tpDstEnd != 0 ? !(tpDstEnd == condition.tpDstEnd) : condition.tpDstEnd != 0) | |
return false; | |
if (tpDstStart != 0 ? !(tpDstStart == condition.tpDstStart) : condition.tpDstStart != 0) | |
return false; | |
if (tpSrcEnd != 0 ? !(tpSrcEnd == condition.tpSrcEnd) : condition.tpSrcEnd != 0) | |
return false; | |
if (tpSrcStart != 0 ? !(tpSrcStart == condition.tpSrcStart) : condition.tpSrcStart != 0) | |
return false; | |
return true; | |
} | |
@Override | |
public int hashCode() { | |
int result = (conjunctionInv ? 1 : 0); | |
result = 31 * result + (matchForwardFlow ? 1 : 0); | |
result = 31 * result + (matchReturnFlow ? 1 : 0); | |
result = 31 * result + (inPortIds != null ? inPortIds.hashCode() : 0); | |
result = 31 * result + (inPortInv ? 1 : 0); | |
result = 31 * result + (outPortIds != null ? outPortIds.hashCode() : 0); | |
result = 31 * result + (outPortInv ? 1 : 0); | |
result = 31 * result + (portGroup != null ? portGroup.hashCode() : 0); | |
result = 31 * result + (invPortGroup ? 1 : 0); | |
result = 31 * result + (dlType != null ? dlType.hashCode() : 0); | |
result = 31 * result + (invDlType ? 1 : 0); | |
result = 31 * result + (dlSrc != null ? dlSrc.hashCode() : 0); | |
result = 31 * result + (invDlSrc ? 1 : 0); | |
result = 31 * result + (dlDst != null ? dlDst.hashCode() : 0); | |
result = 31 * result + (invDlDst ? 1 : 0); | |
result = 31 * result + (nwTos != null ? nwTos.hashCode() : 0); | |
result = 31 * result + (nwTosInv ? 1 : 0); | |
result = 31 * result + (nwProto != null ? nwProto.hashCode() : 0); | |
result = 31 * result + (nwProtoInv ? 1 : 0); | |
result = 31 * result + (nwSrcIp != null ? nwSrcIp.hashCode() : 0); | |
result = 31 * result + (nwSrcInv ? 1 : 0); | |
result = 31 * result + (nwDstIp != null ? nwDstIp.hashCode() : 0); | |
result = 31 * result + (nwDstInv ? 1 : 0); | |
result = 31 * result + tpSrcStart; | |
result = 31 * result + tpSrcEnd; | |
result = 31 * result + (tpSrcInv ? 1 : 0); | |
result = 31 * result + tpDstStart; | |
result = 31 * result + tpDstEnd; | |
result = 31 * result + (tpDstInv ? 1 : 0); | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment