blob: c85c750ec6e6a1ef8a494c54eaf1ed138140ecf6 [file] [log] [blame]
Shudong Zhoue44abfd2015-06-03 21:32:07 -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_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&lt;OFBitMask512&gt;.
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
43public 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 Zhouc2d70892015-06-04 09:42:15 -0700128 // set that bit for all ports >= 511. The reason is that we don't want
Shudong Zhoue44abfd2015-06-03 21:32:07 -0700129 // the OFPortMap to match all ports out of its range (i.e., a packet
Shudong Zhouc2d70892015-06-04 09:42:15 -0700130 // coming in on port 581 would match *any* OFPortMap).
Shudong Zhoue44abfd2015-06-03 21:32:07 -0700131 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 Zhouc2d70892015-06-04 09:42:15 -0700162 // set that bit for all ports >= 511. The reason is that we don't want
Shudong Zhoue44abfd2015-06-03 21:32:07 -0700163 // the OFPortMap to match all ports out of its range (i.e., a packet
Shudong Zhouc2d70892015-06-04 09:42:15 -0700164 // coming in on port 581 would match *any* OFPortMap).
Shudong Zhoue44abfd2015-06-03 21:32:07 -0700165 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}