Merge branch 'master' of github.com:floodlight/loxigen
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index 9ea6d34..46aedda 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -403,6 +403,9 @@
                 if wire_version >= of_g.VERSION_1_3:
                     cls2 = parent + "_id" + cls[len(parent):]
                     type_maps.extension_action_id_subtype[wire_version][experimenter][cls2] = val
+            elif parent == 'of_instruction' and experimenter:
+                val = find_type_value(ofclass, 'subtype')
+                type_maps.extension_instruction_subtype[wire_version][experimenter][cls] = val
 
     # Messages
     for version, protocol in loxi_globals.ir.items():
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 1106f2d..e2bb467 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -2729,7 +2729,8 @@
             # Some tlv16 types may be extensions requiring more work
             if cls in ["of_action_bsn_mirror", "of_action_id_bsn_mirror",
                        "of_action_bsn_set_tunnel_dst", "of_action_id_bsn_set_tunnel_dst",
-                       "of_action_nicira_dec_ttl", "of_action_id_nicira_dec_ttl"]:
+                       "of_action_nicira_dec_ttl", "of_action_id_nicira_dec_ttl",
+                       "of_instruction_bsn_disable_src_mac_check"]:
                 out.write("""
     /* Extended TLV obj; Call specific accessor */
     of_extension_object_id_set(obj, %(enum)s);
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 30c73ac..a48bdf8 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -37,6 +37,9 @@
 #include <loci/loci.h>
 #include <loci/of_message.h>
 
+#define OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET 4
+#define OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET 8
+
 /****************************************************************
  * Top level OpenFlow message length functions
  ****************************************************************/
@@ -207,8 +210,6 @@
 
 /**
  * Set wire data for extension objects, not messages.
- *
- * Currently only handles BSN mirror; ignores all others
  */
 
 void
@@ -235,6 +236,11 @@
                     OF_EXPERIMENTER_ID_NICIRA);
         buf_u16_set(buf + OF_ACTION_EXPERIMENTER_SUBTYPE_OFFSET, 18);
         break;
+    case OF_INSTRUCTION_BSN_DISABLE_SRC_MAC_CHECK:
+        buf_u32_set(buf + OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET,
+                    OF_EXPERIMENTER_ID_BSN);
+        buf_u32_set(buf + OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET, 0);
+        break;
     default:
         break;
     }
@@ -339,10 +345,26 @@
 static int
 extension_instruction_object_id_get(of_object_t *obj, of_object_id_t *id)
 {
-    (void)obj;
+    uint32_t exp_id;
+    uint8_t *buf;
 
     *id = OF_INSTRUCTION_EXPERIMENTER;
 
+    buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
+
+    buf_u32_get(buf + OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET, &exp_id);
+
+    switch (exp_id) {
+    case OF_EXPERIMENTER_ID_BSN: {
+        uint32_t subtype;
+        buf_u32_get(buf + OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET, &subtype);
+        switch (subtype) {
+        case 0: *id = OF_INSTRUCTION_BSN_DISABLE_SRC_MAC_CHECK; break;
+        }
+        break;
+    }
+    }
+
     return OF_ERROR_NONE;
 }
 
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index cf88e35..480eb29 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -156,7 +156,7 @@
     if loxi_utils.class_is_list(cls):
         return True
     # TODO get this from the input file when we have virtual class syntax
-    if cls in ["of_flow_mod", "of_stats_request", "of_stats_reply", "of_error_msg", "of_bsn_header", "of_nicira_header", "of_action_bsn", "of_action_nicira", "of_action_id_bsn", "of_action_id_nicira", "of_bsn_stats_request", "of_bsn_stats_reply", "of_experimenter_stats_request", "of_experimenter_stats_reply"]:
+    if cls in ["of_flow_mod", "of_stats_request", "of_stats_reply", "of_error_msg", "of_bsn_header", "of_nicira_header", "of_action_bsn", "of_action_nicira", "of_action_id_bsn", "of_action_id_nicira", "of_bsn_stats_request", "of_bsn_stats_reply", "of_experimenter_stats_request", "of_experimenter_stats_reply", "of_instruction_experimenter", "of_instruction_bsn"]:
         return True
     return False
 
@@ -597,7 +597,18 @@
 }
 
 # Set to empty dict if no extension instructions defined
-extension_instruction_subtype = {}
+extension_instruction_subtype = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:dict(
+        bsn = {   # of_instruction_bsn_
+            },
+        nicira = {   # of_instruction_nicira_
+            }
+        ),
+}
 
 # Set to empty dict if no extension instructions defined
 extension_queue_prop_subtype = {}
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index f90c1f2..8f5434e 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -65,7 +65,8 @@
         OFExperimenter=set(('data','subtype')),
         OFActionExperimenter=set(('data',)),
         OFExperimenterStatsRequest=set(('data','subtype')),
-        OFExperimenterStatsReply=set(('data','subtype')))
+        OFExperimenterStatsReply=set(('data','subtype')),
+        OFInstructionExperimenter=set(('data',)))
     # map: $java_type -> set(java_name_property)
     write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
     # interfaces that are virtual
@@ -469,6 +470,13 @@
                 return ("action", "OFActionExperimenter", None)
             else:
                 return ("action", "OFAction", None)
+        elif self.ir_class.is_instruction:
+            if self.ir_class.is_subclassof('of_instruction_bsn'):
+                return ("instruction", "OFInstructionBsn", None)
+            elif self.ir_class.is_subclassof('of_instruction_experimenter'):
+                return ("instruction", "OFInstructionExperimenter", None)
+            else:
+                return ("instruction", "OFInstruction", None)
         elif re.match(r'OFBsnVport.+$', self.name):
             return ("", "OFBsnVport", None)
         elif self.name == "OFOxm":
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index d1a9e67..eca00e7 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -597,10 +597,10 @@
         'of_action_push_mpls': { 'ethertype': eth_type },
         'of_action_push_pbb': { 'ethertype': eth_type },
         'of_action_push_vlan': { 'ethertype': eth_type },
+        'of_action_pop_mpls': { 'ethertype': eth_type },
         'of_action_set_nw_dst': { 'nw_addr': ipv4 },
         'of_action_set_nw_ecn': { 'nw_ecn': ip_ecn },
         'of_action_set_nw_src': { 'nw_addr': ipv4 },
-        'of_action_set_nw_dst': { 'tp_port': transport_port },
         'of_action_set_tp_dst': { 'tp_port': transport_port },
         'of_action_set_tp_src': { 'tp_port': transport_port },
         'of_action_set_vlan_pcp': { 'vlan_pcp': vlan_pcp },
diff --git a/java_gen/pre-written/pom.xml b/java_gen/pre-written/pom.xml
index 9845e87..0cb42ac 100644
--- a/java_gen/pre-written/pom.xml
+++ b/java_gen/pre-written/pom.xml
@@ -46,6 +46,12 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-integration</artifactId>
+            <version>1.3</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.netty</groupId>
             <artifactId>netty</artifactId>
             <version>3.2.9.Final</version>
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java
index 051d573..93f5a2d 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java
@@ -22,7 +22,7 @@
         this.raw2 = raw2;
     }
 
-    static OFBitMask128 of(long raw1, long raw2) {
+    public static OFBitMask128 of(long raw1, long raw2) {
         if (raw1 == -1 && raw2 == -1)
             return ALL;
         if (raw1 == 0 && raw2 == 0)
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
index fc214e5..4db84f1 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
@@ -1,24 +1,18 @@
 package org.projectfloodlight.openflow.types;
 
-import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.Matchers.contains;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertThat;
 import junit.framework.TestCase;
 
 import org.junit.Test;
 
-import com.google.common.collect.ImmutableList;
-
 public class OFPortBitMapTest extends TestCase {
     @Test
     public void testCreateAndIterate() {
         OFPortBitMap map = OFPortBitMap.ofPorts(OFPort.of(1), OFPort.of(2), OFPort.of(5));
 
-        assertThat(
-                ImmutableList.copyOf(map.getOnPorts()),
-                equalTo(
-                   ImmutableList.of(OFPort.of(1), OFPort.of(2), OFPort.of(5))
-                ));
+        assertThat(map.getOnPorts(), contains(OFPort.of(1), OFPort.of(2), OFPort.of(5)));
     }
 
     @Test
@@ -27,11 +21,7 @@
 
         OFPortBitMap map = OFPortBitMap.of(bitmap);
 
-        assertThat(
-                ImmutableList.copyOf(map.getOnPorts()),
-                equalTo(
-                   ImmutableList.of(OFPort.of(1), OFPort.of(2), OFPort.of(5))
-                ));
+        assertThat(map.getOnPorts(), contains(OFPort.of(1), OFPort.of(2), OFPort.of(5)));
     }
 
     @Test
diff --git a/java_gen/templates/unit_test.java b/java_gen/templates/unit_test.java
index ad2c3b8..cf01429 100644
--- a/java_gen/templates/unit_test.java
+++ b/java_gen/templates/unit_test.java
@@ -46,7 +46,8 @@
     //:: factory = java_model.model.factory_of(test.interface)
     //:: var_type = msg.interface.name
     //:: var_name = msg.interface.variable_name
-    //:: builder_method = factory.method_name(msg.interface)
+    //:: use_builder = len(msg.data_members) > 0
+    //:: factory_method = factory.method_name(msg.interface, builder=use_builder)
     //:: factory_impl = java_model.model.factory_of(test.interface).of_version(test.java_class.version).name
     ${factory.name if factory.name is not None else "OFFactory"} factory;
 
@@ -61,9 +62,13 @@
     //:: if "java" in test_data:
     @Test
     public void testWrite() {
-        ${var_type}.Builder builder = factory.${builder_method}();
+        //:: if use_builder:
+        ${var_type}.Builder builder = factory.${factory_method}();
         ${test_data["java"]};
         ${var_type} ${var_name} = builder.build();
+        //:: else:
+        ${var_type} ${var_name} = factory.${factory_method}();
+        //:: #endif
         ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
         ${var_name}.writeTo(bb);
         byte[] written = new byte[bb.readableBytes()];
@@ -74,9 +79,13 @@
 
     @Test
     public void testRead() throws Exception {
-        ${var_type}.Builder builder = factory.${builder_method}();
+        //:: if use_builder:
+        ${var_type}.Builder builder = factory.${factory_method}();
         ${test_data["java"]};
         ${var_type} ${var_name}Built = builder.build();
+        //:: else:
+        ${var_type} ${var_name}Built = factory.${factory_method}();
+        //:: #endif
 
         ChannelBuffer input = ChannelBuffers.copiedBuffer(${msg.constant_name}_SERIALIZED);
 
diff --git a/openflow_input/bsn-1.3 b/openflow_input/bsn-1.3
new file mode 100644
index 0000000..f9340b4
--- /dev/null
+++ b/openflow_input/bsn-1.3
@@ -0,0 +1,37 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+
+#version 4
+
+// BSN extension instruction
+struct of_instruction_bsn : of_instruction_experimenter {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == ?;
+    pad(4);
+};
diff --git a/openflow_input/bsn_disable_src_mac_check b/openflow_input/bsn_disable_src_mac_check
new file mode 100644
index 0000000..f75c237
--- /dev/null
+++ b/openflow_input/bsn_disable_src_mac_check
@@ -0,0 +1,40 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+//
+// Also derived from the OpenFlow header files which have these copyrights:
+// Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+// Copyright (c) 2011, 2012 Open Networking Foundation
+
+#version 4
+
+struct of_instruction_bsn_disable_src_mac_check : of_instruction_bsn {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 0;
+    pad(4);
+};
diff --git a/py_gen/templates/instruction.py b/py_gen/templates/instruction.py
index 978e38b..2817625 100644
--- a/py_gen/templates/instruction.py
+++ b/py_gen/templates/instruction.py
@@ -54,16 +54,42 @@
 
 :: #endfor
 
+def parse_experimenter(reader):
+    experimenter, = reader.peek("!4xL")
+    if experimenter == 0x005c16c7: # Big Switch Networks
+        subtype, = reader.peek("!8xL")
+    else:
+        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
+
+    if subtype in experimenter_parsers[experimenter]:
+        return experimenter_parsers[experimenter][subtype](reader)
+    else:
+        raise loxi.ProtocolError("unexpected experimenter id %#x subtype %#x" % (experimenter, subtype))
+
 parsers = {
 :: sort_key = lambda x: x.type_members[0].value
 :: msgtype_groups = itertools.groupby(sorted(ofclasses, key=sort_key), sort_key)
 :: for (k, v) in msgtype_groups:
 :: k = util.constant_for_value(version, "ofp_instruction_type", k)
 :: v = list(v)
-:: if len(v) == 1:
+:: if len(v) == 1 and k != 'const.OFPIT_EXPERIMENTER':
     ${k} : ${v[0].pyname}.unpack,
 :: else:
     ${k} : parse_${k[12:].lower()},
 :: #endif
 :: #endfor
 }
+
+:: experimenter_ofclasses = [x for x in ofclasses if x.type_members[0].value == 0xffff]
+:: sort_key = lambda x: x.type_members[1].value
+:: experimenter_ofclasses.sort(key=sort_key)
+:: grouped = itertools.groupby(experimenter_ofclasses, sort_key)
+experimenter_parsers = {
+:: for (experimenter, v) in grouped:
+    ${experimenter} : {
+:: for ofclass in v:
+        ${ofclass.type_members[2].value}: ${ofclass.pyname}.unpack,
+:: #endfor
+    },
+:: #endfor
+}
diff --git a/test_data/of13/instruction_bsn_disable_src_mac_check.data b/test_data/of13/instruction_bsn_disable_src_mac_check.data
new file mode 100644
index 0000000..6001fde
--- /dev/null
+++ b/test_data/of13/instruction_bsn_disable_src_mac_check.data
@@ -0,0 +1,11 @@
+-- binary
+ff ff # type
+00 10 # length
+00 5c 16 c7 # experimenter
+00 00 00 00 # subtype
+00 00 00 00 # pad
+-- python
+ofp.instruction.bsn_disable_src_mac_check()
+-- java
+-- c
+obj = of_instruction_bsn_disable_src_mac_check_new(OF_VERSION_1_3);