| /** |
| * 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.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(); |
| } |
| }; |
| } |
| |
| |
| } |