blob: 2268ce6f490af7ba94c41538d02bc891ad80137a [file] [log] [blame]
/**
* Copyright 2013, Big Switch Networks, Inc.
*
* 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.projectfloodlight.openflow.protocol;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.google.common.base.Joiner;
/**
* a more user friendly representation of the wildcards bits in an OpenFlow
* match. The Wildcards object is
* <ul>
* <li>immutable (i.e., threadsafe)</li>
* <li>instance managed (don't instantiate it yourself), instead call "of"</li>
* <ul>
* <p>
* You can construct a Wildcard object from either its integer representation
* </p>
* <code>
* Wildcard.of(0x3820e0);
* </code>
* <p>
* Or start with either an empty or full wildcard, and select/unselect foo.
* </p>
* <code>
* Wildcard w = Wildcards.NONE
* .set(Flag.DL_SRC, Flag. DL_DST, Flag.DL_VLAN_PCP)
* .setNwDstMask(8)
* .setNwSrcMask(8);
* </code>
* <p>
* <b>Remember:</b> Wildcards objects are immutable. set... operations have
* <b>NO EFFECT</b> on the current wildcard object. You HAVE to use the returned
* changed object.
* </p>
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
public class Wildcards {
public class OFWildcardFlags {
final public static int OFPFW_ALL = ((1 << 22) - 1);
final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */
final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */
final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */
final public static int OFPFW_DL_DST = 1 << 3; /*
* Ethernet destination
* address.
*/
final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */
final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */
final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */
final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */
/*
* IP source address wildcard bit count. 0 is exact match, 1 ignores the
* LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
* the entire field. This is the *opposite* of the usual convention where
* e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded.
*/
final public static int OFPFW_NW_SRC_SHIFT = 8;
final public static int OFPFW_NW_SRC_BITS = 6;
final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT;
final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT;
/* IP destination address wildcard bit count. Same format as source. */
final public static int OFPFW_NW_DST_SHIFT = 14;
final public static int OFPFW_NW_DST_BITS = 6;
final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT;
final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT;
final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */
final public static int OFPFW_NW_TOS = 1 << 21; /*
* IP ToS (DSCP field, 6
* bits).
*/
final public static int OFPFW_ALL_SANITIZED = (((1 << 22) - 1)
& ~OFPFW_NW_SRC_MASK & ~OFPFW_NW_DST_MASK)
| OFPFW_NW_SRC_ALL
| OFPFW_NW_DST_ALL;
}
public final static Wildcards FULL = new Wildcards(OFWildcardFlags.OFPFW_ALL_SANITIZED);
private static final int FULL_INT = FULL.getInt();
public final static Wildcards EXACT = new Wildcards(0);
// floodlight common case: matches on inport + l2
public final static int INT_INPORT_L2_MATCH = 0x3820e0;
public final static Wildcards INPORT_L2_MATCH = new Wildcards(
INT_INPORT_L2_MATCH);
/**
* enum type for the binary flags that can be set in the wildcards field of
* an OFWildcardFlags. Replaces the unwieldy c-ish int constants in OFWildcardFlags.
*/
public static enum Flag {
IN_PORT(OFWildcardFlags.OFPFW_IN_PORT), /* Switch input port. */
DL_VLAN(OFWildcardFlags.OFPFW_DL_VLAN), /* VLAN id. */
DL_SRC(OFWildcardFlags.OFPFW_DL_SRC), /* Ethernet source address. */
DL_DST(OFWildcardFlags.OFPFW_DL_DST), /* Ethernet destination addr */
DL_TYPE(OFWildcardFlags.OFPFW_DL_TYPE), /* Ethernet frame type. */
NW_PROTO(OFWildcardFlags.OFPFW_NW_PROTO), /* IP protocol. */
TP_SRC(OFWildcardFlags.OFPFW_TP_SRC), /* TCP/UDP source port. */
TP_DST(OFWildcardFlags.OFPFW_TP_DST), /* TCP/UDP destination port. */
DL_VLAN_PCP(OFWildcardFlags.OFPFW_DL_VLAN_PCP), /* VLAN priority. */
NW_SRC(-1) { /*
* virtual NW_SRC flag => translates to the strange 6 bits
* in the header
*/
@Override
boolean isBolean() {
return false;
}
@Override
int getInt(int flags) {
return ((flags & OFWildcardFlags.OFPFW_NW_SRC_MASK) >> OFWildcardFlags.OFPFW_NW_SRC_SHIFT);
}
@Override
int setInt(int flags, int srcMask) {
return (flags & ~OFWildcardFlags.OFPFW_NW_SRC_MASK) | (srcMask << OFWildcardFlags.OFPFW_NW_SRC_SHIFT);
}
@Override
int wildcard(int flags) {
return flags & ~OFWildcardFlags.OFPFW_NW_SRC_MASK;
}
@Override
int matchOn(int flags) {
return flags | OFWildcardFlags.OFPFW_NW_SRC_ALL;
}
@Override
boolean isPartiallyOn(int flags) {
int intValue = getInt(flags);
return intValue > 0 && intValue < 32;
}
@Override
boolean isFullyOn(int flags) {
return getInt(flags) >= 32;
}
},
NW_DST(-1) { /*
* virtual NW_SRC flag => translates to the strange 6 bits
* in the header
*/
@Override
boolean isBolean() {
return false;
}
@Override
int getInt(int flags) {
return ((flags & OFWildcardFlags.OFPFW_NW_DST_MASK) >> OFWildcardFlags.OFPFW_NW_DST_SHIFT);
}
@Override
int setInt(int flags, int srcMask) {
return (flags & ~OFWildcardFlags.OFPFW_NW_DST_MASK) | (srcMask << OFWildcardFlags.OFPFW_NW_DST_SHIFT);
}
@Override
int wildcard(int flags) {
return flags & ~OFWildcardFlags.OFPFW_NW_DST_MASK;
}
@Override
int matchOn(int flags) {
return flags | OFWildcardFlags.OFPFW_NW_DST_ALL;
}
@Override
boolean isFullyOn(int flags) {
return getInt(flags) >= 32;
}
},
NW_TOS(OFWildcardFlags.OFPFW_NW_TOS); /* IP ToS (DSCP field, 6 bits). */
final int bitPosition;
Flag(int bitPosition) {
this.bitPosition = bitPosition;
}
/**
* @return a modified OF-1.0 flags field with this flag cleared (match
* on this field)
*/
int matchOn(int flags) {
return flags & ~this.bitPosition;
}
/**
* @return a modified OF-1.0 flags field with this flag set (wildcard
* this field)
*/
int wildcard(int flags) {
return flags | this.bitPosition;
}
/**
* @return true iff this is a true boolean flag that can either be off
* or on.True in OF-1.0 for all fields except NW_SRC and NW_DST
*/
boolean isBolean() {
return false;
}
/**
* @return true iff this wildcard field is currently 'partially on'.
* Always false for true Boolean Flags. Can be true in OF-1.0
* for NW_SRC, NW_DST.
*/
boolean isPartiallyOn(int flags) {
return false;
}
/**
* @return true iff this wildcard field currently fully on (fully
* wildcarded). Equivalent to the boolean flag being set in the
* bitmask for bit flags, and to the wildcarded bit length set
* to >=32 for NW_SRC and NW_DST
* @param flags
* @return
*/
boolean isFullyOn(int flags) {
return (flags & this.bitPosition) != 0;
}
/**
* set the integer representation of this flag. only for NW_SRC and
* NW_DST
*/
int setInt(int flags, int srcMask) {
throw new UnsupportedOperationException();
}
/**
* set the integer representation of this flag. only for NW_SRC and
* NW_DST
*/
int getInt(int flags) {
throw new UnsupportedOperationException();
}
}
private final int flags;
/** private constructor. use Wildcard.of() instead */
private Wildcards(int flags) {
this.flags = flags;
}
/**
* return a wildcard object matching the given int flags. May reuse / cache
* frequently used wildcard instances. Don't rely on it though (use equals
* not ==).
*
* @param flags
* @return
*/
public static Wildcards of(int paramFlags) {
int flags = paramFlags; //sanitizeInt(paramFlags);
switch(flags) {
case 0x0000:
return EXACT;
case OFWildcardFlags.OFPFW_ALL_SANITIZED:
return FULL;
case INT_INPORT_L2_MATCH:
return INPORT_L2_MATCH;
default:
return new Wildcards(flags);
}
}
/** convience method return a wildcard for exactly one set flag */
public static Wildcards of(Wildcards.Flag setFlag) {
return Wildcards.of(setFlag.wildcard(0));
}
/** convience method return a wildcard for exactly two set flags */
public static Wildcards of(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
return Wildcards.of(setFlag.wildcard(setFlag2.wildcard(0)));
}
/** convience method return a wildcard for an arbitrary number of set flags */
public static Wildcards of(Wildcards.Flag... setFlags) {
int flags = 0;
for (Wildcards.Flag flag : setFlags)
flags = flag.wildcard(0);
return Wildcards.of(flags);
}
/** convience method return a wildcards for ofmatches that match on one flag */
public static Wildcards ofMatches(Wildcards.Flag setFlag) {
return Wildcards.of(setFlag.matchOn(FULL_INT));
}
/**
* convience method return a wildcard for for an ofmatch that match on two
* flags
*/
public static Wildcards ofMatches(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
return Wildcards.of(setFlag.matchOn(setFlag2.matchOn(FULL_INT)));
}
/**
* convience method return a wildcard for an ofmatch that amtch on an
* arbitrary number of set flags
*/
public static Wildcards ofMatches(Wildcards.Flag... setFlags) {
int flags = FULL_INT;
for (Wildcards.Flag flag : setFlags)
flags = flag.matchOn(flags);
return Wildcards.of(flags);
}
public static Wildcards ofMatches(Set<Wildcards.Flag> wSet) {
int flags = FULL_INT;
for (Wildcards.Flag flag : wSet)
flags = flag.matchOn(flags);
return Wildcards.of(flags);
}
/**
* return a Wildcards object that has the given flags set
* <p>
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*/
public Wildcards wildcard(Wildcards.Flag flag) {
int flags = flag.wildcard(this.flags);
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return a Wildcards object that has the given flags set
* <p>
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*/
public Wildcards wildcard(Wildcards.Flag flag, Wildcards.Flag flag2) {
int flags = flag.wildcard(flag2.wildcard(this.flags));
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return a Wildcards object that has the given flags wildcarded
* <p>
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*/
public Wildcards wildcard(Wildcards.Flag... setFlags) {
int flags = this.flags;
for (Wildcards.Flag flag : setFlags)
flags = flag.wildcard(flags);
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return a Wildcards object that matches on exactly the given flag
* <p>
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*/
public Wildcards matchOn(Wildcards.Flag flag) {
int flags = flag.matchOn(this.flags);
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return a Wildcards object that matches on exactly the given flags
* <p>
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*/
public Wildcards matchOn(Wildcards.Flag flag, Wildcards.Flag flag2) {
int flags = flag.matchOn(flag2.matchOn(this.flags));
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return a Wildcards object that matches on exactly the given flags
* <p>
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*/
public Wildcards matchOn(Wildcards.Flag... setFlags) {
int flags = this.flags;
for (Wildcards.Flag flag : setFlags)
flags = flag.matchOn(flags);
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return the nw src mask in normal CIDR style, e.g., 8 means x.x.x.x/8
* means 8 bits wildcarded
*/
public int getNwSrcMask() {
return Math.max(0, 32 - Flag.NW_SRC.getInt(flags));
}
/**
* return the nw dst mask in normal CIDR style, e.g., 8 means x.x.x.x/8
* means 8 bits wildcarded
*/
public int getNwDstMask() {
return Math.max(0, 32 - Flag.NW_DST.getInt(flags));
}
/**
* return a Wildcard object that has the given nwSrcCidrMask set.
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*
* @param srcCidrMask
* source mask to set in <b>normal CIDR notation</b>, i.e., 8
* means x.x.x.x/8
* @return a modified object
*/
public Wildcards withNwSrcMask(int srcCidrMask) {
int flags = Flag.NW_SRC.setInt(this.flags, Math.max(0, 32 - srcCidrMask));
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return a Wildcard object that has the given nwDstCidrMask set.
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
*
* @param dstCidrMask
* dest mask to set in <b>normal CIDR notation</b>, i.e., 8 means
* x.x.x.x/8
* @return a modified object
*/
public Wildcards withNwDstMask(int dstCidrMask) {
int flags = Flag.NW_DST.setInt(this.flags, Math.max(0, 32 - dstCidrMask));
if (flags == this.flags)
return this;
else
return new Wildcards(flags);
}
/**
* return a Wildcard object that is inverted to this wildcard object.
* <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
* unmodified. </b>
* @return a modified object
*/
public Wildcards inverted() {
return Wildcards.of(flags ^ OFWildcardFlags.OFPFW_ALL_SANITIZED);
}
public boolean isWildcarded(Flag flag) {
return flag.isFullyOn(flags);
}
/**
* return all wildcard flags that are fully wildcarded as an EnumSet. Do not
* modify. Note: some flags (like NW_SRC and NW_DST) that are partially
* wildcarded are not returned in this set.
*
* @return the EnumSet of wildcards
*/
public EnumSet<Wildcards.Flag> getWildcardedFlags() {
EnumSet<Wildcards.Flag> res = EnumSet.noneOf(Wildcards.Flag.class);
for (Wildcards.Flag flag : Flag.values()) {
if (flag.isFullyOn(flags)) {
res.add(flag);
}
}
return res;
}
/** return the OpenFlow 'wire' integer representation of these wildcards */
public int getInt() {
return flags;
}
/**
* return the OpenFlow 'wire' integer representation of these wildcards.
* Sanitize nw_src and nw_dst to be max. 32 (values > 32 are technically
* possible, but don't make semantic sense)
*/
public static int sanitizeInt(int flags) {
if (((flags & OFWildcardFlags.OFPFW_NW_SRC_MASK) >> OFWildcardFlags.OFPFW_NW_SRC_SHIFT) > 32) {
flags = (flags & ~OFWildcardFlags.OFPFW_NW_SRC_MASK) | OFWildcardFlags.OFPFW_NW_SRC_ALL;
}
if (((flags & OFWildcardFlags.OFPFW_NW_DST_MASK) >> OFWildcardFlags.OFPFW_NW_DST_SHIFT) > 32) {
flags = (flags & ~OFWildcardFlags.OFPFW_NW_DST_MASK) | OFWildcardFlags.OFPFW_NW_DST_ALL;
}
return flags;
}
/**
* is this a wildcard set that has all flags set + and full (/0) nw_src and
* nw_dst wildcarding ?
*/
public boolean isFull() {
return flags == OFWildcardFlags.OFPFW_ALL || flags == OFWildcardFlags.OFPFW_ALL_SANITIZED;
}
/** is this a wildcard of an exact match */
public boolean isExact() {
return flags == 0;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + flags;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Wildcards other = (Wildcards) obj;
if (flags != other.flags)
return false;
return true;
}
private final static Joiner pipeJoiner = Joiner.on("|");
@Override
public String toString() {
List<String> res = new ArrayList<String>();
for (Wildcards.Flag flag : Flag.values()) {
if (flag.isFullyOn(flags)) {
res.add(flag.name().toLowerCase());
}
}
if (Flag.NW_SRC.isPartiallyOn(flags)) {
res.add("nw_src(/" + getNwSrcMask() + ")");
}
if (Flag.NW_DST.isPartiallyOn(flags)) {
res.add("nw_dst(/" + getNwDstMask() + ")");
}
return pipeJoiner.join(res);
}
private final static Joiner commaJoiner = Joiner.on(", ");
/** a Java expression that constructs 'this' wildcards set */
public String toJava() {
if(isFull()) {
return "Wildcards.FULL";
} else if (isExact()){
return "Wildcards.EXACT";
}
StringBuilder b = new StringBuilder();
EnumSet<Flag> myFlags = getWildcardedFlags();
if (myFlags.size() < 3) {
// default to start with empty
b.append("Wildcards.of("
+ commaJoiner.join(prefix("Flag.", myFlags.iterator())) + ")");
} else {
// too many - start with full
EnumSet<Flag> invFlags = inverted().getWildcardedFlags();
b.append("Wildcards.ofMatches("
+ commaJoiner.join(prefix("Flag.", invFlags.iterator())) + ")");
}
if (Flag.NW_SRC.isPartiallyOn(flags)) {
b.append(".setNwSrcMask(" + getNwSrcMask() + ")");
}
if (Flag.NW_DST.isPartiallyOn(flags)) {
b.append(".setNwDstMask(" + getNwDstMask() + ")");
}
return b.toString();
}
private Iterator<String> prefix(final String prefix, final Iterator<?> i) {
return new Iterator<String>() {
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public String next() {
Object next = i.next();
return next == null ? null : prefix + next.toString();
}
@Override
public void remove() {
i.remove();
}
};
}
}