Merge branch 'master' of github.com:floodlight/loxigen into group_mod

Conflicts:
	java_gen/java_model.py
	loxi_front_end/frontend.py
	loxi_front_end/frontend_ir.py
	loxigen.py
	py_gen/templates/message.py
	utest/test_frontend.py
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index 6e536fa..9ea6d34 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -424,7 +424,7 @@
 
             # Extensions
             experimenter = find_experimenter('of', cls)
-            if experimenter:
+            if experimenter and ofclass.is_subclassof("of_experimenter"):
                 val = find_type_value(ofclass, 'subtype')
                 type_maps.extension_message_subtype[wire_version][experimenter][cls] = val
 
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index bddc642..6068716 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -128,6 +128,11 @@
             m_name == "experimenter" or
             m_name == "subtype")):
         return True
+
+    if (cls in ["of_bsn_lacp_stats_request", "of_bsn_lacp_stats_reply"] and (
+            m_name == "experimenter" or
+            m_name == "subtype")):
+        return True
     return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
 
 def gen_fill_string(out):
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index acc2314..024de52 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -503,6 +503,7 @@
     uint16_t stats_type;
     uint16_t err_type;
     uint8_t flow_mod_cmd;
+    uint32_t experimenter, subtype;
 
     if (length < OF_MESSAGE_MIN_LENGTH) {
         return OF_OBJECT_INVALID;
@@ -541,10 +542,23 @@
             return OF_OBJECT_INVALID;
         }
         stats_type = of_message_stats_type_get(msg);
-        if (obj_id == OF_STATS_REQUEST) {
-            obj_id = of_stats_request_to_object_id(stats_type, ver);
+        if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
+            if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
+                return OF_OBJECT_INVALID;
+            }
+            experimenter = of_message_stats_experimenter_id_get(msg);
+            subtype = of_message_stats_experimenter_subtype_get(msg);
+            if (obj_id == OF_STATS_REQUEST) {
+                obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
+            } else {
+                obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
+            }
         } else {
-            obj_id = of_stats_reply_to_object_id(stats_type, ver);
+            if (obj_id == OF_STATS_REQUEST) {
+                obj_id = of_stats_request_to_object_id(stats_type, ver);
+            } else {
+                obj_id = of_stats_reply_to_object_id(stats_type, ver);
+            }
         }
     }
 
@@ -945,6 +959,9 @@
  * top level message: Action, instruction, error, stats, queue_props, oxm
  */
 #define OF_EXPERIMENTER_TYPE 0xffff
+
+int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
+int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
 """)
     gen_type_to_obj_map_functions(out)
     gen_obj_to_type_map_functions(out)
@@ -1047,6 +1064,17 @@
     if ((type = of_object_to_stats_type(id, ver)) >= 0) {
         /* It's a stats obj */
         of_message_stats_type_set(msg, type);
+        if (type == OF_STATS_TYPE_EXPERIMENTER) {
+            switch (id) {
+            case OF_BSN_LACP_STATS_REQUEST:
+            case OF_BSN_LACP_STATS_REPLY:
+                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
+                of_message_stats_experimenter_subtype_set(msg, 1);
+                break;
+            default:
+                break;
+            }
+        }
     }
     if ((type = of_object_to_error_type(id, ver)) >= 0) {
         /* It's an error obj */
diff --git a/c_gen/templates/of_message.h b/c_gen/templates/of_message.h
index 165fe51..c1b6785 100644
--- a/c_gen/templates/of_message.h
+++ b/c_gen/templates/of_message.h
@@ -58,6 +58,10 @@
 #define OF_MESSAGE_EXPERIMENTER_SUBTYPE_OFFSET 12
 #define OF_MESSAGE_EXPERIMENTER_MIN_LENGTH 16
 
+#define OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET 16
+#define OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET 20
+#define OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH 24
+
 /**
  * The "default" free message function; NULL means use nominal malloc/free
  */
@@ -270,4 +274,42 @@
     }
 }
 
+/**
+ * @brief Get/set stats request/reply experimenter ID of a message
+ * @param msg Pointer to the message buffer of sufficient length
+ * @param experimenter_id Data for set operation
+ * @returns get returns experimenter id in host order
+ */
+
+static inline uint32_t
+of_message_stats_experimenter_id_get(of_message_t msg) {
+    uint32_t val;
+    buf_u32_get(msg + OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET, &val);
+    return val;
+}
+
+static inline void
+of_message_stats_experimenter_id_set(of_message_t msg, uint32_t experimenter_id) {
+    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET, experimenter_id);
+}
+
+/**
+ * @brief Get/set stats request/reply experimenter subtype of a message
+ * @param msg Pointer to the message buffer of sufficient length
+ * @param subtype Data for set operation
+ * @returns get returns experimenter subtype in host order
+ */
+
+static inline uint32_t
+of_message_stats_experimenter_subtype_get(of_message_t msg) {
+    uint32_t val;
+    buf_u32_get(msg + OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET, &val);
+    return val;
+}
+
+static inline void
+of_message_stats_experimenter_subtype_set(of_message_t msg, uint32_t subtype) {
+    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET, subtype);
+}
+
 #endif /* _OF_MESSAGE_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index fabd25f..30c73ac 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -840,3 +840,27 @@
 
     return OF_ERROR_NONE;
 }
+
+int
+of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver)
+{
+    switch (experimenter) {
+    case OF_EXPERIMENTER_ID_BSN:
+        switch (subtype) {
+        case 1: return OF_BSN_LACP_STATS_REQUEST;
+        }
+    }
+    return OF_OBJECT_INVALID;
+}
+
+int
+of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver)
+{
+    switch (experimenter) {
+    case OF_EXPERIMENTER_ID_BSN:
+        switch (subtype) {
+        case 1: return OF_BSN_LACP_STATS_REPLY;
+        }
+    }
+    return OF_OBJECT_INVALID;
+}
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index 909ee79..cf88e35 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"]:
+    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"]:
         return True
     return False
 
@@ -267,7 +267,8 @@
         meter_features = 11,
         table_features = 12,
         port_desc = 13,
-        experimenter = 0xffff
+        experimenter = 0xffff,
+        bsn_lacp = 0xffff
         )
     }
 
@@ -452,7 +453,9 @@
     "of_port_desc_stats_reply",
     "of_queue_stats_reply",
     "of_table_stats_reply",
-    "of_table_features_stats_reply"
+    "of_table_features_stats_reply",
+    "of_bsn_stats_reply",
+    "of_bsn_lacp_stats_reply",
 ]
 
 stats_request_list = [
@@ -470,7 +473,9 @@
     "of_port_desc_stats_request",
     "of_queue_stats_request",
     "of_table_stats_request",
-    "of_table_features_stats_request"
+    "of_table_features_stats_request",
+    "of_bsn_stats_request",
+    "of_bsn_lacp_stats_request",
 ]
 
 flow_mod_list = [