VlanVid: fix special case handling (untagged+present)

OF1.0 and OF1.3 differ in the magic values they assign to matching
untagged packets (OF1.0: 0xFFFF, OF1.3: 0x0000), and the presence
of the OFPVID_PRESENT flag (0x1000) in OF1.3. This change attempts
to handle these changes in a transparent way for the OF1.0 and OF1.3
line protocols.

Internally, the class uses the OF1.3 representation.
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 410a1dd..f555b56 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -140,7 +140,7 @@
 class JavaModel(object):
     # registry for enums that should not be generated
     # set(${java_enum_name})
-    enum_blacklist = set(("OFDefinitions", "OFPortNo",))
+    enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId"))
     # registry for enum *entry* that should not be generated
     # map: ${java_enum_name} -> set(${java_entry_entry_name})
     enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 6acdb83..83c56b4 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -324,9 +324,9 @@
             write="$name.write2Bytes(bb)",
             default="EthType.NONE")
 vlan_vid = JType("VlanVid")\
-        .op(read="VlanVid.read2Bytes(bb)",
-            write="$name.write2Bytes(bb)",
-            default="VlanVid.NONE")
+        .op(version=1, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
+        .op(version=2, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
+        .op(version=ANY, read="VlanVid.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="VlanVid.NONE")
 vlan_pcp = JType("VlanPcp")\
         .op(read="VlanPcp.readByte(bb)",
             write="$name.writeByte(bb)",
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
index d6f65d5..6bd7581 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
@@ -5,15 +5,45 @@
 
 import com.google.common.primitives.Shorts;
 
+/** Represents an OpenFlow Vlan VID, as specified by the OpenFlow 1.3 spec.
+ *
+ *  <b> Note: this is not just the 12-bit vlan tag. OpenFlow defines
+ *      the additional mask bits 0x1000 to represent the presence of a vlan
+ *      tag. This additional bit will be stripped when writing a OF1.0 value
+ *      tag.
+ *  </b>
+ *
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ *
+ */
 public class VlanVid implements OFValueType<VlanVid> {
 
-    private static final short VALIDATION_MASK = 0x0FFF;
+    private static final short VALIDATION_MASK = 0x1FFF;
+    private static final short PRESENT_VAL = 0x1000;
+    private static final short VLAN_MASK = 0x0FFF;
     private static final short NONE_VAL = 0x0000;
+    private static final short UNTAGGED_VAL_OF13 = (short) 0x0000;
+    private static final short UNTAGGED_VAL_OF10 = (short) 0xFFFF;
     final static int LENGTH = 2;
 
+    /** presence of a VLAN tag is idicated by the presence of bit 0x1000 */
+    public static final VlanVid PRESENT = new VlanVid(PRESENT_VAL);
+
+    /** this value means 'not set' in OF1.0 (e.g., in a match). not used elsewhere */
     public static final VlanVid NONE = new VlanVid(NONE_VAL);
+
+    /** for use with masking operations */
     public static final VlanVid NO_MASK = new VlanVid((short)0xFFFF);
-    public static final VlanVid FULL_MASK = VlanVid.of((short)0x0);
+    public static final VlanVid FULL_MASK = NONE;
+
+    /** an untagged packet is specified as 0000 in OF 1.0, but 0xFFFF in OF1.0. Special case that. */
+    public static final VlanVid UNTAGGED = new VlanVid(NONE_VAL) {
+        @Override
+        public void write2BytesOF10(ChannelBuffer c) {
+            c.writeShort(UNTAGGED_VAL_OF10);
+        }
+    };
 
     private final short vid;
 
@@ -21,14 +51,42 @@
         this.vid = vid;
     }
 
-    public static VlanVid of(short vid) {
-        if(vid == NONE_VAL)
-            return NONE;
+    public static VlanVid ofRawVid(short vid) {
+        if(vid == UNTAGGED_VAL_OF13)
+            return UNTAGGED;
+        else if(vid == PRESENT_VAL)
+            return PRESENT;
         else if ((vid & VALIDATION_MASK) != vid)
-            throw new IllegalArgumentException("Illegal VLAN VID value: " + vid);
+            throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vid));
         return new VlanVid(vid);
     }
 
+    public static VlanVid ofVlan(int vlan) {
+        if( (vlan & VLAN_MASK) != vlan)
+            throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vlan));
+        return ofRawVid( (short) (vlan | PRESENT_VAL));
+    }
+
+    public static VlanVid ofVlanOF10(short of10vlan) {
+        if(of10vlan == NONE_VAL) {
+            return NONE;
+        } else if(of10vlan == UNTAGGED_VAL_OF10) {
+            return UNTAGGED;
+        } else {
+            return ofVlan(of10vlan);
+        }
+    }
+
+    /** @return whether or not this VlanId has the present (0x1000) bit set */
+    public boolean isPresentBitSet() {
+       return (vid & PRESENT_VAL) != 0;
+    }
+
+    /** @return the actual VLAN tag this vid identifies */
+    public short getVlan() {
+        return (short) (vid & VLAN_MASK);
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof VlanVid))
@@ -50,10 +108,11 @@
         return "0x" + Integer.toHexString(vid);
     }
 
-    public short getValue() {
+    public short getRawVid() {
         return vid;
     }
 
+
     @Override
     public int getLength() {
         return LENGTH;
@@ -79,13 +138,21 @@
         c.writeShort(this.vid);
     }
 
+    public void write2BytesOF10(ChannelBuffer c) {
+        c.writeShort(this.getVlan());
+    }
+
     public static VlanVid read2Bytes(ChannelBuffer c) throws OFParseError {
-        return VlanVid.of(c.readShort());
+        return VlanVid.ofRawVid(c.readShort());
+    }
+
+    public static VlanVid read2BytesOF10(ChannelBuffer c) throws OFParseError {
+        return VlanVid.ofVlanOF10(c.readShort());
     }
 
     @Override
     public VlanVid applyMask(VlanVid mask) {
-        return VlanVid.of((short)(this.vid & mask.vid));
+        return VlanVid.ofRawVid((short)(this.vid & mask.vid));
     }
 
     @Override
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVidWithMask.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVidWithMask.java
new file mode 100644
index 0000000..cb81d31
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVidWithMask.java
@@ -0,0 +1,11 @@
+package org.projectfloodlight.openflow.types;
+
+public class VlanVidWithMask extends Masked<VlanVid> {
+    private VlanVidWithMask(VlanVid value, VlanVid mask) {
+        super(value, mask);
+    }
+
+    /* a combination of Vlan Vid and mask that matches any tagged packet */
+    public final static VlanVidWithMask ANY_TAGGED = new VlanVidWithMask(VlanVid.PRESENT, VlanVid.PRESENT);
+
+}