blob: 0fae3e653c809c6c0f8cc87b0f7865b732a0412c [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 *
24 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
25 *
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) {
77 return ofVlan(vid.getVlan());
78 }
79
80
81 public static OFVlanVidMatch ofVlan(int vlan) {
82 if( (vlan & VLAN_MASK) != vlan)
83 throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vlan));
84 return ofRawVid( (short) (vlan | PRESENT_VAL));
85 }
86
87 public static OFVlanVidMatch ofVlanOF10(short of10vlan) {
88 if(of10vlan == NONE_VAL) {
89 return NONE;
90 } else if(of10vlan == UNTAGGED_VAL_OF10) {
91 return UNTAGGED;
92 } else {
93 return ofVlan(of10vlan);
94 }
95 }
96
97 /** @return whether or not this VlanId has the present (0x1000) bit set */
98 public boolean isPresentBitSet() {
99 return (vid & PRESENT_VAL) != 0;
100 }
101
102 /** @return the actual VLAN tag this vid identifies */
103 public short getVlan() {
104 return (short) (vid & VLAN_MASK);
105 }
106
107 /** @return the actual vlan tag this vid identifies as a VlanVid object, if this
108 * VlanVidMatch has the present bit set (i.e., identifies a tagged VLAN).
109 * Else, returns null.
110 */
111 @Nullable
112 public VlanVid getVlanVid() {
113 return isPresentBitSet() ? VlanVid.ofVlan((short) (vid & VLAN_MASK)) : null;
114 }
115
116 @Override
117 public boolean equals(Object obj) {
118 if (!(obj instanceof OFVlanVidMatch))
119 return false;
120 OFVlanVidMatch other = (OFVlanVidMatch)obj;
121 if (other.vid != this.vid)
122 return false;
123 return true;
124 }
125
126 @Override
127 public int hashCode() {
128 int prime = 13873;
129 return this.vid * prime;
130 }
131
132 @Override
133 public String toString() {
134 return "0x" + Integer.toHexString(vid);
135 }
136
137 public short getRawVid() {
138 return vid;
139 }
140
141
142 @Override
143 public int getLength() {
144 return LENGTH;
145 }
146
147
Andreas Wundsam4e2469e2014-02-17 15:32:43 -0800148 private volatile byte[] bytesCache = null;
Andreas Wundsam98a18632013-11-05 11:34:24 -0800149
150 public byte[] getBytes() {
151 if (bytesCache == null) {
152 synchronized (this) {
153 if (bytesCache == null) {
154 bytesCache =
155 new byte[] { (byte) ((vid >>> 8) & 0xFF),
156 (byte) ((vid >>> 0) & 0xFF) };
157 }
158 }
159 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800160 return Arrays.copyOf(bytesCache, bytesCache.length);
Andreas Wundsam98a18632013-11-05 11:34:24 -0800161 }
162
163 public void write2Bytes(ChannelBuffer c) {
164 c.writeShort(this.vid);
165 }
166
167 public void write2BytesOF10(ChannelBuffer c) {
168 c.writeShort(this.getVlan());
169 }
170
171 public static OFVlanVidMatch read2Bytes(ChannelBuffer c) throws OFParseError {
172 return OFVlanVidMatch.ofRawVid(c.readShort());
173 }
174
175 public static OFVlanVidMatch read2BytesOF10(ChannelBuffer c) throws OFParseError {
176 return OFVlanVidMatch.ofVlanOF10(c.readShort());
177 }
178
179 @Override
180 public OFVlanVidMatch applyMask(OFVlanVidMatch mask) {
181 return OFVlanVidMatch.ofRawVid((short)(this.vid & mask.vid));
182 }
183
184 @Override
185 public int compareTo(OFVlanVidMatch o) {
186 return Shorts.compare(vid, o.vid);
187 }
188 @Override
189 public void putTo(PrimitiveSink sink) {
190 sink.putShort(vid);
191 }
192}