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