Shudong Zhou | e44abfd | 2015-06-03 21:32:07 -0700 | [diff] [blame] | 1 | package org.projectfloodlight.openflow.types; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | |
| 5 | import javax.annotation.concurrent.Immutable; |
| 6 | |
| 7 | |
| 8 | /** User-facing object representing a bitmap of ports that can be matched on. |
| 9 | * This is implemented by the custom BSN OXM type of_oxm_bsn_in_ports_512. |
| 10 | * |
| 11 | * You can call set() on the builder for all the Ports you want to match on |
| 12 | * and unset to exclude the port. |
| 13 | * |
| 14 | * <b>Implementation note:</b> to comply with the matching semantics of OXM (which is a logical "AND" not "OR") |
| 15 | * the underlying match uses a data format which is very unintuitive. The value is always |
| 16 | * 0, and the mask has the bits set for the ports that should <b>NOT</b> be included in the |
| 17 | * range. |
| 18 | * |
| 19 | * For the curious: We transformed the bitmap (a logical OR) problem into a logical |
| 20 | * AND NOT problem. |
| 21 | * |
| 22 | * We logically mean: Inport is 1 OR 3 |
| 23 | * We technically say: Inport IS NOT 2 AND IS NOT 4 AND IS NOT 5 AND IS NOT .... |
| 24 | * The second term cannot be represented in OXM, the second can. |
| 25 | * |
| 26 | * That said, all that craziness is hidden from the user of this object. |
| 27 | * |
| 28 | * <h2>Usage</h2> |
| 29 | * OFPortBitmap is meant to be used with MatchField <tt>BSN_IN_PORTS_512</tt> in place |
| 30 | * of the raw type Masked<OFBitMask512>. |
| 31 | * |
| 32 | * <h3>Example:</h3>: |
| 33 | * <pre> |
| 34 | * OFPortBitMap portBitMap; |
| 35 | * Match.Builder matchBuilder; |
| 36 | * // initialize |
| 37 | * matchBuilder.setMasked(MatchField.BSN_IN_PORTS_512, portBitmap); |
| 38 | * </pre> |
| 39 | * |
| 40 | * @author Andreas Wundsam {@literal <}andreas.wundsam@bigswitch.com{@literal >} |
| 41 | */ |
| 42 | @Immutable |
| 43 | public class OFPortBitMap512 extends Masked<OFBitMask512> { |
| 44 | |
| 45 | private OFPortBitMap512(OFBitMask512 mask) { |
| 46 | super(OFBitMask512.NONE, mask); |
| 47 | } |
| 48 | |
| 49 | /** @return whether or not the given port is logically included in the |
| 50 | * match, i.e., whether a packet from in-port <em>port</em> be matched by |
| 51 | * this OXM. |
| 52 | */ |
| 53 | public boolean isOn(OFPort port) { |
| 54 | // see the implementation note above about the logical inversion of the mask |
| 55 | return !(this.mask.isOn(port.getPortNumber())); |
| 56 | } |
| 57 | |
| 58 | public static OFPortBitMap512 ofPorts(OFPort... ports) { |
| 59 | Builder builder = new Builder(); |
| 60 | for (OFPort port: ports) { |
| 61 | builder.set(port); |
| 62 | } |
| 63 | return builder.build(); |
| 64 | } |
| 65 | |
| 66 | /** @return an OFPortBitmap based on the 'mask' part of an OFBitMask512, as, e.g., returned |
| 67 | * by the switch. |
| 68 | **/ |
| 69 | public static OFPortBitMap512 of(OFBitMask512 mask) { |
| 70 | return new OFPortBitMap512(mask); |
| 71 | } |
| 72 | |
| 73 | /** @return iterating over all ports that are logically included in the |
| 74 | * match, i.e., whether a packet from in-port <em>port</em> be matched by |
| 75 | * this OXM. |
| 76 | */ |
| 77 | public Iterable<OFPort> getOnPorts() { |
| 78 | ArrayList<OFPort> ports = new ArrayList<>(); |
| 79 | for(int i=0; i < 511; i++) { |
| 80 | if(!(this.mask.isOn(i))) { |
| 81 | ports.add(OFPort.of(i)); |
| 82 | } |
| 83 | } |
| 84 | return ports; |
| 85 | } |
| 86 | |
| 87 | @Override |
| 88 | public boolean equals(Object obj) { |
| 89 | if (!(obj instanceof OFPortBitMap512)) |
| 90 | return false; |
| 91 | OFPortBitMap512 other = (OFPortBitMap512)obj; |
| 92 | return (other.value.equals(this.value) && other.mask.equals(this.mask)); |
| 93 | } |
| 94 | |
| 95 | @Override |
| 96 | public int hashCode() { |
| 97 | return 619 * mask.hashCode() + 257 * value.hashCode(); |
| 98 | } |
| 99 | |
| 100 | public static class Builder { |
| 101 | private long raw1 = -1, raw2 = -1, raw3 = -1, raw4 = -1, |
| 102 | raw5 = -1, raw6 = -1, raw7 = -1, raw8 = -1; |
| 103 | |
| 104 | public Builder() { |
| 105 | |
| 106 | } |
| 107 | |
| 108 | /** @return whether or not the given port is logically included in the |
| 109 | * match, i.e., whether a packet from in-port <em>port</em> be matched by |
| 110 | * this OXM. |
| 111 | */ |
| 112 | public boolean isOn(OFPort port) { |
| 113 | // see the implementation note above about the logical inversion of the mask |
| 114 | return !(OFBitMask512.isBitOn(raw1, raw2, raw3, raw4, |
| 115 | raw5, raw6, raw7, raw8, port.getPortNumber())); |
| 116 | } |
| 117 | |
| 118 | /** remove this port from the match, i.e., packets from this in-port |
| 119 | * will NOT be matched. |
| 120 | */ |
| 121 | public Builder unset(OFPort port) { |
| 122 | // see the implementation note above about the logical inversion of the mask |
| 123 | int bit = port.getPortNumber(); |
| 124 | if (bit < 0 || bit > 511) |
| 125 | throw new IndexOutOfBoundsException("Port number is out of bounds"); |
| 126 | else if (bit == 511) |
| 127 | // the highest order bit in the bitmask is reserved. The switch will |
Shudong Zhou | c2d7089 | 2015-06-04 09:42:15 -0700 | [diff] [blame] | 128 | // set that bit for all ports >= 511. The reason is that we don't want |
Shudong Zhou | e44abfd | 2015-06-03 21:32:07 -0700 | [diff] [blame] | 129 | // the OFPortMap to match all ports out of its range (i.e., a packet |
Shudong Zhou | c2d7089 | 2015-06-04 09:42:15 -0700 | [diff] [blame] | 130 | // coming in on port 581 would match *any* OFPortMap). |
Shudong Zhou | e44abfd | 2015-06-03 21:32:07 -0700 | [diff] [blame] | 131 | throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved."); |
| 132 | else if (bit < 64) { |
| 133 | raw8 |= ((long)1 << bit); |
| 134 | } else if (bit < 128) { |
| 135 | raw7 |= ((long)1 << bit - 64); |
| 136 | } else if (bit < 192) { |
| 137 | raw6 |= ((long)1 << bit - 128); |
| 138 | } else if (bit < 256) { |
| 139 | raw5 |= ((long)1 << bit - 192); |
| 140 | } else if (bit < 320) { |
| 141 | raw4 |= ((long)1 << bit - 256); |
| 142 | } else if (bit < 384) { |
| 143 | raw3 |= ((long)1 << bit - 320); |
| 144 | } else if (bit < 448) { |
| 145 | raw2 |= ((long)1 << bit - 384); |
| 146 | } else { |
| 147 | raw1 |= ((long)1 << (bit - 448)); |
| 148 | } |
| 149 | return this; |
| 150 | } |
| 151 | |
| 152 | /** add this port from the match, i.e., packets from this in-port |
| 153 | * will NOT be matched. |
| 154 | */ |
| 155 | public Builder set(OFPort port) { |
| 156 | // see the implementation note above about the logical inversion of the mask |
| 157 | int bit = port.getPortNumber(); |
| 158 | if (bit < 0 || bit > 511) |
| 159 | throw new IndexOutOfBoundsException("Port number is out of bounds"); |
| 160 | else if (bit == 511) |
| 161 | // the highest order bit in the bitmask is reserved. The switch will |
Shudong Zhou | c2d7089 | 2015-06-04 09:42:15 -0700 | [diff] [blame] | 162 | // set that bit for all ports >= 511. The reason is that we don't want |
Shudong Zhou | e44abfd | 2015-06-03 21:32:07 -0700 | [diff] [blame] | 163 | // the OFPortMap to match all ports out of its range (i.e., a packet |
Shudong Zhou | c2d7089 | 2015-06-04 09:42:15 -0700 | [diff] [blame] | 164 | // coming in on port 581 would match *any* OFPortMap). |
Shudong Zhou | e44abfd | 2015-06-03 21:32:07 -0700 | [diff] [blame] | 165 | throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved."); |
| 166 | else if (bit < 64) { |
| 167 | raw8 &= ~((long)1 << bit); |
| 168 | } else if (bit < 128) { |
| 169 | raw7 &= ~((long)1 << bit - 64); |
| 170 | } else if (bit < 192) { |
| 171 | raw6 &= ~((long)1 << bit - 128); |
| 172 | } else if (bit < 256) { |
| 173 | raw5 &= ~((long)1 << bit - 192); |
| 174 | } else if (bit < 320) { |
| 175 | raw4 &= ~((long)1 << bit - 256); |
| 176 | } else if (bit < 384) { |
| 177 | raw3 &= ~((long)1 << bit - 320); |
| 178 | } else if (bit < 448) { |
| 179 | raw2 &= ~((long)1 << bit - 384); |
| 180 | } else { |
| 181 | raw1 &= ~((long)1 << (bit - 448)); |
| 182 | } |
| 183 | return this; |
| 184 | } |
| 185 | |
| 186 | public OFPortBitMap512 build() { |
| 187 | return new OFPortBitMap512(OFBitMask512.of(raw1, raw2, raw3, raw4, |
| 188 | raw5, raw6, raw7, raw8)); |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | } |