Skip to content

Instantly share code, notes, and snippets.

@hugobenichi
Created June 4, 2013 01:10
Show Gist options
  • Save hugobenichi/5702858 to your computer and use it in GitHub Desktop.
Save hugobenichi/5702858 to your computer and use it in GitHub Desktop.
/*
* 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