Added support for cpythonize to generate auxillary info
to stdout. Also added check for of_message_parse to
print out error if wrong version is called.
diff --git a/tools/munger/Makefile b/tools/munger/Makefile
index aa7394c..5a04a1f 100644
--- a/tools/munger/Makefile
+++ b/tools/munger/Makefile
@@ -21,16 +21,13 @@
PYTHONIZE = bin/pyopenflow-pythonize.py
OFP_GEN_CMD = (cd ${PYLIBOF_DIR} && ${PYTHONIZE} -i ${OF_HEADER} \
${TARGET_DIR}/ofp.py)
+OFP_AUX_INFO = ${TARGET_DIR}/ofp_aux.py
# Dependencies for ofp.py
OFP_DEP = ${ABS_OF_HEADER} $(wildcard ${PYLIBOF_DIR}/pylib/*.py)
-OFP_DEP = $(wildcard ${PYLIBOF_DIR}/pylib/of/*.py)
+OFP_DEP += $(wildcard ${PYLIBOF_DIR}/pylib/of/*.py)
-# FIXME: There are three types of .py files:
-# ofp.py from pylibopenflow output
-# %.py generated from %_gen.py
-# of_message.py and action_list.py -- hand built, already in src dir
-
+# Generated and other files
GEN_FILES := $(addprefix ${TARGET_DIR}/,ofp.py message.py error.py action.py)
OTHER_FILES := $(addprefix ${TARGET_DIR}/,action_list.py of_message.py)
LINT_SOURCE := ${GEN_FILES} ${OTHER_FILES}
@@ -40,13 +37,15 @@
all: ${GEN_FILES}
@echo "Generated files"
+# The core OpenFlow libraries generated from openflow.h
${TARGET_DIR}/ofp.py: ${OFP_DEP}
- ${OFP_GEN_CMD}
+ ${OFP_GEN_CMD} > ${OFP_AUX_INFO}
# General rule like src/message.py comes from scripts/message_gen.py
${TARGET_DIR}/%.py: scripts/%_gen.py ${TARGET_DIR}/ofp.py
python $< > $@
+# The pylint files
lint/%.log: ${TARGET_DIR}/%.py
(cd ${TARGET_DIR} && pylint -e $(notdir $<)) > $@
diff --git a/tools/munger/scripts/action_gen.py b/tools/munger/scripts/action_gen.py
index 22c7b4b..c66eb8f 100644
--- a/tools/munger/scripts/action_gen.py
+++ b/tools/munger/scripts/action_gen.py
@@ -4,6 +4,10 @@
#
import re
+import sys
+sys.path.append("../../src/python/oftest/ofmsg")
+from ofp import *
+from ofp_aux import class_to_members_map
print """
# Python OpenFlow action wrapper classes
@@ -12,7 +16,9 @@
# This will never happen; done to avoid lint warning
if __name__ == '__main__':
- def of_message_parse(msg): return None
+ def of_message_parse(msg):
+ print "ERROR: of_msg_parse in action.py called"
+ return None
"""
@@ -69,6 +75,8 @@
class action_--TYPE--(--PARENT_TYPE--):
\"""
Wrapper class for --TYPE-- action object
+
+ --DOC_INFO--
\"""
def __init__(self):
--PARENT_TYPE--.__init__(self)
@@ -81,10 +89,17 @@
if __name__ == '__main__':
for (t, parent) in action_class_map.items():
+ if not parent in class_to_members_map.keys():
+ doc_info = "Unknown parent action class: " + parent
+ else:
+ doc_info = "Data members inherited from " + parent + ":\n"
+ for var in class_to_members_map[parent]:
+ doc_info += " @arg " + var + "\n"
action_name = "OFPAT_" + t.upper()
to_print = re.sub('--TYPE--', t, template)
to_print = re.sub('--PARENT_TYPE--', parent, to_print)
to_print = re.sub('--ACTION_NAME--', action_name, to_print)
+ to_print = re.sub('--DOC_INFO--', doc_info, to_print)
print to_print
# Generate a list of action classes
diff --git a/tools/munger/scripts/error_gen.py b/tools/munger/scripts/error_gen.py
index 7dff087..9fce70d 100644
--- a/tools/munger/scripts/error_gen.py
+++ b/tools/munger/scripts/error_gen.py
@@ -4,6 +4,10 @@
#
import re
+import sys
+sys.path.append("../../src/python/oftest/ofmsg")
+from ofp import *
+from ofp_aux import class_to_members_map
print """
# Python OpenFlow error wrapper classes
@@ -12,7 +16,9 @@
# This will never happen; done to avoid lint warning
if __name__ == '__main__':
- def of_message_parse(msg): return None
+ def of_message_parse(msg):
+ print "ERROR: of_msg_parse in error.py called"
+ return None
"""
@@ -28,6 +34,12 @@
class --TYPE--_error_msg(ofp_error_msg):
\"""
Wrapper class for --TYPE-- error message class
+
+ Data members inherited from ofp_error_msg:
+ @arg type
+ @arg code
+ @arg data: Binary string following message members
+
\"""
def __init__(self):
ofp_error_msg.__init__(self)
diff --git a/tools/munger/scripts/message_gen.py b/tools/munger/scripts/message_gen.py
index f065874..61aada8 100644
--- a/tools/munger/scripts/message_gen.py
+++ b/tools/munger/scripts/message_gen.py
@@ -80,6 +80,9 @@
import re
import string
import sys
+sys.path.append("../../src/python/oftest/ofmsg")
+from ofp import *
+from ofp_aux import class_to_members_map
message_top_matter = """
# Python OpenFlow message wrapper classes
@@ -107,6 +110,7 @@
\"""
self.header = ofp_header()
# Additional base data members declared here
+
# Normally will define pack, unpack, __len__ functions
class template_msg(ofp_template_msg):
@@ -123,7 +127,11 @@
Must set the header type value appropriately for the message
\"""
+
+ ##@var header
+ # OpenFlow message header: length, version, xid, type
ofp_template_msg.__init__(self)
+ self.header = ofp_header()
# For a real message, will be set to an integer
self.header.type = "TEMPLATE_MSG_VALUE"
def pack(self):
@@ -268,21 +276,51 @@
_p1('"""')
_p1("Wrapper class for " + msg)
print
+ _p1("OpenFlow message header: length, version, xid, type")
+ _p1("@arg length: The total length of the message")
+ _p1("@arg version: The OpenFlow version (" + str(OFP_VERSION) + ")")
+ _p1("@arg xid: The transaction ID")
+ _p1("@arg type: The message type (" + msg_name + "=" +
+ str(eval(msg_name)) + ")")
+ print
+ if has_core_members and parent in class_to_members_map.keys():
+ _p1("Data members inherited from " + parent + ":")
+ for var in class_to_members_map[parent]:
+ _p1("@arg " + var)
if has_list:
if list_type == None:
- _p1("Has trailing variable array " + list_var);
+ _p1("@arg " + list_var + ": Variable length array of TBD")
else:
- _p1("Has trailing object " + list_var + " of type " + list_type);
- print
+ _p1("@arg " + list_var + ": Object of type " + list_type);
if has_string:
- _p1("Has trailing string data")
- print
+ _p1("@arg data: Binary string following message members")
+ print
_p1('"""')
print
_p1("def __init__(self):")
if has_core_members:
_p2(parent + ".__init__(self)")
+ _p2("##@var header")
+ _p2("# OpenFlow message header: length, version, xid, type")
+ _p2("# @arg length: The total length of the message")
+ _p2("# @arg version: The OpenFlow version (" + str(OFP_VERSION) + ")")
+ _p2("# @arg xid: The transaction ID")
+ _p2("# @arg type: The message type (" + msg_name + "=" +
+ str(eval(msg_name)) + ")")
+ print
+ if has_list:
+ _p2("##@var " + list_var)
+ if list_type == None:
+ _p2("# Array of objects of type TBD")
+ else:
+ _p2("# Object of type " + list_type)
+ print
+ if has_string:
+ _p2("##@var data")
+ _p2("# Binary string following message members")
+ print
+
_p2("self.header = ofp_header()")
_p2("self.header.type = " + msg_name)
if has_list:
diff --git a/tools/pylibopenflow/pylib/config.py b/tools/pylibopenflow/pylib/config.py
index bbf1528..b90f630 100644
--- a/tools/pylibopenflow/pylib/config.py
+++ b/tools/pylibopenflow/pylib/config.py
@@ -22,3 +22,8 @@
# Generate dictionary of enum strings to values
GEN_ENUM_DICTIONARY = 1
+
+# Auxilary info: Stuff written to stdout for additional processing
+# Currently generates a (python) map from a class to a list of
+# the data members; used for documentation
+GEN_AUX_INFO = 1
diff --git a/tools/pylibopenflow/pylib/cpythonize.py b/tools/pylibopenflow/pylib/cpythonize.py
index 6a66d7c..2fcdc9f 100644
--- a/tools/pylibopenflow/pylib/cpythonize.py
+++ b/tools/pylibopenflow/pylib/cpythonize.py
@@ -134,6 +134,8 @@
for name in struct_keys:
struct = self.cheader.structs[name]
code.append(self.pycode_struct_size(name, struct))
+ if GEN_AUX_INFO:
+ self.gen_struct_map()
return code
@@ -275,6 +277,27 @@
str(self.rules.get_default_value(struct_in.typename, member.name)))
return code
+ def gen_struct_map(self):
+ print
+ print "# Class to array member map"
+ print "class_to_members_map = {"
+ for name, struct in self.cheader.structs.items():
+ if not len(struct.members):
+ continue
+ s = " '" + name + "'"
+ print s + _space_to(36, s) + ": ["
+ prev = None
+ for member in struct.members:
+ if re.search('pad', member.name):
+ continue
+ if prev:
+ print _space_to(39, "") + "'" + prev + "',"
+ prev = member.name
+ print _space_to(39, "") + "'" + prev + "'"
+ print _space_to(38, "") + "],"
+ print " '_ignore' : []"
+ print "}"
+
def __structassert(self, cstruct, cstructname):
"""Return code to check for C array
"""