pyloxi: move OFType interface functions to module level
This removes the need to replace the LOXI IR OFType object in members with our
own version. If/when the core OFType is upgraded to an inheritance hierachy we
won't need to duplicate it in pyloxi.
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index fb2e48c..4e93c4c 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -67,20 +67,12 @@
for m in ofclass.members:
if type(m) == OFTypeMember:
- members.append(OFTypeMember(
- name=m.name,
- oftype=oftype.OFType(m.oftype, version),
- value=m.value))
+ members.append(m)
type_members.append(members[-1])
elif type(m) == OFLengthMember:
- members.append(OFLengthMember(
- name=m.name,
- oftype=oftype.OFType(m.oftype, version)))
+ members.append(m)
elif type(m) == OFFieldLengthMember:
- members.append(OFFieldLengthMember(
- name=m.name,
- oftype=oftype.OFType(m.oftype, version),
- field_name=m.field_name))
+ members.append(m)
elif type(m) == OFPadMember:
members.append(m)
elif type(m) == OFDataMember:
@@ -88,13 +80,11 @@
# HACK move to frontend
members.append(OFTypeMember(
name=m.name,
- oftype=oftype.OFType(m.oftype, version),
+ oftype=m.oftype,
value=version))
type_members.append(members[-1])
else:
- members.append(OFDataMember(
- name=m.name,
- oftype=oftype.OFType(m.oftype, version)))
+ members.append(m)
ofclasses.append(
PyOFClass(name=cls,
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index 2854e76..cf87ded 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -32,7 +32,7 @@
# Map from LOXI type name to an object with templates for init, pack, and unpack
# Most types are defined using the convenience code below. This dict should
# only be used directly for special cases such as primitive types.
-type_data = {
+type_data_map = {
'char': OFTypeData(
init='0',
pack='struct.pack("!B", %s)',
@@ -129,7 +129,7 @@
}
for (cls, length) in fixed_length_strings.items():
- type_data[cls] = OFTypeData(
+ type_data_map[cls] = OFTypeData(
init='""',
pack='struct.pack("!%ds", %%s)' % length,
unpack='%%s.read("!%ds")[0].rstrip("\\x00")' % length)
@@ -145,7 +145,7 @@
}
for (cls, pyclass) in embedded_structs.items():
- type_data[cls] = OFTypeData(
+ type_data_map[cls] = OFTypeData(
init='%s()' % pyclass,
pack='%s.pack()',
unpack='%s.unpack(%%s)' % pyclass)
@@ -168,7 +168,7 @@
}
for (cls, deserializer) in variable_elem_len_lists.items():
- type_data[cls] = OFTypeData(
+ type_data_map[cls] = OFTypeData(
init='[]',
pack='util.pack_list(%s)',
unpack='%s(%%s)' % deserializer)
@@ -189,39 +189,39 @@
}
for (cls, element_deserializer) in fixed_elem_len_lists.items():
- type_data[cls] = OFTypeData(
+ type_data_map[cls] = OFTypeData(
init='[]',
pack='util.pack_list(%s)',
unpack='loxi.generic_util.unpack_list(%%s, %s)' % element_deserializer)
+## Public interface
-class OFType(object):
- """
- Encapsulates knowledge about the OpenFlow type system.
- """
+# Return an initializer expression for the given oftype
+def gen_init_expr(oftype):
+ type_data = type_data_map.get(oftype)
+ if type_data and type_data.init:
+ return type_data.init
+ else:
+ return "loxi.unimplemented('init %s')" % oftype
- version = None
- base = None
+# Return a pack expression for the given oftype
+#
+# 'value_expr' is a string of Python code which will evaluate to
+# the value to be packed.
+def gen_pack_expr(oftype, value_expr):
+ type_data = type_data_map.get(oftype)
+ if type_data and type_data.pack:
+ return type_data.pack % value_expr
+ else:
+ return "loxi.unimplemented('pack %s')" % oftype
- def __init__(self, string, version):
- self.version = version
- self.base = string
- self.type_data = type_data.get(self.base)
-
- def gen_init_expr(self):
- if self.type_data and self.type_data.init:
- return self.type_data.init
- else:
- return "loxi.unimplemented('init %s')" % self.base
-
- def gen_pack_expr(self, value_expr):
- if self.type_data and self.type_data.pack:
- return self.type_data.pack % value_expr
- else:
- "loxi.unimplemented('pack %s')" % self.base
-
- def gen_unpack_expr(self, reader_expr):
- if self.type_data and self.type_data.unpack:
- return self.type_data.unpack % reader_expr
- else:
- "loxi.unimplemented('unpack %s')" % self.base
+# Return an unpack expression for the given oftype
+#
+# 'reader_expr' is a string of Python code which will evaluate to
+# the OFReader instance used for deserialization.
+def gen_unpack_expr(oftype, reader_expr):
+ type_data = type_data_map.get(oftype)
+ if type_data and type_data.unpack:
+ return type_data.unpack % reader_expr
+ else:
+ return "loxi.unimplemented('unpack %s')" % oftype
diff --git a/py_gen/templates/_ofclass.py b/py_gen/templates/_ofclass.py
index 4c5358e..ec6b04e 100644
--- a/py_gen/templates/_ofclass.py
+++ b/py_gen/templates/_ofclass.py
@@ -1,4 +1,5 @@
:: from loxi_ir import *
+:: import py_gen.oftype
:: normal_members = [m for m in ofclass.members if type(m) == OFDataMember]
class ${ofclass.pyname}(${superclass}):
:: for m in ofclass.type_members:
@@ -10,7 +11,7 @@
if ${m.name} != None:
self.${m.name} = ${m.name}
else:
- self.${m.name} = ${m.oftype.gen_init_expr()}
+ self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype)}
:: #endfor
return
diff --git a/py_gen/templates/_pack.py b/py_gen/templates/_pack.py
index 9a481b2..4714e97 100644
--- a/py_gen/templates/_pack.py
+++ b/py_gen/templates/_pack.py
@@ -27,6 +27,7 @@
::
:: # TODO coalesce format strings
:: from loxi_ir import *
+:: from py_gen.oftype import gen_pack_expr
:: length_member = None
:: length_member_index = None
:: field_length_members = {}
@@ -36,26 +37,26 @@
:: if type(m) == OFLengthMember:
:: length_member = m
:: length_member_index = index
- packed.append(${m.oftype.gen_pack_expr('0')}) # placeholder for ${m.name} at index ${index}
+ packed.append(${gen_pack_expr(m.oftype, '0')}) # placeholder for ${m.name} at index ${index}
:: elif type(m) == OFFieldLengthMember:
:: field_length_members[m.field_name] = m
:: field_length_indexes[m.field_name] = index
- packed.append(${m.oftype.gen_pack_expr('0')}) # placeholder for ${m.name} at index ${index}
+ packed.append(${gen_pack_expr(m.oftype, '0')}) # placeholder for ${m.name} at index ${index}
:: elif type(m) == OFPadMember:
packed.append('\x00' * ${m.length})
:: else:
- packed.append(${m.oftype.gen_pack_expr('self.' + m.name)})
+ packed.append(${gen_pack_expr(m.oftype, 'self.' + m.name)})
:: if m.name in field_length_members:
:: field_length_member = field_length_members[m.name]
:: field_length_index = field_length_indexes[m.name]
- packed[${field_length_index}] = ${field_length_member.oftype.gen_pack_expr('len(packed[-1])')}
+ packed[${field_length_index}] = ${gen_pack_expr(field_length_member.oftype, 'len(packed[-1])')}
:: #endif
:: #endif
:: index += 1
:: #endfor
:: if length_member_index != None:
length = sum([len(x) for x in packed])
- packed[${length_member_index}] = ${length_member.oftype.gen_pack_expr('length')}
+ packed[${length_member_index}] = ${gen_pack_expr(length_member.oftype, 'length')}
:: #endif
:: if ofclass.name == 'of_match_v3':
packed.append('\x00' * ((length + 7)/8*8 - length))
diff --git a/py_gen/templates/_pretty_print.py b/py_gen/templates/_pretty_print.py
index 65c5941..7be7a14 100644
--- a/py_gen/templates/_pretty_print.py
+++ b/py_gen/templates/_pretty_print.py
@@ -44,15 +44,15 @@
q.text("%#x" % self.${m.name})
else:
q.text('None')
-:: elif m.oftype.base == 'of_mac_addr_t':
+:: elif m.oftype == 'of_mac_addr_t':
q.text(util.pretty_mac(self.${m.name}))
-:: elif m.oftype.base == 'uint32_t' and m.name.startswith("ipv4"):
+:: elif m.oftype == 'uint32_t' and m.name.startswith("ipv4"):
q.text(util.pretty_ipv4(self.${m.name}))
-:: elif m.oftype.base == 'of_wc_bmap_t' and version in [1,2]:
+:: elif m.oftype == 'of_wc_bmap_t' and version in [1,2]:
q.text(util.pretty_wildcards(self.${m.name}))
-:: elif m.oftype.base == 'of_port_no_t':
+:: elif m.oftype == 'of_port_no_t':
q.text(util.pretty_port(self.${m.name}))
-:: elif m.oftype.base.startswith("uint"):
+:: elif m.oftype.startswith("uint"):
q.text("%#x" % self.${m.name})
:: else:
q.pp(self.${m.name})
diff --git a/py_gen/templates/_unpack.py b/py_gen/templates/_unpack.py
index 211043e..133e831 100644
--- a/py_gen/templates/_unpack.py
+++ b/py_gen/templates/_unpack.py
@@ -27,6 +27,7 @@
::
:: # TODO coalesce format strings
:: from loxi_ir import *
+:: from py_gen.oftype import gen_unpack_expr
if type(buf) == loxi.generic_util.OFReader:
reader = buf
else:
@@ -36,12 +37,12 @@
:: if type(m) == OFPadMember:
reader.skip(${m.length})
:: elif type(m) == OFLengthMember:
- _${m.name} = ${m.oftype.gen_unpack_expr('reader')}
+ _${m.name} = ${gen_unpack_expr(m.oftype, 'reader')}
:: elif type(m) == OFFieldLengthMember:
:: field_length_members[m.field_name] = m
- _${m.name} = ${m.oftype.gen_unpack_expr('reader')}
+ _${m.name} = ${gen_unpack_expr(m.oftype, 'reader')}
:: elif type(m) == OFTypeMember:
- _${m.name} = ${m.oftype.gen_unpack_expr('reader')}
+ _${m.name} = ${gen_unpack_expr(m.oftype, 'reader')}
assert(_${m.name} == ${m.value})
:: elif type(m) == OFDataMember:
:: if m.name in field_length_members:
@@ -49,7 +50,7 @@
:: else:
:: reader_expr = 'reader'
:: #endif
- obj.${m.name} = ${m.oftype.gen_unpack_expr(reader_expr)}
+ obj.${m.name} = ${gen_unpack_expr(m.oftype, reader_expr)}
:: #endif
:: #endfor
:: if ofclass.name == 'of_match_v3':
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index ffad6cf..8bf11f1 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -28,6 +28,7 @@
:: import itertools
:: import of_g
:: import py_gen.util as util
+:: import py_gen.oftype
:: include('_copyright.py')
:: include('_autogen.py')
@@ -66,7 +67,7 @@
if ${m.name} != None:
self.${m.name} = ${m.name}
else:
- self.${m.name} = ${m.oftype.gen_init_expr()}
+ self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype)}
:: #endfor
def pack(self):
diff --git a/py_gen/templates/oxm.py b/py_gen/templates/oxm.py
index 2a10a5f..d95dd8e 100644
--- a/py_gen/templates/oxm.py
+++ b/py_gen/templates/oxm.py
@@ -27,6 +27,7 @@
::
:: import itertools
:: import of_g
+:: import py_gen.oftype
:: include('_copyright.py')
:: include('_autogen.py')
@@ -65,7 +66,7 @@
if ${m.name} != None:
self.${m.name} = ${m.name}
else:
- self.${m.name} = ${m.oftype.gen_init_expr()}
+ self.${m.name} = ${py_gen.oftype.gen_init_expr(m.oftype)}
:: #endfor
def pack(self):