Initial import
LoxiGen is the work of several developers, not just myself.
diff --git a/py_gen/templates/.gitignore b/py_gen/templates/.gitignore
new file mode 100644
index 0000000..81fc9b5
--- /dev/null
+++ b/py_gen/templates/.gitignore
@@ -0,0 +1,2 @@
+# Tenjin cache files
+/*.cache
diff --git a/py_gen/templates/_autogen.py b/py_gen/templates/_autogen.py
new file mode 100644
index 0000000..520ad9e
--- /dev/null
+++ b/py_gen/templates/_autogen.py
@@ -0,0 +1,30 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: import inspect, os
+# Automatically generated by LOXI from template #{os.path.basename(inspect.stack()[3][1])}
+# Do not modify
diff --git a/py_gen/templates/_copyright.py b/py_gen/templates/_copyright.py
new file mode 100644
index 0000000..24dc1b6
--- /dev/null
+++ b/py_gen/templates/_copyright.py
@@ -0,0 +1,30 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+# Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+# Copyright (c) 2011, 2012 Open Networking Foundation
+# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
diff --git a/py_gen/templates/_pack.py b/py_gen/templates/_pack.py
new file mode 100644
index 0000000..0d50a38
--- /dev/null
+++ b/py_gen/templates/_pack.py
@@ -0,0 +1,47 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: # TODO coalesce format strings
+:: all_members = ofclass.members[:]
+:: if ofclass.length_member: all_members.append(ofclass.length_member)
+:: all_members.extend(ofclass.type_members)
+:: all_members.sort(key=lambda x: x.offset)
+:: length_member_index = None
+:: index = 0
+:: for m in all_members:
+:: if m == ofclass.length_member:
+:: length_member_index = index
+ packed.append(${m.oftype.gen_pack_expr('0')}) # placeholder for ${m.name} at index ${length_member_index}
+:: else:
+ packed.append(${m.oftype.gen_pack_expr('self.' + m.name)})
+:: #endif
+:: index += 1
+:: #endfor
+:: if length_member_index != None:
+ length = sum([len(x) for x in packed])
+ packed[${length_member_index}] = ${ofclass.length_member.oftype.gen_pack_expr('length')}
+:: #endif
diff --git a/py_gen/templates/_pack_packet_out.py b/py_gen/templates/_pack_packet_out.py
new file mode 100644
index 0000000..ad8b827
--- /dev/null
+++ b/py_gen/templates/_pack_packet_out.py
@@ -0,0 +1,39 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+ packed.append(struct.pack("!B", self.version))
+ packed.append(struct.pack("!B", self.type))
+ packed.append(struct.pack("!H", 0)) # placeholder for length at index 3
+ packed.append(struct.pack("!L", self.xid))
+ packed.append(struct.pack("!L", self.buffer_id))
+ packed.append(struct.pack("!H", self.in_port))
+ packed_actions = "".join([x.pack() for x in self.actions])
+ packed.append(struct.pack("!H", len(packed_actions)))
+ packed.append(packed_actions)
+ packed.append(self.data)
+ length = sum([len(x) for x in packed])
+ packed[2] = struct.pack("!H", length)
diff --git a/py_gen/templates/_pretty_print.py b/py_gen/templates/_pretty_print.py
new file mode 100644
index 0000000..604cd94
--- /dev/null
+++ b/py_gen/templates/_pretty_print.py
@@ -0,0 +1,61 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+ q.text("${ofclass.pyname} {")
+ with q.group():
+ with q.indent(2):
+ q.breakable()
+:: first = True
+:: for m in ofclass.members:
+:: if m.name == 'actions_len': continue
+:: if not first:
+ q.text(","); q.breakable()
+:: else:
+:: first = False
+:: #endif
+ q.text("${m.name} = ");
+:: if m.name == "xid":
+ if self.${m.name} != None:
+ q.text("%#x" % self.${m.name})
+ else:
+ q.text('None')
+:: elif m.oftype.base == 'of_mac_addr_t':
+ q.text(util.pretty_mac(self.${m.name}))
+:: elif m.oftype.base == 'uint32_t' and m.name.startswith("ipv4"):
+ q.text(util.pretty_ipv4(self.${m.name}))
+:: elif m.oftype.base == 'of_wc_bmap_t':
+ q.text(util.pretty_wildcards(self.${m.name}))
+:: elif m.oftype.base == 'of_port_no_t':
+ q.text(util.pretty_port(self.${m.name}))
+:: elif m.oftype.base.startswith("uint") and not m.oftype.is_array:
+ q.text("%#x" % self.${m.name})
+:: else:
+ q.pp(self.${m.name})
+:: #endif
+:: #endfor
+ q.breakable()
+ q.text('}')
diff --git a/py_gen/templates/_unpack.py b/py_gen/templates/_unpack.py
new file mode 100644
index 0000000..173ebb5
--- /dev/null
+++ b/py_gen/templates/_unpack.py
@@ -0,0 +1,49 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: # TODO coalesce format strings
+:: all_members = ofclass.members[:]
+:: if ofclass.length_member: all_members.append(ofclass.length_member)
+:: all_members.extend(ofclass.type_members)
+:: all_members.sort(key=lambda x: x.offset)
+:: for m in all_members:
+:: unpack_expr = m.oftype.gen_unpack_expr('buf', m.offset)
+:: if m == ofclass.length_member:
+ _length = ${unpack_expr}
+ assert(_length == len(buf))
+:: if ofclass.is_fixed_length:
+ if _length != ${ofclass.min_length}: raise loxi.ProtocolError("${ofclass.pyname} length is %d, should be ${ofclass.min_length}" % _length)
+:: else:
+ if _length < ${ofclass.min_length}: raise loxi.ProtocolError("${ofclass.pyname} length is %d, should be at least ${ofclass.min_length}" % _length)
+:: #endif
+:: elif m in ofclass.type_members:
+ ${m.name} = ${unpack_expr}
+ assert(${m.name} == ${m.value})
+:: else:
+ obj.${m.name} = ${unpack_expr}
+:: #endif
+:: #endfor
diff --git a/py_gen/templates/_unpack_packet_out.py b/py_gen/templates/_unpack_packet_out.py
new file mode 100644
index 0000000..b97e829
--- /dev/null
+++ b/py_gen/templates/_unpack_packet_out.py
@@ -0,0 +1,40 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+ version = struct.unpack_from('!B', buf, 0)[0]
+ assert(version == const.OFP_VERSION)
+ type = struct.unpack_from('!B', buf, 1)[0]
+ assert(type == const.OFPT_PACKET_OUT)
+ _length = struct.unpack_from('!H', buf, 2)[0]
+ assert(_length == len(buf))
+ if _length < 16: raise loxi.ProtocolError("packet_out length is %d, should be at least 16" % _length)
+ obj.xid = struct.unpack_from('!L', buf, 4)[0]
+ obj.buffer_id = struct.unpack_from('!L', buf, 8)[0]
+ obj.in_port = struct.unpack_from('!H', buf, 12)[0]
+ actions_len = struct.unpack_from('!H', buf, 14)[0]
+ obj.actions = action.unpack_list(buffer(buf, 16, actions_len))
+ obj.data = str(buffer(buf, 16+actions_len))
diff --git a/py_gen/templates/action.py b/py_gen/templates/action.py
new file mode 100644
index 0000000..439e56f
--- /dev/null
+++ b/py_gen/templates/action.py
@@ -0,0 +1,145 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: import itertools
+:: include('_copyright.py')
+
+:: include('_autogen.py')
+
+import struct
+import const
+import util
+import loxi
+
+def unpack_list(buf):
+ if len(buf) % 8 != 0: raise loxi.ProtocolError("action list length not a multiple of 8")
+ actions = []
+ offset = 0
+ while offset < len(buf):
+ type, length = struct.unpack_from("!HH", buf, offset)
+ if length == 0: raise loxi.ProtocolError("action length is 0")
+ if length % 8 != 0: raise loxi.ProtocolError("action length not a multiple of 8")
+ if offset + length > len(buf): raise loxi.ProtocolError("action length overruns list length")
+ parser = parsers.get(type)
+ if not parser: raise loxi.ProtocolError("unknown action type %d" % type)
+ actions.append(parser(buffer(buf, offset, length)))
+ offset += length
+ return actions
+
+class Action(object):
+ type = None # override in subclass
+ pass
+
+:: for ofclass in ofclasses:
+:: nonskip_members = [m for m in ofclass.members if not m.skip]
+class ${ofclass.pyname}(Action):
+:: for m in ofclass.type_members:
+ ${m.name} = ${m.value}
+:: #endfor
+
+ def __init__(self, ${', '.join(["%s=None" % m.name for m in nonskip_members])}):
+:: for m in nonskip_members:
+ if ${m.name} != None:
+ self.${m.name} = ${m.name}
+ else:
+ self.${m.name} = ${m.oftype.gen_init_expr()}
+:: #endfor
+
+ def pack(self):
+ packed = []
+:: include("_pack.py", ofclass=ofclass)
+ return ''.join(packed)
+
+ @staticmethod
+ def unpack(buf):
+ obj = ${ofclass.pyname}()
+:: include("_unpack.py", ofclass=ofclass)
+ return obj
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+:: for m in nonskip_members:
+ if self.${m.name} != other.${m.name}: return False
+:: #endfor
+ return True
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def show(self):
+ import loxi.pp
+ return loxi.pp.pp(self)
+
+ def pretty_print(self, q):
+:: include('_pretty_print.py', ofclass=ofclass)
+
+:: #endfor
+
+def parse_vendor(buf):
+ if len(buf) < 16:
+ raise loxi.ProtocolError("experimenter action too short")
+
+ experimenter, = struct.unpack_from("!L", buf, 4)
+ if experimenter == 0x005c16c7: # Big Switch Networks
+ subtype, = struct.unpack_from("!L", buf, 8)
+ elif experimenter == 0x00002320: # Nicira
+ subtype, = struct.unpack_from("!H", buf, 8)
+ else:
+ raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
+
+ if subtype in experimenter_parsers[experimenter]:
+ return experimenter_parsers[experimenter][subtype](buf)
+ else:
+ raise loxi.ProtocolError("unexpected BSN experimenter subtype %#x" % subtype)
+
+parsers = {
+:: sort_key = lambda x: x.type_members[0].value
+:: msgtype_groups = itertools.groupby(sorted(ofclasses, key=sort_key), sort_key)
+:: for (k, v) in msgtype_groups:
+:: v = list(v)
+:: if len(v) == 1:
+ ${k} : ${v[0].pyname}.unpack,
+:: else:
+ ${k} : parse_${k[12:].lower()},
+:: #endif
+:: #endfor
+}
+
+:: experimenter_ofclasses = [x for x in ofclasses if x.type_members[0].value == 'const.OFPAT_VENDOR']
+:: sort_key = lambda x: x.type_members[1].value
+:: experimenter_ofclasses.sort(key=sort_key)
+:: grouped = itertools.groupby(experimenter_ofclasses, sort_key)
+experimenter_parsers = {
+:: for (experimenter, v) in grouped:
+ ${experimenter} : {
+:: for ofclass in v:
+ ${ofclass.type_members[2].value}: ${ofclass.pyname}.unpack,
+:: #endfor
+ },
+:: #endfor
+}
diff --git a/py_gen/templates/common.py b/py_gen/templates/common.py
new file mode 100644
index 0000000..08fb65d
--- /dev/null
+++ b/py_gen/templates/common.py
@@ -0,0 +1,125 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.py')
+
+:: include('_autogen.py')
+
+import sys
+import struct
+import action
+import const
+import util
+
+# HACK make this module visible as 'common' to simplify code generation
+common = sys.modules[__name__]
+
+def unpack_list_flow_stats_entry(buf):
+ entries = []
+ offset = 0
+ while offset < len(buf):
+ length, = struct.unpack_from("!H", buf, offset)
+ if length == 0: raise loxi.ProtocolError("entry length is 0")
+ if offset + length > len(buf): raise loxi.ProtocolError("entry length overruns list length")
+ entries.append(flow_stats_entry.unpack(buffer(buf, offset, length)))
+ offset += length
+ return entries
+
+def unpack_list_queue_prop(buf):
+ entries = []
+ offset = 0
+ while offset < len(buf):
+ type, length, = struct.unpack_from("!HH", buf, offset)
+ if length == 0: raise loxi.ProtocolError("entry length is 0")
+ if offset + length > len(buf): raise loxi.ProtocolError("entry length overruns list length")
+ if type == const.OFPQT_MIN_RATE:
+ entry = queue_prop_min_rate.unpack(buffer(buf, offset, length))
+ else:
+ raise loxi.ProtocolError("unknown queue prop %d" % type)
+ entries.append(entry)
+ offset += length
+ return entries
+
+def unpack_list_packet_queue(buf):
+ entries = []
+ offset = 0
+ while offset < len(buf):
+ _, length, = struct.unpack_from("!LH", buf, offset)
+ if length == 0: raise loxi.ProtocolError("entry length is 0")
+ if offset + length > len(buf): raise loxi.ProtocolError("entry length overruns list length")
+ entries.append(packet_queue.unpack(buffer(buf, offset, length)))
+ offset += length
+ return entries
+
+:: for ofclass in ofclasses:
+class ${ofclass.pyname}(object):
+:: for m in ofclass.type_members:
+ ${m.name} = ${m.value}
+:: #endfor
+
+ def __init__(self, ${', '.join(["%s=None" % m.name for m in ofclass.members])}):
+:: for m in ofclass.members:
+ if ${m.name} != None:
+ self.${m.name} = ${m.name}
+ else:
+ self.${m.name} = ${m.oftype.gen_init_expr()}
+:: #endfor
+
+ def pack(self):
+ packed = []
+:: include("_pack.py", ofclass=ofclass)
+ return ''.join(packed)
+
+ @staticmethod
+ def unpack(buf):
+ assert(len(buf) >= ${ofclass.min_length}) # Should be verified by caller
+ obj = ${ofclass.pyname}()
+:: include("_unpack.py", ofclass=ofclass)
+ return obj
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+:: for m in ofclass.members:
+ if self.${m.name} != other.${m.name}: return False
+:: #endfor
+ return True
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def show(self):
+ import loxi.pp
+ return loxi.pp.pp(self)
+
+ def pretty_print(self, q):
+:: include('_pretty_print.py', ofclass=ofclass)
+
+:: if ofclass.name.startswith("of_match_v"):
+match = ${ofclass.pyname}
+
+:: #endif
+:: #endfor
diff --git a/py_gen/templates/const.py b/py_gen/templates/const.py
new file mode 100644
index 0000000..c5a0e93
--- /dev/null
+++ b/py_gen/templates/const.py
@@ -0,0 +1,66 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: blacklisted_map_groups = ['macro_definitions']
+:: blacklisted_map_idents = ['OFPFW_NW_DST_BITS', 'OFPFW_NW_SRC_BITS',
+:: 'OFPFW_NW_SRC_SHIFT', 'OFPFW_NW_DST_SHIFT', 'OFPFW_NW_SRC_ALL',
+:: 'OFPFW_NW_SRC_MASK', 'OFPFW_NW_DST_ALL', 'OFPFW_NW_DST_MASK',
+:: 'OFPFW_ALL']
+:: include('_copyright.py')
+
+:: include('_autogen.py')
+
+OFP_VERSION = ${version}
+
+:: for (group, idents) in sorted(groups.items()):
+:: idents.sort(key=lambda (ident, value): eval(value))
+# Identifiers from group ${group}
+:: for (ident, value) in idents:
+:: if version == 1 and ident.startswith('OFPP_'):
+:: # HACK loxi converts these to 32-bit
+${ident} = ${"%#x" % (int(value, 16) & 0xffff)}
+:: else:
+${ident} = ${value}
+:: #endif
+:: #endfor
+
+:: if group not in blacklisted_map_groups:
+${group}_map = {
+:: for (ident, value) in idents:
+:: if ident in blacklisted_map_idents:
+:: pass
+:: elif version == 1 and ident.startswith('OFPP_'):
+:: # HACK loxi converts these to 32-bit
+ ${"%#x" % (int(value, 16) & 0xffff)}: ${repr(ident)},
+:: else:
+ ${value}: ${repr(ident)},
+:: #endif
+:: #endfor
+}
+
+:: #endif
+:: #endfor
diff --git a/py_gen/templates/init.py b/py_gen/templates/init.py
new file mode 100644
index 0000000..abc8d70
--- /dev/null
+++ b/py_gen/templates/init.py
@@ -0,0 +1,35 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.py')
+
+:: include('_autogen.py')
+
+import action, common, const, message
+from const import *
+from common import *
+from loxi import ProtocolError
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
new file mode 100644
index 0000000..71a2871
--- /dev/null
+++ b/py_gen/templates/message.py
@@ -0,0 +1,219 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http::: #www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: import itertools
+:: include('_copyright.py')
+
+:: include('_autogen.py')
+
+import struct
+import loxi
+import const
+import common
+import action # for unpack_list
+import util
+
+class Message(object):
+ version = const.OFP_VERSION
+ type = None # override in subclass
+ xid = None
+
+:: for ofclass in ofclasses:
+:: nonskip_members = [m for m in ofclass.members if not m.skip]
+class ${ofclass.pyname}(Message):
+:: for m in ofclass.type_members:
+ ${m.name} = ${m.value}
+:: #endfor
+
+ def __init__(self, ${', '.join(["%s=None" % m.name for m in nonskip_members])}):
+ self.xid = xid
+:: for m in [x for x in nonskip_members if x.name != 'xid']:
+ if ${m.name} != None:
+ self.${m.name} = ${m.name}
+ else:
+ self.${m.name} = ${m.oftype.gen_init_expr()}
+:: #endfor
+
+ def pack(self):
+ packed = []
+:: if ofclass.name == 'of_packet_out':
+:: include('_pack_packet_out.py', ofclass=ofclass)
+:: else:
+:: include('_pack.py', ofclass=ofclass)
+:: #endif
+ return ''.join(packed)
+
+ @staticmethod
+ def unpack(buf):
+ if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+ obj = ${ofclass.pyname}()
+:: if ofclass.name == 'of_packet_out':
+:: include('_unpack_packet_out.py', ofclass=ofclass)
+:: else:
+:: include('_unpack.py', ofclass=ofclass)
+:: #endif
+ return obj
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ if self.version != other.version: return False
+ if self.type != other.type: return False
+:: for m in nonskip_members:
+ if self.${m.name} != other.${m.name}: return False
+:: #endfor
+ return True
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __str__(self):
+ return self.show()
+
+ def show(self):
+ import loxi.pp
+ return loxi.pp.pp(self)
+
+ def pretty_print(self, q):
+:: include('_pretty_print.py', ofclass=ofclass)
+
+:: #endfor
+
+def parse_header(buf):
+ if len(buf) < 8:
+ raise loxi.ProtocolError("too short to be an OpenFlow message")
+ return struct.unpack_from("!BBHL", buf)
+
+def parse_message(buf):
+ msg_ver, msg_type, msg_len, msg_xid = parse_header(buf)
+ if msg_ver != const.OFP_VERSION and msg_type != ofp.OFPT_HELLO:
+ raise loxi.ProtocolError("wrong OpenFlow version")
+ if len(buf) != msg_len:
+ raise loxi.ProtocolError("incorrect message size")
+ if msg_type in parsers:
+ return parsers[msg_type](buf)
+ else:
+ raise loxi.ProtocolError("unexpected message type")
+
+:: # TODO fix for OF 1.1+
+def parse_flow_mod(buf):
+ if len(buf) < 56 + 2:
+ raise loxi.ProtocolError("message too short")
+ cmd, = struct.unpack_from("!H", buf, 56)
+ if cmd in flow_mod_parsers:
+ return flow_mod_parsers[cmd](buf)
+ else:
+ raise loxi.ProtocolError("unexpected flow mod cmd %u" % cmd)
+
+def parse_stats_reply(buf):
+ if len(buf) < 8 + 2:
+ raise loxi.ProtocolError("message too short")
+ stats_type, = struct.unpack_from("!H", buf, 8)
+ if stats_type in stats_reply_parsers:
+ return stats_reply_parsers[stats_type](buf)
+ else:
+ raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
+
+def parse_stats_request(buf):
+ if len(buf) < 8 + 2:
+ raise loxi.ProtocolError("message too short")
+ stats_type, = struct.unpack_from("!H", buf, 8)
+ if stats_type in stats_request_parsers:
+ return stats_request_parsers[stats_type](buf)
+ else:
+ raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
+
+def parse_vendor(buf):
+ if len(buf) < 16:
+ raise loxi.ProtocolError("experimenter message too short")
+
+ experimenter, = struct.unpack_from("!L", buf, 8)
+ if experimenter == 0x005c16c7: # Big Switch Networks
+ subtype, = struct.unpack_from("!L", buf, 12)
+ elif experimenter == 0x00002320: # Nicira
+ subtype, = struct.unpack_from("!L", buf, 12)
+ else:
+ raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
+
+ if subtype in experimenter_parsers[experimenter]:
+ return experimenter_parsers[experimenter][subtype](buf)
+ else:
+ raise loxi.ProtocolError("unexpected experimenter %#x subtype %#x" % (experimenter, subtype))
+
+parsers = {
+:: sort_key = lambda x: x.type_members[1].value
+:: msgtype_groups = itertools.groupby(sorted(ofclasses, key=sort_key), sort_key)
+:: for (k, v) in msgtype_groups:
+:: v = list(v)
+:: if len(v) == 1:
+ ${k} : ${v[0].pyname}.unpack,
+:: else:
+ ${k} : parse_${k[11:].lower()},
+:: #endif
+:: #endfor
+}
+
+flow_mod_parsers = {
+ const.OFPFC_ADD : flow_add.unpack,
+ const.OFPFC_MODIFY : flow_modify.unpack,
+ const.OFPFC_MODIFY_STRICT : flow_modify_strict.unpack,
+ const.OFPFC_DELETE : flow_delete.unpack,
+ const.OFPFC_DELETE_STRICT : flow_delete_strict.unpack,
+}
+
+stats_reply_parsers = {
+ const.OFPST_DESC : desc_stats_reply.unpack,
+ const.OFPST_FLOW : flow_stats_reply.unpack,
+ const.OFPST_AGGREGATE : aggregate_stats_reply.unpack,
+ const.OFPST_TABLE : table_stats_reply.unpack,
+ const.OFPST_PORT : port_stats_reply.unpack,
+ const.OFPST_QUEUE : queue_stats_reply.unpack,
+ const.OFPST_VENDOR : experimenter_stats_reply.unpack,
+}
+
+stats_request_parsers = {
+ const.OFPST_DESC : desc_stats_request.unpack,
+ const.OFPST_FLOW : flow_stats_request.unpack,
+ const.OFPST_AGGREGATE : aggregate_stats_request.unpack,
+ const.OFPST_TABLE : table_stats_request.unpack,
+ const.OFPST_PORT : port_stats_request.unpack,
+ const.OFPST_QUEUE : queue_stats_request.unpack,
+ const.OFPST_VENDOR : experimenter_stats_request.unpack,
+}
+
+:: experimenter_ofclasses = [x for x in ofclasses if x.type_members[1].value == 'const.OFPT_VENDOR']
+:: sort_key = lambda x: x.type_members[2].value
+:: experimenter_ofclasses.sort(key=sort_key)
+:: grouped = itertools.groupby(experimenter_ofclasses, sort_key)
+experimenter_parsers = {
+:: for (experimenter, v) in grouped:
+ ${experimenter} : {
+:: for ofclass in v:
+ ${ofclass.type_members[3].value}: ${ofclass.pyname}.unpack,
+:: #endfor
+ },
+:: #endfor
+}
diff --git a/py_gen/templates/pp.py b/py_gen/templates/pp.py
new file mode 100644
index 0000000..0021a28
--- /dev/null
+++ b/py_gen/templates/pp.py
@@ -0,0 +1,277 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+# Copyright 2013, Big Switch Networks, Inc.
+
+"""
+pp - port of Ruby's PP library
+Also based on Lindig, C., & GbR, G. D. (2000). Strictly Pretty.
+
+Example usage:
+>>> import pp.pp as pp
+>>> print pp([[1, 2], [3, 4]], maxwidth=15)
+[
+ [ 1, 2 ],
+ [ 3, 4 ]
+]
+"""
+import unittest
+from contextlib import contextmanager
+
+def pp(obj, maxwidth=79):
+ """
+ Pretty-print the given object.
+ """
+ ctx = PrettyPrinter(maxwidth=maxwidth)
+ ctx.pp(obj)
+ return str(ctx)
+
+
+## Pretty-printers for builtin classes
+
+def pretty_print_list(pp, obj):
+ with pp.group():
+ pp.text('[')
+ with pp.indent(2):
+ for v in obj:
+ if not pp.first(): pp.text(',')
+ pp.breakable()
+ pp.pp(v)
+ pp.breakable()
+ pp.text(']')
+
+def pretty_print_dict(pp, obj):
+ with pp.group():
+ pp.text('{')
+ with pp.indent(2):
+ for (k, v) in sorted(obj.items()):
+ if not pp.first(): pp.text(',')
+ pp.breakable()
+ pp.pp(k)
+ pp.text(': ')
+ pp.pp(v)
+ pp.breakable()
+ pp.text('}')
+
+pretty_printers = {
+ list: pretty_print_list,
+ dict: pretty_print_dict,
+}
+
+
+## Implementation
+
+class PrettyPrinter(object):
+ def __init__(self, maxwidth):
+ self.maxwidth = maxwidth
+ self.cur_indent = 0
+ self.root_group = Group()
+ self.group_stack = [self.root_group]
+
+ def current_group(self):
+ return self.group_stack[-1]
+
+ def text(self, s):
+ self.current_group().append(str(s))
+
+ def breakable(self, sep=' '):
+ self.current_group().append(Breakable(sep, self.cur_indent))
+
+ def first(self):
+ return self.current_group().first()
+
+ @contextmanager
+ def indent(self, n):
+ self.cur_indent += n
+ yield
+ self.cur_indent -= n
+
+ @contextmanager
+ def group(self):
+ self.group_stack.append(Group())
+ yield
+ new_group = self.group_stack.pop()
+ self.current_group().append(new_group)
+
+ def pp(self, obj):
+ if hasattr(obj, "pretty_print"):
+ obj.pretty_print(self)
+ elif type(obj) in pretty_printers:
+ pretty_printers[type(obj)](self, obj)
+ else:
+ self.text(repr(obj))
+
+ def __str__(self):
+ return self.root_group.render(0, self.maxwidth)
+
+class Group(object):
+ __slots__ = ["fragments", "length", "_first"]
+
+ def __init__(self):
+ self.fragments = []
+ self.length = 0
+ self._first = True
+
+ def append(self, x):
+ self.fragments.append(x)
+ self.length += len(x)
+
+ def first(self):
+ if self._first:
+ self._first = False
+ return True
+ return False
+
+ def __len__(self):
+ return self.length
+
+ def render(self, curwidth, maxwidth):
+ dobreak = len(self) > (maxwidth - curwidth)
+
+ a = []
+ for x in self.fragments:
+ if isinstance(x, Breakable):
+ if dobreak:
+ a.append('\n')
+ a.append(' ' * x.indent)
+ curwidth = 0
+ else:
+ a.append(x.sep)
+ elif isinstance(x, Group):
+ a.append(x.render(curwidth, maxwidth))
+ else:
+ a.append(x)
+ curwidth += len(a[-1])
+ return ''.join(a)
+
+class Breakable(object):
+ __slots__ = ["sep", "indent"]
+
+ def __init__(self, sep, indent):
+ self.sep = sep
+ self.indent = indent
+
+ def __len__(self):
+ return len(self.sep)
+
+
+## Tests
+
+class TestPP(unittest.TestCase):
+ def test_scalars(self):
+ self.assertEquals(pp(1), "1")
+ self.assertEquals(pp("foo"), "'foo'")
+
+ def test_hash(self):
+ expected = """{ 1: 'a', 'b': 2 }"""
+ self.assertEquals(pp(eval(expected)), expected)
+ expected = """\
+{
+ 1: 'a',
+ 'b': 2
+}"""
+ self.assertEquals(pp(eval(expected), maxwidth=0), expected)
+
+ def test_array(self):
+ expected = """[ 1, 'a', 2 ]"""
+ self.assertEquals(pp(eval(expected)), expected)
+ expected = """\
+[
+ 1,
+ 'a',
+ 2
+]"""
+ self.assertEquals(pp(eval(expected), maxwidth=0), expected)
+
+ def test_nested(self):
+ expected = """[ [ 1, 2 ], [ 3, 4 ] ]"""
+ self.assertEquals(pp(eval(expected)), expected)
+ expected = """\
+[
+ [
+ 1,
+ 2
+ ],
+ [
+ 3,
+ 4
+ ]
+]"""
+ self.assertEquals(pp(eval(expected), maxwidth=0), expected)
+
+ def test_breaking(self):
+ expected = """\
+[
+ [ 1, 2 ],
+ 'abcdefghijklmnopqrstuvwxyz'
+]"""
+ self.assertEquals(pp(eval(expected), maxwidth=24), expected)
+ expected = """\
+[
+ [ 'abcd', 2 ],
+ [ '0123456789' ],
+ [
+ '0123456789',
+ 'abcdefghij'
+ ],
+ [ 'abcdefghijklmnop' ],
+ [
+ 'abcdefghijklmnopq'
+ ],
+ { 'k': 'v' },
+ {
+ 1: [ 2, [ 3, 4 ] ],
+ 'foo': 'abcdefghijklmnop'
+ }
+]"""
+ self.assertEquals(pp(eval(expected), maxwidth=24), expected)
+ expected = """\
+[
+ [ 1, 2 ],
+ [ 3, 4 ]
+]"""
+ self.assertEquals(pp(eval(expected), maxwidth=15), expected)
+
+ # This is an edge case where our simpler algorithm breaks down.
+ @unittest.expectedFailure
+ def test_greedy_breaking(self):
+ expected = """\
+abc def
+ghijklmnopqrstuvwxyz\
+"""
+ pp = PrettyPrinter(maxwidth=8)
+ pp.text("abc")
+ with pp.group():
+ pp.breakable()
+ pp.text("def")
+ with pp.group():
+ pp.breakable()
+ pp.text("ghijklmnopqrstuvwxyz")
+ self.assertEquals(str(pp), expected)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/py_gen/templates/toplevel_init.py b/py_gen/templates/toplevel_init.py
new file mode 100644
index 0000000..c990aa3
--- /dev/null
+++ b/py_gen/templates/toplevel_init.py
@@ -0,0 +1,46 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.py')
+
+:: include('_autogen.py')
+
+def protocol(ver):
+ """
+ Import and return the protocol module for the given wire version.
+ """
+ if ver == 1:
+ import of10
+ return of10
+ else:
+ raise ValueError
+
+class ProtocolError(Exception):
+ """
+ Raised when failing to deserialize an invalid OpenFlow message.
+ """
+ pass
diff --git a/py_gen/templates/util.py b/py_gen/templates/util.py
new file mode 100644
index 0000000..5933e14
--- /dev/null
+++ b/py_gen/templates/util.py
@@ -0,0 +1,77 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.py')
+
+:: include('_autogen.py')
+
+import loxi
+import const
+
+def unpack_array(deserializer, element_size, buf):
+ """
+ Deserialize an array of fixed length elements.
+ The deserializer function should take a buffer and return the new object.
+ """
+ if len(buf) % element_size != 0: raise loxi.ProtocolError("invalid array length")
+ n = len(buf) / element_size
+ return [deserializer(buffer(buf, i*element_size, element_size)) for i in range(n)]
+
+def pretty_mac(mac):
+ return ':'.join(["%02x" % x for x in mac])
+
+def pretty_ipv4(v):
+ return "%d.%d.%d.%d" % ((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF)
+
+def pretty_flags(v, flag_names):
+ set_flags = []
+ for flag_name in flag_names:
+ flag_value = getattr(const, flag_name)
+ if v & flag_value == flag_value:
+ set_flags.append(flag_name)
+ elif v & flag_value:
+ set_flags.append('%s&%#x' % (flag_name, v & flag_value))
+ v &= ~flag_value
+ if v:
+ set_flags.append("%#x" % v)
+ return '|'.join(set_flags) or '0'
+
+def pretty_wildcards(v):
+ if v == const.OFPFW_ALL:
+ return 'OFPFW_ALL'
+ flag_names = ['OFPFW_IN_PORT', 'OFPFW_DL_VLAN', 'OFPFW_DL_SRC', 'OFPFW_DL_DST',
+ 'OFPFW_DL_TYPE', 'OFPFW_NW_PROTO', 'OFPFW_TP_SRC', 'OFPFW_TP_DST',
+ 'OFPFW_NW_SRC_MASK', 'OFPFW_NW_DST_MASK', 'OFPFW_DL_VLAN_PCP',
+ 'OFPFW_NW_TOS']
+ return pretty_flags(v, flag_names)
+
+def pretty_port(v):
+ named_ports = [(k,v2) for (k,v2) in const.__dict__.iteritems() if k.startswith('OFPP_')]
+ for (k, v2) in named_ports:
+ if v == v2:
+ return k
+ return v