blob: 91c9fc87a9fd71c43aa0ac5399beeebc2356b479 [file] [log] [blame]
Andreas Wundsam98a18632013-11-05 11:34:24 -08001package org.projectfloodlight.openflow.types;
2
Andreas Wundsam5f71b412014-02-18 12:56:35 -08003import java.util.Arrays;
4
Andreas Wundsam98a18632013-11-05 11:34:24 -08005import javax.annotation.Nullable;
6
7import org.jboss.netty.buffer.ChannelBuffer;
8import org.projectfloodlight.openflow.exceptions.OFParseError;
Andreas Wundsambad18452013-11-17 18:19:14 -08009import org.slf4j.Logger;
10import org.slf4j.LoggerFactory;
Andreas Wundsam98a18632013-11-05 11:34:24 -080011
12import com.google.common.hash.PrimitiveSink;
13import com.google.common.primitives.Shorts;
14
15/** Represents an OpenFlow Vlan VID for use in Matches, as specified by the OpenFlow 1.3 spec.
16 *
17 * <b> Note: this is not just the 12-bit vlan tag. OpenFlow defines
18 * the additional mask bits 0x1000 to represent the presence of a vlan
19 * tag. This additional bit will be stripped when writing a OF1.0 value
20 * tag.
21 * </b>
22 *
23 *
kjwon157bc85402015-02-12 15:07:42 +090024 * @author Andreas Wundsam {@literal <}andreas.wundsam@bigswitch.com{@literal >}
Andreas Wundsam98a18632013-11-05 11:34:24 -080025 *
26 */
27public class OFVlanVidMatch implements OFValueType<OFVlanVidMatch> {
Andreas Wundsambad18452013-11-17 18:19:14 -080028 private static final Logger logger = LoggerFactory.getLogger(OFVlanVidMatch.class);
Andreas Wundsam98a18632013-11-05 11:34:24 -080029
30 private static final short VALIDATION_MASK = 0x1FFF;
31 private static final short PRESENT_VAL = 0x1000;
32 private static final short VLAN_MASK = 0x0FFF;
33 private static final short NONE_VAL = 0x0000;
34 private static final short UNTAGGED_VAL_OF13 = (short) 0x0000;
35 private static final short UNTAGGED_VAL_OF10 = (short) 0xFFFF;
36 final static int LENGTH = 2;
37
38 /** presence of a VLAN tag is indicated by the presence of bit 0x1000 */
39 public static final OFVlanVidMatch PRESENT = new OFVlanVidMatch(PRESENT_VAL);
40
41 /** this value means 'not set' in OF1.0 (e.g., in a match). not used elsewhere */
42 public static final OFVlanVidMatch NONE = new OFVlanVidMatch(NONE_VAL);
43
44 /** for use with masking operations */
45 public static final OFVlanVidMatch NO_MASK = new OFVlanVidMatch((short)0xFFFF);
46 public static final OFVlanVidMatch FULL_MASK = NONE;
47
48 /** an untagged packet is specified as 0000 in OF 1.0, but 0xFFFF in OF1.0. Special case that. */
49 public static final OFVlanVidMatch UNTAGGED = new OFVlanVidMatch(NONE_VAL) {
50 @Override
51 public void write2BytesOF10(ChannelBuffer c) {
52 c.writeShort(UNTAGGED_VAL_OF10);
53 }
54 };
55
56 private final short vid;
57
58 private OFVlanVidMatch(short vid) {
59 this.vid = vid;
60 }
61
62 public static OFVlanVidMatch ofRawVid(short vid) {
63 if(vid == UNTAGGED_VAL_OF13)
64 return UNTAGGED;
65 else if(vid == PRESENT_VAL)
66 return PRESENT;
Andreas Wundsambad18452013-11-17 18:19:14 -080067 else if(vid == UNTAGGED_VAL_OF10) {
68 // workaround for IVS sometimes sending 0F1.0 untagged (0xFFFF) values
69 logger.warn("Warning: received OF1.0 untagged vlan value (0xFFFF) in OF1.3 VlanVid. Treating as UNTAGGED");
70 return UNTAGGED;
71 } else if ((vid & VALIDATION_MASK) != vid)
Andreas Wundsam98a18632013-11-05 11:34:24 -080072 throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vid));
73 return new OFVlanVidMatch(vid);
74 }
75
76 public static OFVlanVidMatch ofVlanVid(VlanVid vid) {
Andreas Wundsam4193e5d2014-03-23 09:20:36 -070077 if(vid == null)
78 return UNTAGGED;
79 else if(VlanVid.NO_MASK.equals(vid))
80 // NO_MASK is a special value in that it doesn't fit in the
81 // allowed value space (0x1FFF) of this type. Do a manual conversion
82 return NO_MASK;
83 else
84 return ofVlan(vid.getVlan());
Andreas Wundsam98a18632013-11-05 11:34:24 -080085 }
86
87
88 public static OFVlanVidMatch ofVlan(int vlan) {
89 if( (vlan & VLAN_MASK) != vlan)
90 throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vlan));
91 return ofRawVid( (short) (vlan | PRESENT_VAL));
92 }
93
94 public static OFVlanVidMatch ofVlanOF10(short of10vlan) {
95 if(of10vlan == NONE_VAL) {
96 return NONE;
97 } else if(of10vlan == UNTAGGED_VAL_OF10) {
98 return UNTAGGED;
99 } else {
100 return ofVlan(of10vlan);
101 }
102 }
103
104 /** @return whether or not this VlanId has the present (0x1000) bit set */
105 public boolean isPresentBitSet() {
106 return (vid & PRESENT_VAL) != 0;
107 }
108
109 /** @return the actual VLAN tag this vid identifies */
110 public short getVlan() {
111 return (short) (vid & VLAN_MASK);
112 }
113
114 /** @return the actual vlan tag this vid identifies as a VlanVid object, if this
115 * VlanVidMatch has the present bit set (i.e., identifies a tagged VLAN).
116 * Else, returns null.
117 */
118 @Nullable
119 public VlanVid getVlanVid() {
Andreas Wundsam4193e5d2014-03-23 09:20:36 -0700120 if(this.equals(NO_MASK))
121 return VlanVid.NO_MASK;
122 else if(isPresentBitSet())
123 return VlanVid.ofVlan((short) (vid & VLAN_MASK));
124 else
125 return null;
Andreas Wundsam98a18632013-11-05 11:34:24 -0800126 }
127
128 @Override
129 public boolean equals(Object obj) {
130 if (!(obj instanceof OFVlanVidMatch))
131 return false;
132 OFVlanVidMatch other = (OFVlanVidMatch)obj;
133 if (other.vid != this.vid)
134 return false;
135 return true;
136 }
137
138 @Override
139 public int hashCode() {
140 int prime = 13873;
141 return this.vid * prime;
142 }
143
144 @Override
145 public String toString() {
146 return "0x" + Integer.toHexString(vid);
147 }
148
149 public short getRawVid() {
150 return vid;
151 }
152
153
154 @Override
155 public int getLength() {
156 return LENGTH;
157 }
158
159
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800160 private volatile byte[] bytesCache = null;
Andreas Wundsam98a18632013-11-05 11:34:24 -0800161
162 public byte[] getBytes() {
163 if (bytesCache == null) {
164 synchronized (this) {
165 if (bytesCache == null) {
166 bytesCache =
167 new byte[] { (byte) ((vid >>> 8) & 0xFF),
168 (byte) ((vid >>> 0) & 0xFF) };
169 }
170 }
171 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800172 return Arrays.copyOf(bytesCache, bytesCache.length);
Andreas Wundsam98a18632013-11-05 11:34:24 -0800173 }
174
175 public void write2Bytes(ChannelBuffer c) {
176 c.writeShort(this.vid);
177 }
178
179 public void write2BytesOF10(ChannelBuffer c) {
180 c.writeShort(this.getVlan());
181 }
182
183 public static OFVlanVidMatch read2Bytes(ChannelBuffer c) throws OFParseError {
184 return OFVlanVidMatch.ofRawVid(c.readShort());
185 }
186
187 public static OFVlanVidMatch read2BytesOF10(ChannelBuffer c) throws OFParseError {
188 return OFVlanVidMatch.ofVlanOF10(c.readShort());
189 }
190
191 @Override
192 public OFVlanVidMatch applyMask(OFVlanVidMatch mask) {
193 return OFVlanVidMatch.ofRawVid((short)(this.vid & mask.vid));
194 }
195
196 @Override
197 public int compareTo(OFVlanVidMatch o) {
198 return Shorts.compare(vid, o.vid);
199 }
200 @Override
201 public void putTo(PrimitiveSink sink) {
202 sink.putShort(vid);
203 }
204}