blob: 18ab8b040fc664b7edb8d107575d5b146bfca1b6 [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 Wundsam30b359c2013-11-21 19:27:21 -080066 public static OFPortBitMap of(OFBitMask128 mask) {
67 return new OFPortBitMap(mask);
68 }
69
70 public Iterable<OFPort> getOnPorts() {
71 ArrayList<OFPort> ports = new ArrayList<>();
72 for(int i=0; i < 127; i++) {
73 if(!(this.mask.isOn(i))) {
74 ports.add(OFPort.of(i));
75 }
76 }
77 return ports;
78 }
79
Yotam Harchola11f38b2013-09-26 15:38:17 -070080 @Override
Yotam Harchol595c6442013-09-27 16:29:08 -070081 public boolean equals(Object obj) {
Andreas Wundsam9667a162013-10-21 12:58:16 -070082 if (!(obj instanceof OFPortBitMap))
Yotam Harchol595c6442013-09-27 16:29:08 -070083 return false;
Andreas Wundsam9667a162013-10-21 12:58:16 -070084 OFPortBitMap other = (OFPortBitMap)obj;
Yotam Harchol595c6442013-09-27 16:29:08 -070085 return (other.value.equals(this.value) && other.mask.equals(this.mask));
86 }
87
88 @Override
89 public int hashCode() {
90 return 619 * mask.hashCode() + 257 * value.hashCode();
Yotam Harchola11f38b2013-09-26 15:38:17 -070091 }
92
93 public static class Builder {
Yotam Harchol2c535582013-10-01 15:50:20 -070094 private long raw1 = -1, raw2 = -1;
Yotam Harchola11f38b2013-09-26 15:38:17 -070095
96 public Builder() {
97
98 }
99
Andreas Wundsam28c99752013-10-22 16:51:25 -0700100 /** @return whether or not the given port is logically included in the
101 * match, i.e., whether a packet from in-port <emph>port</emph> be matched by
102 * this OXM.
103 */
Yotam Harchola11f38b2013-09-26 15:38:17 -0700104 public boolean isOn(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -0700105 // see the implementation note above about the logical inversion of the mask
Yotam Harchol2c535582013-10-01 15:50:20 -0700106 return !(OFBitMask128.isBitOn(raw1, raw2, port.getPortNumber()));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700107 }
108
Andreas Wundsam28c99752013-10-22 16:51:25 -0700109 /** remove this port from the match, i.e., packets from this in-port
110 * will NOT be matched.
111 */
Yotam Harchol2c535582013-10-01 15:50:20 -0700112 public Builder unset(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -0700113 // see the implementation note above about the logical inversion of the mask
Yotam Harchola11f38b2013-09-26 15:38:17 -0700114 int bit = port.getPortNumber();
Andreas Wundsam28c99752013-10-22 16:51:25 -0700115 if (bit < 0 || bit > 127)
Yotam Harchola11f38b2013-09-26 15:38:17 -0700116 throw new IndexOutOfBoundsException("Port number is out of bounds");
Andreas Wundsam28c99752013-10-22 16:51:25 -0700117 else if (bit == 127)
118 // the highest order bit in the bitmask is reserved. The switch will
119 // set that bit for all ports >= 127. The reason is that we don't want
120 // the OFPortMap to match all ports out of its range (i.e., a packet
121 // coming in on port 181 would match *any* OFPortMap).
122 throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
123 else if (bit < 64) {
Yotam Harchol595c6442013-09-27 16:29:08 -0700124 raw2 |= ((long)1 << bit);
Yotam Harchola11f38b2013-09-26 15:38:17 -0700125 } else {
Yotam Harchol595c6442013-09-27 16:29:08 -0700126 raw1 |= ((long)1 << (bit - 64));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700127 }
128 return this;
129 }
130
Andreas Wundsam28c99752013-10-22 16:51:25 -0700131 /** add this port from the match, i.e., packets from this in-port
132 * will NOT be matched.
133 */
Yotam Harchol2c535582013-10-01 15:50:20 -0700134 public Builder set(OFPort port) {
Andreas Wundsam28c99752013-10-22 16:51:25 -0700135 // see the implementation note above about the logical inversion of the mask
Yotam Harchola11f38b2013-09-26 15:38:17 -0700136 int bit = port.getPortNumber();
Andreas Wundsam28c99752013-10-22 16:51:25 -0700137 if (bit < 0 || bit > 127)
Yotam Harchola11f38b2013-09-26 15:38:17 -0700138 throw new IndexOutOfBoundsException("Port number is out of bounds");
Andreas Wundsam28c99752013-10-22 16:51:25 -0700139 else if (bit == 127)
140 // the highest order bit in the bitmask is reserved. The switch will
141 // set that bit for all ports >= 127. The reason is that we don't want
142 // the OFPortMap to match all ports out of its range (i.e., a packet
143 // coming in on port 181 would match *any* OFPortMap).
144 throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
145 else if (bit < 64) {
Yotam Harchol595c6442013-09-27 16:29:08 -0700146 raw2 &= ~((long)1 << bit);
Yotam Harchola11f38b2013-09-26 15:38:17 -0700147 } else {
Yotam Harchol595c6442013-09-27 16:29:08 -0700148 raw1 &= ~((long)1 << (bit - 64));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700149 }
150 return this;
151 }
152
Andreas Wundsam9667a162013-10-21 12:58:16 -0700153 public OFPortBitMap build() {
154 return new OFPortBitMap(OFBitMask128.of(raw1, raw2));
Yotam Harchola11f38b2013-09-26 15:38:17 -0700155 }
156 }
157
158}