blob: b9c2b7566840930eb2648afd97c14f785b42b238 [file] [log] [blame]
Yotam Harchola11f38b2013-09-26 15:38:17 -07001package org.projectfloodlight.openflow.types;
2
Andreas Wundsam9539f922013-10-24 13:07:30 -07003import javax.annotation.concurrent.Immutable;
4
Yotam Harchola11f38b2013-09-26 15:38:17 -07005
Andreas Wundsam28c99752013-10-22 16:51:25 -07006/** User-facing object representing a bitmap of ports that can be matched on.
7 * This is implemented by the custom BSN OXM type of_oxm_bsn_in_ports_182.
8 *
9 * You can call set() on the builder for all the Ports you want to match on
10 * and unset to exclude the port.
11 *
12 * <b>Implementation note:</b> to comply with the matching semantics of OXM (which is a logical "AND" not "OR")
13 * the underlying match uses a data format which is very unintuitive. The value is always
14 * 0, and the mask has the bits set for the ports that should <b>NOT</b> be included in the
15 * range.
16 *
17 * For the curious: We transformed the bitmap (a logical OR) problem into a logical
18 * AND NOT problem.
19 *
20 * We logically mean: Inport is 1 OR 3
21 * We technically say: Inport IS NOT 2 AND IS NOT 4 AND IS NOT 5 AND IS NOT ....
22 * The second term cannot be represented in OXM, the second can.
23 *
24 * That said, all that craziness is hidden from the user of this object.
Andreas Wundsam9539f922013-10-24 13:07:30 -070025 *
26 * <h2>Usage</h2>
27 * OFPortBitmap is meant to be used with MatchField <tt>BSN_IN_PORTS_128</tt> in place
28 * of the raw type Masked&lt;OFBitMask128&gt;.
29 *
30 * <h3>Example:</h3>:
31 * <pre>
32 * OFPortBitMap portBitMap;
33 * Match.Builder matchBuilder;
34 * // initialize
35 * matchBuilder.setMasked(MatchField.BSN_IN_PORTS_128, portBitmap);
36 * </pre>
37 *
Andreas Wundsam28c99752013-10-22 16:51:25 -070038 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
39 */
Andreas Wundsam9539f922013-10-24 13:07:30 -070040@Immutable
Andreas Wundsam9667a162013-10-21 12:58:16 -070041public class OFPortBitMap extends Masked<OFBitMask128> {
Yotam Harchola11f38b2013-09-26 15:38:17 -070042
Andreas Wundsam9667a162013-10-21 12:58:16 -070043 private OFPortBitMap(OFBitMask128 mask) {
Yotam Harchol2c535582013-10-01 15:50:20 -070044 super(OFBitMask128.NONE, mask);
Yotam Harchola11f38b2013-09-26 15:38:17 -070045 }
46
Andreas Wundsam28c99752013-10-22 16:51:25 -070047 /** @return whether or not the given port is logically included in the
48 * match, i.e., whether a packet from in-port <emph>port</emph> be matched by
49 * this OXM.
50 */
Yotam Harchola11f38b2013-09-26 15:38:17 -070051 public boolean isOn(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -070052 // see the implementation note above about the logical inversion of the mask
Yotam Harchol2c535582013-10-01 15:50:20 -070053 return !(this.mask.isOn(port.getPortNumber()));
Yotam Harchola11f38b2013-09-26 15:38:17 -070054 }
55
Andreas Wundsam9667a162013-10-21 12:58:16 -070056 public static OFPortBitMap ofPorts(OFPort... ports) {
Yotam Harchola11f38b2013-09-26 15:38:17 -070057 Builder builder = new Builder();
58 for (OFPort port: ports) {
59 builder.set(port);
60 }
61 return builder.build();
62 }
63
64 @Override
Yotam Harchol595c6442013-09-27 16:29:08 -070065 public boolean equals(Object obj) {
Andreas Wundsam9667a162013-10-21 12:58:16 -070066 if (!(obj instanceof OFPortBitMap))
Yotam Harchol595c6442013-09-27 16:29:08 -070067 return false;
Andreas Wundsam9667a162013-10-21 12:58:16 -070068 OFPortBitMap other = (OFPortBitMap)obj;
Yotam Harchol595c6442013-09-27 16:29:08 -070069 return (other.value.equals(this.value) && other.mask.equals(this.mask));
70 }
71
72 @Override
73 public int hashCode() {
74 return 619 * mask.hashCode() + 257 * value.hashCode();
Yotam Harchola11f38b2013-09-26 15:38:17 -070075 }
76
77 public static class Builder {
Yotam Harchol2c535582013-10-01 15:50:20 -070078 private long raw1 = -1, raw2 = -1;
Yotam Harchola11f38b2013-09-26 15:38:17 -070079
80 public Builder() {
81
82 }
83
Andreas Wundsam28c99752013-10-22 16:51:25 -070084 /** @return whether or not the given port is logically included in the
85 * match, i.e., whether a packet from in-port <emph>port</emph> be matched by
86 * this OXM.
87 */
Yotam Harchola11f38b2013-09-26 15:38:17 -070088 public boolean isOn(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -070089 // see the implementation note above about the logical inversion of the mask
Yotam Harchol2c535582013-10-01 15:50:20 -070090 return !(OFBitMask128.isBitOn(raw1, raw2, port.getPortNumber()));
Yotam Harchola11f38b2013-09-26 15:38:17 -070091 }
92
Andreas Wundsam28c99752013-10-22 16:51:25 -070093 /** remove this port from the match, i.e., packets from this in-port
94 * will NOT be matched.
95 */
Yotam Harchol2c535582013-10-01 15:50:20 -070096 public Builder unset(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -070097 // see the implementation note above about the logical inversion of the mask
Yotam Harchola11f38b2013-09-26 15:38:17 -070098 int bit = port.getPortNumber();
Andreas Wundsam28c99752013-10-22 16:51:25 -070099 if (bit < 0 || bit > 127)
Yotam Harchola11f38b2013-09-26 15:38:17 -0700100 throw new IndexOutOfBoundsException("Port number is out of bounds");
Andreas Wundsam28c99752013-10-22 16:51:25 -0700101 else if (bit == 127)
102 // the highest order bit in the bitmask is reserved. The switch will
103 // set that bit for all ports >= 127. The reason is that we don't want
104 // the OFPortMap to match all ports out of its range (i.e., a packet
105 // coming in on port 181 would match *any* OFPortMap).
106 throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
107 else if (bit < 64) {
Yotam Harchol595c6442013-09-27 16:29:08 -0700108 raw2 |= ((long)1 << bit);
Yotam Harchola11f38b2013-09-26 15:38:17 -0700109 } else {
Yotam Harchol595c6442013-09-27 16:29:08 -0700110 raw1 |= ((long)1 << (bit - 64));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700111 }
112 return this;
113 }
114
Andreas Wundsam28c99752013-10-22 16:51:25 -0700115 /** add this port from the match, i.e., packets from this in-port
116 * will NOT be matched.
117 */
Yotam Harchol2c535582013-10-01 15:50:20 -0700118 public Builder set(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -0700119 // see the implementation note above about the logical inversion of the mask
Yotam Harchola11f38b2013-09-26 15:38:17 -0700120 int bit = port.getPortNumber();
Andreas Wundsam28c99752013-10-22 16:51:25 -0700121 if (bit < 0 || bit > 127)
Yotam Harchola11f38b2013-09-26 15:38:17 -0700122 throw new IndexOutOfBoundsException("Port number is out of bounds");
Andreas Wundsam28c99752013-10-22 16:51:25 -0700123 else if (bit == 127)
124 // the highest order bit in the bitmask is reserved. The switch will
125 // set that bit for all ports >= 127. The reason is that we don't want
126 // the OFPortMap to match all ports out of its range (i.e., a packet
127 // coming in on port 181 would match *any* OFPortMap).
128 throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
129 else if (bit < 64) {
Yotam Harchol595c6442013-09-27 16:29:08 -0700130 raw2 &= ~((long)1 << bit);
Yotam Harchola11f38b2013-09-26 15:38:17 -0700131 } else {
Yotam Harchol595c6442013-09-27 16:29:08 -0700132 raw1 &= ~((long)1 << (bit - 64));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700133 }
134 return this;
135 }
136
Andreas Wundsam9667a162013-10-21 12:58:16 -0700137 public OFPortBitMap build() {
138 return new OFPortBitMap(OFBitMask128.of(raw1, raw2));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700139 }
140 }
141
142}