blob: 63b97f324605807fa32929be41f7ff1246d70f1f [file] [log] [blame]
Yotam Harchola11f38b2013-09-26 15:38:17 -07001package org.projectfloodlight.openflow.types;
2
Andreas Wundsam30b359c2013-11-21 19:27:21 -08003import java.util.ArrayList;
4
Andreas Wundsam9539f922013-10-24 13:07:30 -07005import javax.annotation.concurrent.Immutable;
6
Yotam Harchola11f38b2013-09-26 15:38:17 -07007
Andreas Wundsam28c99752013-10-22 16:51:25 -07008/** 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_182.
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.
Andreas Wundsam9539f922013-10-24 13:07:30 -070027 *
28 * <h2>Usage</h2>
29 * OFPortBitmap is meant to be used with MatchField <tt>BSN_IN_PORTS_128</tt> in place
30 * of the raw type Masked&lt;OFBitMask128&gt;.
31 *
32 * <h3>Example:</h3>:
33 * <pre>
34 * OFPortBitMap portBitMap;
35 * Match.Builder matchBuilder;
36 * // initialize
37 * matchBuilder.setMasked(MatchField.BSN_IN_PORTS_128, portBitmap);
38 * </pre>
39 *
Andreas Wundsam28c99752013-10-22 16:51:25 -070040 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
41 */
Andreas Wundsam9539f922013-10-24 13:07:30 -070042@Immutable
Andreas Wundsam9667a162013-10-21 12:58:16 -070043public class OFPortBitMap extends Masked<OFBitMask128> {
Yotam Harchola11f38b2013-09-26 15:38:17 -070044
Andreas Wundsam9667a162013-10-21 12:58:16 -070045 private OFPortBitMap(OFBitMask128 mask) {
Yotam Harchol2c535582013-10-01 15:50:20 -070046 super(OFBitMask128.NONE, mask);
Yotam Harchola11f38b2013-09-26 15:38:17 -070047 }
48
Andreas Wundsam28c99752013-10-22 16:51:25 -070049 /** @return whether or not the given port is logically included in the
50 * match, i.e., whether a packet from in-port <emph>port</emph> be matched by
51 * this OXM.
52 */
Yotam Harchola11f38b2013-09-26 15:38:17 -070053 public boolean isOn(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -070054 // see the implementation note above about the logical inversion of the mask
Yotam Harchol2c535582013-10-01 15:50:20 -070055 return !(this.mask.isOn(port.getPortNumber()));
Yotam Harchola11f38b2013-09-26 15:38:17 -070056 }
57
Andreas Wundsam9667a162013-10-21 12:58:16 -070058 public static OFPortBitMap ofPorts(OFPort... ports) {
Yotam Harchola11f38b2013-09-26 15:38:17 -070059 Builder builder = new Builder();
60 for (OFPort port: ports) {
61 builder.set(port);
62 }
63 return builder.build();
64 }
65
Andreas Wundsam4b98d612013-11-25 18:12:54 -080066 /** @return an OFPortBitmap based on the 'mask' part of an OFBitMask128, as, e.g., returned
67 * by the switch.
68 **/
Andreas Wundsam30b359c2013-11-21 19:27:21 -080069 public static OFPortBitMap of(OFBitMask128 mask) {
70 return new OFPortBitMap(mask);
71 }
72
Andreas Wundsam4b98d612013-11-25 18:12:54 -080073 /** @return iterating over all ports that are logically included in the
74 * match, i.e., whether a packet from in-port <emph>port</emph> be matched by
75 * this OXM.
76 */
Andreas Wundsam30b359c2013-11-21 19:27:21 -080077 public Iterable<OFPort> getOnPorts() {
78 ArrayList<OFPort> ports = new ArrayList<>();
79 for(int i=0; i < 127; i++) {
80 if(!(this.mask.isOn(i))) {
81 ports.add(OFPort.of(i));
82 }
83 }
84 return ports;
85 }
86
Yotam Harchola11f38b2013-09-26 15:38:17 -070087 @Override
Yotam Harchol595c6442013-09-27 16:29:08 -070088 public boolean equals(Object obj) {
Andreas Wundsam9667a162013-10-21 12:58:16 -070089 if (!(obj instanceof OFPortBitMap))
Yotam Harchol595c6442013-09-27 16:29:08 -070090 return false;
Andreas Wundsam9667a162013-10-21 12:58:16 -070091 OFPortBitMap other = (OFPortBitMap)obj;
Yotam Harchol595c6442013-09-27 16:29:08 -070092 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();
Yotam Harchola11f38b2013-09-26 15:38:17 -070098 }
99
100 public static class Builder {
Yotam Harchol2c535582013-10-01 15:50:20 -0700101 private long raw1 = -1, raw2 = -1;
Yotam Harchola11f38b2013-09-26 15:38:17 -0700102
103 public Builder() {
104
105 }
106
Andreas Wundsam28c99752013-10-22 16:51:25 -0700107 /** @return whether or not the given port is logically included in the
108 * match, i.e., whether a packet from in-port <emph>port</emph> be matched by
109 * this OXM.
110 */
Yotam Harchola11f38b2013-09-26 15:38:17 -0700111 public boolean isOn(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -0700112 // see the implementation note above about the logical inversion of the mask
Yotam Harchol2c535582013-10-01 15:50:20 -0700113 return !(OFBitMask128.isBitOn(raw1, raw2, port.getPortNumber()));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700114 }
115
Andreas Wundsam28c99752013-10-22 16:51:25 -0700116 /** remove this port from the match, i.e., packets from this in-port
117 * will NOT be matched.
118 */
Yotam Harchol2c535582013-10-01 15:50:20 -0700119 public Builder unset(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -0700120 // see the implementation note above about the logical inversion of the mask
Yotam Harchola11f38b2013-09-26 15:38:17 -0700121 int bit = port.getPortNumber();
Andreas Wundsam28c99752013-10-22 16:51:25 -0700122 if (bit < 0 || bit > 127)
Yotam Harchola11f38b2013-09-26 15:38:17 -0700123 throw new IndexOutOfBoundsException("Port number is out of bounds");
Andreas Wundsam28c99752013-10-22 16:51:25 -0700124 else if (bit == 127)
125 // the highest order bit in the bitmask is reserved. The switch will
126 // set that bit for all ports >= 127. The reason is that we don't want
127 // the OFPortMap to match all ports out of its range (i.e., a packet
128 // coming in on port 181 would match *any* OFPortMap).
129 throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
130 else if (bit < 64) {
Yotam Harchol595c6442013-09-27 16:29:08 -0700131 raw2 |= ((long)1 << bit);
Yotam Harchola11f38b2013-09-26 15:38:17 -0700132 } else {
Yotam Harchol595c6442013-09-27 16:29:08 -0700133 raw1 |= ((long)1 << (bit - 64));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700134 }
135 return this;
136 }
137
Andreas Wundsam28c99752013-10-22 16:51:25 -0700138 /** add this port from the match, i.e., packets from this in-port
139 * will NOT be matched.
140 */
Yotam Harchol2c535582013-10-01 15:50:20 -0700141 public Builder set(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -0700142 // see the implementation note above about the logical inversion of the mask
Yotam Harchola11f38b2013-09-26 15:38:17 -0700143 int bit = port.getPortNumber();
Andreas Wundsam28c99752013-10-22 16:51:25 -0700144 if (bit < 0 || bit > 127)
Yotam Harchola11f38b2013-09-26 15:38:17 -0700145 throw new IndexOutOfBoundsException("Port number is out of bounds");
Andreas Wundsam28c99752013-10-22 16:51:25 -0700146 else if (bit == 127)
147 // the highest order bit in the bitmask is reserved. The switch will
148 // set that bit for all ports >= 127. The reason is that we don't want
149 // the OFPortMap to match all ports out of its range (i.e., a packet
150 // coming in on port 181 would match *any* OFPortMap).
151 throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
152 else if (bit < 64) {
Yotam Harchol595c6442013-09-27 16:29:08 -0700153 raw2 &= ~((long)1 << bit);
Yotam Harchola11f38b2013-09-26 15:38:17 -0700154 } else {
Yotam Harchol595c6442013-09-27 16:29:08 -0700155 raw1 &= ~((long)1 << (bit - 64));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700156 }
157 return this;
158 }
159
Andreas Wundsam9667a162013-10-21 12:58:16 -0700160 public OFPortBitMap build() {
161 return new OFPortBitMap(OFBitMask128.of(raw1, raw2));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700162 }
163 }
164
165}