| package org.projectfloodlight.openflow.types; |
| |
| import java.util.ArrayList; |
| |
| import javax.annotation.concurrent.Immutable; |
| |
| |
| /** User-facing object representing a bitmap of ports that can be matched on. |
| * This is implemented by the custom BSN OXM type of_oxm_bsn_in_ports_512. |
| * |
| * You can call set() on the builder for all the Ports you want to match on |
| * and unset to exclude the port. |
| * |
| * <b>Implementation note:</b> to comply with the matching semantics of OXM (which is a logical "AND" not "OR") |
| * the underlying match uses a data format which is very unintuitive. The value is always |
| * 0, and the mask has the bits set for the ports that should <b>NOT</b> be included in the |
| * range. |
| * |
| * For the curious: We transformed the bitmap (a logical OR) problem into a logical |
| * AND NOT problem. |
| * |
| * We logically mean: Inport is 1 OR 3 |
| * We technically say: Inport IS NOT 2 AND IS NOT 4 AND IS NOT 5 AND IS NOT .... |
| * The second term cannot be represented in OXM, the second can. |
| * |
| * That said, all that craziness is hidden from the user of this object. |
| * |
| * <h2>Usage</h2> |
| * OFPortBitmap is meant to be used with MatchField <tt>BSN_IN_PORTS_512</tt> in place |
| * of the raw type Masked<OFBitMask512>. |
| * |
| * <h3>Example:</h3>: |
| * <pre> |
| * OFPortBitMap portBitMap; |
| * Match.Builder matchBuilder; |
| * // initialize |
| * matchBuilder.setMasked(MatchField.BSN_IN_PORTS_512, portBitmap); |
| * </pre> |
| * |
| * @author Andreas Wundsam {@literal <}andreas.wundsam@bigswitch.com{@literal >} |
| */ |
| @Immutable |
| public class OFPortBitMap512 extends Masked<OFBitMask512> { |
| |
| private OFPortBitMap512(OFBitMask512 mask) { |
| super(OFBitMask512.NONE, mask); |
| } |
| |
| /** @return whether or not the given port is logically included in the |
| * match, i.e., whether a packet from in-port <em>port</em> be matched by |
| * this OXM. |
| */ |
| public boolean isOn(OFPort port) { |
| // see the implementation note above about the logical inversion of the mask |
| return !(this.mask.isOn(port.getPortNumber())); |
| } |
| |
| public static OFPortBitMap512 ofPorts(OFPort... ports) { |
| Builder builder = new Builder(); |
| for (OFPort port: ports) { |
| builder.set(port); |
| } |
| return builder.build(); |
| } |
| |
| /** @return an OFPortBitmap based on the 'mask' part of an OFBitMask512, as, e.g., returned |
| * by the switch. |
| **/ |
| public static OFPortBitMap512 of(OFBitMask512 mask) { |
| return new OFPortBitMap512(mask); |
| } |
| |
| /** @return iterating over all ports that are logically included in the |
| * match, i.e., whether a packet from in-port <em>port</em> be matched by |
| * this OXM. |
| */ |
| public Iterable<OFPort> getOnPorts() { |
| ArrayList<OFPort> ports = new ArrayList<>(); |
| for(int i=0; i < 511; i++) { |
| if(!(this.mask.isOn(i))) { |
| ports.add(OFPort.of(i)); |
| } |
| } |
| return ports; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (!(obj instanceof OFPortBitMap512)) |
| return false; |
| OFPortBitMap512 other = (OFPortBitMap512)obj; |
| return (other.value.equals(this.value) && other.mask.equals(this.mask)); |
| } |
| |
| @Override |
| public int hashCode() { |
| return 619 * mask.hashCode() + 257 * value.hashCode(); |
| } |
| |
| public static class Builder { |
| private long raw1 = -1, raw2 = -1, raw3 = -1, raw4 = -1, |
| raw5 = -1, raw6 = -1, raw7 = -1, raw8 = -1; |
| |
| public Builder() { |
| |
| } |
| |
| /** @return whether or not the given port is logically included in the |
| * match, i.e., whether a packet from in-port <em>port</em> be matched by |
| * this OXM. |
| */ |
| public boolean isOn(OFPort port) { |
| // see the implementation note above about the logical inversion of the mask |
| return !(OFBitMask512.isBitOn(raw1, raw2, raw3, raw4, |
| raw5, raw6, raw7, raw8, port.getPortNumber())); |
| } |
| |
| /** remove this port from the match, i.e., packets from this in-port |
| * will NOT be matched. |
| */ |
| public Builder unset(OFPort port) { |
| // see the implementation note above about the logical inversion of the mask |
| int bit = port.getPortNumber(); |
| if (bit < 0 || bit > 511) |
| throw new IndexOutOfBoundsException("Port number is out of bounds"); |
| else if (bit == 511) |
| // the highest order bit in the bitmask is reserved. The switch will |
| // set that bit for all ports >= 511. The reason is that we don't want |
| // the OFPortMap to match all ports out of its range (i.e., a packet |
| // coming in on port 581 would match *any* OFPortMap). |
| throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved."); |
| else if (bit < 64) { |
| raw8 |= ((long)1 << bit); |
| } else if (bit < 128) { |
| raw7 |= ((long)1 << bit - 64); |
| } else if (bit < 192) { |
| raw6 |= ((long)1 << bit - 128); |
| } else if (bit < 256) { |
| raw5 |= ((long)1 << bit - 192); |
| } else if (bit < 320) { |
| raw4 |= ((long)1 << bit - 256); |
| } else if (bit < 384) { |
| raw3 |= ((long)1 << bit - 320); |
| } else if (bit < 448) { |
| raw2 |= ((long)1 << bit - 384); |
| } else { |
| raw1 |= ((long)1 << (bit - 448)); |
| } |
| return this; |
| } |
| |
| /** add this port from the match, i.e., packets from this in-port |
| * will NOT be matched. |
| */ |
| public Builder set(OFPort port) { |
| // see the implementation note above about the logical inversion of the mask |
| int bit = port.getPortNumber(); |
| if (bit < 0 || bit > 511) |
| throw new IndexOutOfBoundsException("Port number is out of bounds"); |
| else if (bit == 511) |
| // the highest order bit in the bitmask is reserved. The switch will |
| // set that bit for all ports >= 511. The reason is that we don't want |
| // the OFPortMap to match all ports out of its range (i.e., a packet |
| // coming in on port 581 would match *any* OFPortMap). |
| throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved."); |
| else if (bit < 64) { |
| raw8 &= ~((long)1 << bit); |
| } else if (bit < 128) { |
| raw7 &= ~((long)1 << bit - 64); |
| } else if (bit < 192) { |
| raw6 &= ~((long)1 << bit - 128); |
| } else if (bit < 256) { |
| raw5 &= ~((long)1 << bit - 192); |
| } else if (bit < 320) { |
| raw4 &= ~((long)1 << bit - 256); |
| } else if (bit < 384) { |
| raw3 &= ~((long)1 << bit - 320); |
| } else if (bit < 448) { |
| raw2 &= ~((long)1 << bit - 384); |
| } else { |
| raw1 &= ~((long)1 << (bit - 448)); |
| } |
| return this; |
| } |
| |
| public OFPortBitMap512 build() { |
| return new OFPortBitMap512(OFBitMask512.of(raw1, raw2, raw3, raw4, |
| raw5, raw6, raw7, raw8)); |
| } |
| } |
| |
| } |