Merge pull request #337 from rlane/of14

Expand standard-1.4 input file
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index dacc8bf..db7ca28 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -101,6 +101,7 @@
         of_match_t="match",
         of_oxm_header_t="oxm",
         of_bsn_vport_header_t="bsn_vport",
+        of_table_desc_t="table_desc",
         # BSN extensions
         of_bsn_vport_q_in_q_t="vport",
         of_bitmap_128_t="bitmap_128",
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 17f63ca..36ad5f6 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -73,6 +73,9 @@
 extern void of_queue_stats_entry_wire_length_get(of_object_t *obj, int *bytes);
 extern void of_queue_stats_entry_wire_length_set(of_object_t *obj, int bytes);
 
+extern void of_queue_desc_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_queue_desc_wire_length_set(of_object_t *obj, int bytes);
+
 """)
 
 
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index dba3d53..f480453 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -201,6 +201,7 @@
 special_length_classes = set([
     'of_packet_queue', 'of_meter_stats', 'of_port_desc',
     'of_port_stats_entry', 'of_queue_stats_entry',
+    'of_queue_desc',
 ])
 
 def build_class_metadata():
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 8847515..3fcf024 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -443,3 +443,35 @@
         LOCI_ASSERT(obj->length == OF_OBJECT_FIXED_LENGTH(obj));
     }
 }
+
+/**
+ * Get the wire length for a queue_desc object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ */
+void
+of_queue_desc_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 8), &u16);
+    *bytes = u16;
+}
+
+/**
+ * Set the wire length for a queue_desc object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ */
+
+void
+of_queue_desc_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 8), bytes);
+}
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index e0f0680..294f5f0 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -525,6 +525,10 @@
 
 generic_t = JType("T")
 
+table_desc = JType('OFTableDesc') \
+        .op(read='OFTableDescVer$version.READER.readFrom(bb)', \
+            write='$name.writeTo(bb)')
+
 
 default_mtype_to_jtype_convert_map = {
         'uint8_t' : u8,
@@ -561,6 +565,7 @@
         'of_bitmap_128_t': port_bitmap,
         'of_checksum_128_t': u128,
         'of_bsn_vport_t': bsn_vport,
+        'of_table_desc_t': table_desc,
         }
 
 ## Map that defines exceptions from the standard loxi->java mapping scheme
diff --git a/openflow_input/standard-1.4 b/openflow_input/standard-1.4
index 9b923af..23e96ed 100644
--- a/openflow_input/standard-1.4
+++ b/openflow_input/standard-1.4
@@ -101,7 +101,7 @@
     OFPT_METER_MOD = 29,
     OFPT_ROLE_STATUS = 30,
     OFPT_TABLE_STATUS = 31,
-    OFPT_REQUESTFORWARD = 32, 
+    OFPT_REQUESTFORWARD = 32,
     OFPT_BUNDLE_CONTROL = 33,
     OFPT_BUNDLE_ADD_MESSAGE = 34,
 };
@@ -645,6 +645,60 @@
     OFPHET_VERSIONBITMAP = 1,
 };
 
+enum ofp_optical_port_features(wire_type=uint32_t, bitmask=True) {
+    OFPOPF_RX_TUNE = 0x1,
+    OFPOPF_TX_TUNE = 0x2,
+    OFPOPF_TX_PWR = 0x4,
+    OFPOPF_USE_FREQ = 0x8,
+};
+
+enum ofp_table_mod_prop_eviction_flag(wire_type=uint32_t, bitmask=True) {
+    OFPTMPEF_OTHER = 0x1,
+    OFPTMPEF_IMPORTANCE = 0x2,
+    OFPTMPEF_LIFETIME = 0x4,
+};
+
+enum ofp_port_stats_optical_flags(wire_type=uint32_t, bitmask=True) {
+    OFPOSF_RX_TUNE = 0x1,
+    OFPOSF_TX_TUNE = 0x2,
+    OFPOSF_TX_PWR = 0x4,
+    OFPOSF_RX_PWR = 0x10,
+    OFPOSF_TX_BIAS = 0x20,
+    OFPOSF_TX_TEMP = 0x40,
+};
+
+enum ofp_bundle_ctrl_type(wire_type=uint16_t) {
+    OFPBCT_OPEN_REQUEST = 0,
+    OFPBCT_OPEN_REPLY = 1,
+    OFPBCT_CLOSE_REQUEST = 2,
+    OFPBCT_CLOSE_REPLY = 3,
+    OFPBCT_COMMIT_REQUEST = 4,
+    OFPBCT_COMMIT_REPLY = 5,
+    OFPBCT_DISCARD_REQUEST = 6,
+    OFPBCT_DISCARD_REPLY = 7,
+};
+
+enum ofp_bundle_flags(wire_type=uint16_t, bitmask=True) {
+    OFPBF_ATOMIC = 1,
+    OFPBF_ORDERED = 2,
+};
+
+enum ofp_controller_role_reason(wire_type=uint8_t) {
+    OFPCRR_MASTER_REQUEST = 0,
+    OFPCRR_CONFIG = 1,
+    OFPCRR_EXPERIMENTER = 2,
+};
+
+enum ofp_table_reason(wire_type=uint8_t) {
+    OFPTR_VACANCY_DOWN = 3,
+    OFPTR_VACANCY_UP = 4,
+};
+
+enum ofp_requestforward_reason {
+    OFPRFR_GROUP_MOD = 0,
+    OFPRFR_METER_MOD = 1,
+};
+
 /* XXX rename to of_message */
 struct of_header {
     uint8_t version;
@@ -756,6 +810,28 @@
     uint16_t length; /* Length in bytes of this property. */
 };
 
+struct of_table_mod_prop_eviction {
+    uint16_t type == 2;
+    uint16_t length;
+    enum ofp_table_mod_prop_eviction_flag flags;
+};
+
+struct of_table_mod_prop_vacancy {
+    uint16_t type == 3;
+    uint16_t length;
+    uint8_t vacancy_down;
+    uint8_t vacancy_up;
+    uint8_t vacancy;
+    pad(1);
+};
+
+struct of_table_mod_prop_experimenter {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
 struct of_table_mod : of_header {
     uint8_t version;
     uint8_t type == 17;
@@ -784,11 +860,33 @@
     uint32_t max_speed;
 };
 
+struct of_port_desc_prop_optical : of_port_desc_prop {
+    uint16_t type == 1;
+    uint16_t length;
+    pad(4);
+    uint32_t supported;
+    uint32_t tx_min_freq_lmda;
+    uint32_t tx_max_freq_lmda;
+    uint32_t tx_grid_freq_lmda;
+    uint32_t rx_min_freq_lmda;
+    uint32_t rx_max_freq_lmda;
+    uint32_t rx_grid_freq_lmda;
+    uint32_t tx_pwr_min;
+    uint32_t tx_pwr_max;
+};
+
+struct of_port_desc_prop_experimenter : of_port_desc_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
 struct of_port_desc {
     of_port_no_t port_no;
     uint16_t length;
     pad(2);
-    of_mac_addr_t hw_addr;    
+    of_mac_addr_t hw_addr;
     pad(2);
     of_port_name_t name;
     enum ofp_port_config config; /* Bitmap of OFPPC_* flags. */
@@ -848,6 +946,13 @@
     uint32_t tx_pwr;
 };
 
+struct of_port_mod_prop_experimenter : of_port_mod_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
 struct of_port_mod : of_header {
     uint8_t version;
     uint8_t type == 16;
@@ -868,7 +973,7 @@
     list(of_oxm_t) oxm_list;
 };
 
-// This looks like an action header, but is standalone.  See 
+// This looks like an action header, but is standalone.  See
 // ofp_table_features_prop_actions
 struct of_action_id {
     uint16_t type;
@@ -1130,7 +1235,7 @@
     of_port_no_t out_port;
     uint32_t out_group;
     enum ofp_flow_mod_flags flags;
-    uint16_t importance;    
+    uint16_t importance;
     of_match_t match;
     list(of_instruction_t) instructions;
 };
@@ -1259,7 +1364,7 @@
     uint64_t cookie;
     of_match_t match;
     pad(2);
-    of_octets_t data; /* FIXME: Ensure total_len gets updated */
+    of_octets_t data;
 };
 
 struct of_flow_removed : of_header {
@@ -1538,12 +1643,12 @@
 
     uint32_t flags;       
     uint32_t tx_freq_lmda;
-    uint32_t tx_offset;  
+    uint32_t tx_offset;
     uint32_t tx_grid_span;
     uint32_t rx_freq_lmda;
     uint32_t rx_offset;
     uint32_t rx_grid_span;
-    uint16_t tx_pwr; 
+    uint16_t tx_pwr;
     uint16_t rx_pwr;
     uint16_t bias_current;
     uint16_t temperature;
@@ -1552,7 +1657,7 @@
 /* Experimenter port stats property. */
 struct of_port_stats_prop_experimenter : of_port_stats_prop {
     uint16_t         type == 0xffff;
-    uint16_t         length; 
+    uint16_t         length;
     uint32_t         experimenter == ?;
     uint32_t         exp_type;
     of_octets_t      experimenter_data;
@@ -1580,18 +1685,23 @@
     uint16_t         length;
 };
 
+struct of_queue_stats_prop_experimenter : of_queue_stats_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
 struct of_queue_stats_entry {
-    uint16_t length;  
-    pad(6);         
+    uint16_t length;
+    pad(6);
     of_port_no_t port_no;
-    uint32_t queue_id;  
-    uint64_t tx_bytes; 
+    uint32_t queue_id;
+    uint64_t tx_bytes;
     uint64_t tx_packets;
     uint64_t tx_errors;
     uint32_t duration_sec;
     uint32_t duration_nsec;
-                          
-
     list(of_queue_stats_prop_t) properties;
 };
 
@@ -1621,7 +1731,7 @@
     list(of_bucket_t) buckets;
 };
 
-// STATS: 
+// STATS:
 //  Desc, flow, agg, table, port, queue, group, group_desc, group_feat, experi
 
 struct of_stats_request : of_header {
@@ -1867,6 +1977,12 @@
     list(of_uint32_t) oxm_ids;
 };
 
+struct of_table_feature_prop_table_sync_from : of_table_feature_prop {
+    uint16_t         type == 16;
+    uint16_t         length;
+    list(of_uint8_t) table_ids;
+};
+
 struct of_table_feature_prop_experimenter : of_table_feature_prop {
     uint16_t         type == 65534;
     uint16_t         length;
@@ -2140,6 +2256,96 @@
     list(of_port_desc_t) entries;
 };
 
+struct of_table_desc_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 14;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_table_desc {
+    uint16_t length;
+    uint8_t table_id;
+    pad(1);
+    enum ofp_table_config config;
+};
+
+struct of_table_desc_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 14;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_table_desc_t) entries;
+};
+
+struct of_queue_desc_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 15;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_queue_desc_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_queue_desc_prop_min_rate : of_queue_desc_prop {
+    uint16_t type == 1;
+    uint16_t length;
+    uint16_t rate;
+    pad(2);
+};
+
+struct of_queue_desc_prop_max_rate : of_queue_desc_prop {
+    uint16_t type == 2;
+    uint16_t length;
+    uint16_t rate;
+    pad(2);
+};
+
+struct of_queue_desc_prop_experimenter : of_queue_desc_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_queue_desc {
+    uint32_t port_no;
+    uint32_t queue_id;
+    uint16_t length;
+    pad(6);
+    list(of_queue_desc_prop_t) properties;
+};
+
+struct of_queue_desc_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 15;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_queue_desc_t) entries;
+};
+
+/*
+ * Not supporting the flow monitor multipart messages. This message is
+ * poorly designed because it includes a variable length match inside a
+ * struct (ofp_flow_monitor_request) with no explicit length member.
+ * I'm not writing the special case code to figure out the total length.
+ */
+
 struct of_meter_band_stats {
     uint64_t        packet_band_count;
     uint64_t        byte_band_count;
@@ -2225,24 +2431,139 @@
     uint64_t generation_id;
 };
 
-////////////////////////////////////////////////////////////////
-// FIXME understand async; where do bitmasks live?
-// Determine bitmap type for masks below.
-// DOCUMENT masks where uint32_t[0] is interest for equal/master
-//   while uint32_t[1] is interest for slave
-////////////////////////////////////////////////////////////////
+/* Bundle messages */
+
+struct of_bundle_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_bundle_prop_experimenter : of_bundle_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_bundle_ctrl_msg : of_header {
+    uint8_t version;
+    uint8_t type == 33;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t bundle_id;
+    enum ofp_bundle_ctrl_type bundle_ctrl_type;
+    enum ofp_bundle_flags flags;
+    list(of_bundle_prop_t) properties;
+};
+
+struct of_bundle_add_msg : of_header {
+    uint8_t version;
+    uint8_t type == 34;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t bundle_id;
+    pad(2);
+    enum ofp_bundle_flags flags;
+    // TODO support embedding of_header
+    of_octets_t data;
+    // TODO support trailing properties
+};
+
+/* Async config messages */
+
+struct of_async_config_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_async_config_prop_packet_in_slave : of_async_config_prop {
+    uint16_t type == 0;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_packet_in_master : of_async_config_prop {
+    uint16_t type == 1;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_port_status_slave : of_async_config_prop {
+    uint16_t type == 2;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_port_status_master : of_async_config_prop {
+    uint16_t type == 3;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_flow_removed_slave : of_async_config_prop {
+    uint16_t type == 4;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_flow_removed_master : of_async_config_prop {
+    uint16_t type == 5;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_role_status_slave : of_async_config_prop {
+    uint16_t type == 6;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_role_status_master : of_async_config_prop {
+    uint16_t type == 7;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_table_status_slave : of_async_config_prop {
+    uint16_t type == 8;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_table_status_master : of_async_config_prop {
+    uint16_t type == 9;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_requestforward_slave : of_async_config_prop {
+    uint16_t type == 10;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_requestforward_master : of_async_config_prop {
+    uint16_t type == 11;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_experimenter_slave : of_async_config_prop {
+    uint16_t type == 0xfffe;
+    uint16_t length;
+};
+
+struct of_async_config_prop_experimenter_master : of_async_config_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+};
 
 struct of_async_get_request : of_header {
     uint8_t version;
     uint8_t type == 26;
     uint16_t length;
     uint32_t xid;
-    uint32_t packet_in_mask_equal_master;
-    uint32_t packet_in_mask_slave;
-    uint32_t port_status_mask_equal_master;
-    uint32_t port_status_mask_slave;
-    uint32_t flow_removed_mask_equal_master;
-    uint32_t flow_removed_mask_slave;
+    list(of_async_config_prop_t) properties;
 };
 
 struct of_async_get_reply : of_header {
@@ -2250,12 +2571,7 @@
     uint8_t type == 27;
     uint16_t length;
     uint32_t xid;
-    uint32_t packet_in_mask_equal_master;
-    uint32_t packet_in_mask_slave;
-    uint32_t port_status_mask_equal_master;
-    uint32_t port_status_mask_slave;
-    uint32_t flow_removed_mask_equal_master;
-    uint32_t flow_removed_mask_slave;
+    list(of_async_config_prop_t) properties;
 };
 
 struct of_async_set : of_header {
@@ -2263,10 +2579,56 @@
     uint8_t type == 28;
     uint16_t length;
     uint32_t xid;
-    uint32_t packet_in_mask_equal_master;
-    uint32_t packet_in_mask_slave;
-    uint32_t port_status_mask_equal_master;
-    uint32_t port_status_mask_slave;
-    uint32_t flow_removed_mask_equal_master;
-    uint32_t flow_removed_mask_slave;
+    list(of_async_config_prop_t) properties;
+};
+
+/* Role status message */
+
+struct of_role_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_role_prop_experimenter : of_role_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_role_status : of_header {
+    uint8_t version;
+    uint8_t type == 30;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t role;
+    enum ofp_controller_role_reason reason;
+    pad(3);
+    uint64_t generation_id;
+    list(of_role_prop_t) properties;
+};
+
+/* Table status messages */
+
+struct of_table_status : of_header {
+    uint8_t version;
+    uint8_t type == 31;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t role;
+    enum ofp_table_reason reason;
+    pad(7);
+    of_table_desc_t table;
+};
+
+/* Request forward message */
+
+struct of_requestforward : of_header {
+    uint8_t version;
+    uint8_t type == 32;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t role;
+    // TODO support embedding of_header
+    of_octets_t data;
 };
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index a664d87..f8a7211 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -49,6 +49,12 @@
     'of_table_mod_prop': 'table_mod_prop',
     'of_queue_desc_prop': 'queue_desc_prop',
     'of_queue_stats_prop': 'queue_stats_prop',
+    'of_async_config_prop': 'async_config_prop',
+    'of_bundle_prop': 'bundle_prop',
+    #'of_queue_prop': 'queue_prop',
+    'of_role_prop': 'role_prop',
+    #'of_table_feature_prop': 'table_feature_prop',
+    'of_table_mod_prop': 'table_mod_prop',
 }
 
 # Return the module and class names for the generated Python class
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index 7bd242e..51b8e13 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -143,6 +143,7 @@
     'of_port_desc_t': 'common.port_desc',
     'of_meter_features_t': 'common.meter_features',
     'of_bsn_vport_t': 'common.bsn_vport',
+    'of_table_desc_t': 'common.table_desc',
 }
 
 for (cls, pyclass) in embedded_structs.items():
@@ -190,6 +191,7 @@
     elif oftype_is_list(oftype):
         ofproto = loxi_globals.ir[version]
         ofclass = ofproto.class_by_name(oftype_list_elem(oftype))
+        assert ofclass, "No class named %r" % oftype_list_elem(oftype)
         module_name, class_name = py_gen.codegen.generate_pyname(ofclass)
         return 'loxi.generic_util.unpack_list(%s, %s.%s.unpack)' % \
             (reader_expr, module_name, class_name)