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 = [
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index d124f5a..824a320 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -61,7 +61,11 @@
interface_blacklist = set( ("OFUint8", "OFUint32",))
# registry of interface properties that should not be generated
# map: $java_type -> set(java_name_property)
- read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
+ read_blacklist = defaultdict(lambda: set(),
+ OFExperimenter=set(('data','subtype')),
+ OFActionExperimenter=set(('data',)),
+ OFExperimenterStatsRequest=set(('data','subtype')),
+ OFExperimenterStatsReply=set(('data','subtype')))
# 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
@@ -502,9 +506,19 @@
if re.match(r'OFStatsRequest$', self.name):
return ("", "OFMessage", "T extends OFStatsReply")
elif self.ir_class.is_subclassof('of_stats_request'):
- return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
+ if self.ir_class.is_subclassof('of_bsn_stats_request'):
+ return ("", "OFBsnStatsRequest", None)
+ elif self.ir_class.is_subclassof('of_experimenter_stats_request'):
+ return ("", "OFExperimenterStatsRequest", None)
+ else:
+ return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
elif self.ir_class.is_subclassof('of_stats_reply'):
- return ("", "OFStatsReply", None)
+ if self.ir_class.is_subclassof('of_bsn_stats_reply'):
+ return ("", "OFBsnStatsReply", None)
+ elif self.ir_class.is_subclassof('of_experimenter_stats_reply'):
+ return ("", "OFExperimenterStatsReply", None)
+ else:
+ return ("", "OFStatsReply", None)
elif self.ir_class.is_subclassof('of_error_msg'):
return ("", "OFErrorMsg", None)
elif self.ir_class.is_subclassof('of_flow_mod'):
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index 1e1b1de..a84508a 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -114,8 +114,4 @@
if not ofinput.wire_versions:
raise InputError("Missing #version metadata")
- for used_enum in ctx.used_enums:
- if not find(lambda e: e.name == used_enum, ofinput.enums):
- raise Exception("Undeclared enum used in OFInput: {}".format(used_enum))
-
return ofinput
diff --git a/loxigen.py b/loxigen.py
index ba62288..700168a 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -111,7 +111,7 @@
# Create the OFInput from the AST
try:
- ofinput = frontend.create_ofinput(filename, ast)
+ ofinput = frontend.create_ofinput(os.path.basename(filename), ast)
except frontend.InputError as e:
print "Error in %s: %s" % (os.path.basename(filename), str(e))
sys.exit(1)
@@ -131,6 +131,8 @@
# Ignore emacs backup files
filenames = [x for x in filenames if not x.endswith('~')]
+ # Read input files
+ all_ofinputs = []
for filename in filenames:
log("Processing struct file: " + filename)
ofinput = process_input_file(filename)
diff --git a/openflow_input/bsn b/openflow_input/bsn
index 0aa674b..dfbf981 100644
--- a/openflow_input/bsn
+++ b/openflow_input/bsn
@@ -46,3 +46,26 @@
pad(4);
};
+struct of_bsn_stats_request : of_experimenter_stats_request {
+ uint8_t version;
+ uint8_t type == 18;
+ uint16_t length;
+ uint32_t xid;
+ uint16_t stats_type == 0xffff;
+ enum ofp_stats_request_flags flags;
+ pad(4);
+ uint32_t experimenter == 0x5c16c7;
+ uint32_t subtype == ?;
+};
+
+struct of_bsn_stats_reply : of_experimenter_stats_reply {
+ uint8_t version;
+ uint8_t type == 19;
+ uint16_t length;
+ uint32_t xid;
+ uint16_t stats_type == 0xffff;
+ enum ofp_stats_reply_flags flags;
+ pad(4);
+ uint32_t experimenter == 0x5c16c7;
+ uint32_t subtype == ?;
+};
diff --git a/openflow_input/bsn_lacp b/openflow_input/bsn_lacp
index 8237641..d2e540a 100644
--- a/openflow_input/bsn_lacp
+++ b/openflow_input/bsn_lacp
@@ -88,3 +88,45 @@
uint16_t partner_port_num;
uint16_t partner_key;
};
+
+struct of_bsn_lacp_stats_request : of_bsn_stats_request {
+ uint8_t version;
+ uint8_t type == 18;
+ uint16_t length;
+ uint32_t xid;
+ uint16_t stats_type == 0xffff;
+ enum ofp_stats_request_flags flags;
+ pad(4);
+ uint32_t experimenter == 0x5c16c7;
+ uint32_t subtype == 1;
+};
+
+struct of_bsn_lacp_stats_entry {
+ of_port_no_t port_no;
+ uint16_t actor_sys_priority;
+ of_mac_addr_t actor_sys_mac;
+ uint16_t actor_port_priority;
+ uint16_t actor_port_num;
+ uint16_t actor_key;
+ uint8_t convergence_status;
+ pad(1);
+ uint16_t partner_sys_priority;
+ of_mac_addr_t partner_sys_mac;
+ uint16_t partner_port_priority;
+ uint16_t partner_port_num;
+ uint16_t partner_key;
+ pad(2);
+};
+
+struct of_bsn_lacp_stats_reply : of_bsn_stats_reply {
+ uint8_t version;
+ uint8_t type == 19;
+ uint16_t length;
+ uint32_t xid;
+ uint16_t stats_type == 0xffff;
+ enum ofp_stats_reply_flags flags;
+ pad(4);
+ uint32_t experimenter == 0x5c16c7;
+ uint32_t subtype == 1;
+ list(of_bsn_lacp_stats_entry_t) entries;
+};
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index bedb533..4d0ca7e 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -1563,6 +1563,30 @@
list(of_table_stats_entry_t) entries;
};
+struct of_experimenter_stats_request : of_stats_request {
+ uint8_t version;
+ uint8_t type == 18;
+ uint16_t length;
+ uint32_t xid;
+ uint16_t stats_type == 0xffff;
+ enum ofp_stats_request_flags flags;
+ pad(4);
+ uint32_t experimenter == ?;
+ uint32_t subtype;
+};
+
+struct of_experimenter_stats_reply : of_stats_reply {
+ uint8_t version;
+ uint8_t type == 19;
+ uint16_t length;
+ uint32_t xid;
+ uint16_t stats_type == 0xffff;
+ enum ofp_stats_reply_flags flags;
+ pad(4);
+ uint32_t experimenter == ?;
+ uint32_t subtype;
+};
+
// FIXME: These are padded to 8 byte align beyond the length indicated
struct of_table_feature_prop {
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index b4c34f5..605d5be 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -203,6 +203,7 @@
'list(of_table_stats_entry_t)': 'common.table_stats_entry.unpack',
'list(of_uint32_t)': 'common.uint32.unpack',
'list(of_uint8_t)': 'common.uint8.unpack',
+ 'list(of_bsn_lacp_stats_entry_t)': 'common.bsn_lacp_stats_entry.unpack',
}
for (cls, element_deserializer) in fixed_elem_len_lists.items():
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index 23f28dc..39e9722 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -177,6 +177,30 @@
else:
raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
+def parse_experimenter_stats_request(buf):
+ if len(buf) < 24:
+ raise loxi.ProtocolError("experimenter stats request message too short")
+
+ experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
+
+ if experimenter in experimenter_stats_request_parsers and \
+ exp_type in experimenter_stats_request_parsers[experimenter]:
+ return experimenter_stats_request_parsers[experimenter][exp_type](buf)
+ else:
+ raise loxi.ProtocolError("unexpected stats request experimenter %#x exp_type %#x" % (experimenter, exp_type))
+
+def parse_experimenter_stats_reply(buf):
+ if len(buf) < 24:
+ raise loxi.ProtocolError("experimenter stats reply message too short")
+
+ experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
+
+ if experimenter in experimenter_stats_reply_parsers and \
+ exp_type in experimenter_stats_reply_parsers[experimenter]:
+ return experimenter_stats_reply_parsers[experimenter][exp_type](buf)
+ else:
+ raise loxi.ProtocolError("unexpected stats reply experimenter %#x exp_type %#x" % (experimenter, exp_type))
+
def parse_experimenter(buf):
if len(buf) < 16:
raise loxi.ProtocolError("experimenter message too short")
@@ -255,6 +279,7 @@
const.OFPST_TABLE : table_stats_reply.unpack,
const.OFPST_PORT : port_stats_reply.unpack,
const.OFPST_QUEUE : queue_stats_reply.unpack,
+ const.OFPST_EXPERIMENTER : parse_experimenter_stats_reply,
:: if version >= OFVersions.VERSION_1_1:
const.OFPST_GROUP : group_stats_reply.unpack,
const.OFPST_GROUP_DESC : group_desc_stats_reply.unpack,
@@ -278,6 +303,7 @@
const.OFPST_TABLE : table_stats_request.unpack,
const.OFPST_PORT : port_stats_request.unpack,
const.OFPST_QUEUE : queue_stats_request.unpack,
+ const.OFPST_EXPERIMENTER : parse_experimenter_stats_request,
:: if version >= OFVersions.VERSION_1_1:
const.OFPST_GROUP : group_stats_request.unpack,
const.OFPST_GROUP_DESC : group_desc_stats_request.unpack,
@@ -307,3 +333,19 @@
},
:: #endfor
}
+
+experimenter_stats_request_parsers = {
+ 0x005c16c7: {
+:: if version >= OFVersions.VERSION_1_3:
+ 1: bsn_lacp_stats_request.unpack,
+:: #endif
+ },
+}
+
+experimenter_stats_reply_parsers = {
+ 0x005c16c7: {
+:: if version >= OFVersions.VERSION_1_3:
+ 1: bsn_lacp_stats_reply.unpack,
+:: #endif
+ },
+}