blob: 63b97f324605807fa32929be41f7ff1246d70f1f [file] [log] [blame]
tom0eb04ca2014-08-25 14:34:51 -07001package org.projectfloodlight.openflow.types;
2
3import java.util.ArrayList;
4
5import 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_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.
27 *
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 *
40 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
41 */
42@Immutable
43public class OFPortBitMap extends Masked<OFBitMask128> {
44
45 private OFPortBitMap(OFBitMask128 mask) {
46 super(OFBitMask128.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 <emph>port</emph> 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 OFPortBitMap 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 OFBitMask128, as, e.g., returned
67 * by the switch.
68 **/
69 public static OFPortBitMap of(OFBitMask128 mask) {
70 return new OFPortBitMap(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 <emph>port</emph> be matched by
75 * this OXM.
76 */
77 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
87 @Override
88 public boolean equals(Object obj) {
89 if (!(obj instanceof OFPortBitMap))
90 return false;
91 OFPortBitMap other = (OFPortBitMap)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;
102
103 public Builder() {
104
105 }
106
107 /** @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 */
111 public boolean isOn(OFPort port) {
112 // see the implementation note above about the logical inversion of the mask
113 return !(OFBitMask128.isBitOn(raw1, raw2, port.getPortNumber()));
114 }
115
116 /** remove this port from the match, i.e., packets from this in-port
117 * will NOT be matched.
118 */
119 public Builder unset(OFPort port) {
120 // see the implementation note above about the logical inversion of the mask
121 int bit = port.getPortNumber();
122 if (bit < 0 || bit > 127)
123 throw new IndexOutOfBoundsException("Port number is out of bounds");
124 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) {
131 raw2 |= ((long)1 << bit);
132 } else {
133 raw1 |= ((long)1 << (bit - 64));
134 }
135 return this;
136 }
137
138 /** add this port from the match, i.e., packets from this in-port
139 * will NOT be matched.
140 */
141 public Builder set(OFPort port) {
142 // see the implementation note above about the logical inversion of the mask
143 int bit = port.getPortNumber();
144 if (bit < 0 || bit > 127)
145 throw new IndexOutOfBoundsException("Port number is out of bounds");
146 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) {
153 raw2 &= ~((long)1 << bit);
154 } else {
155 raw1 &= ~((long)1 << (bit - 64));
156 }
157 return this;
158 }
159
160 public OFPortBitMap build() {
161 return new OFPortBitMap(OFBitMask128.of(raw1, raw2));
162 }
163 }
164
165}