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