def gen_class(t, parent, obj_type, template=None): if not parent in class_to_members_map.keys(): doc_info = "Unknown parent action/instruction class: " + parent else: doc_info = "Data members inherited from " + parent + ":\n" for var in class_to_members_map[parent]: doc_info += " @arg " + var + "\n" if obj_type == "action": name = "OFPAT_" + t.upper() else: name = "OFPIT_" + t.upper() if template is None: template = template_no_list to_print = re.sub('--TYPE--', t, template) to_print = re.sub('--OBJ_TYPE--', obj_type, to_print) to_print = re.sub('--PARENT_TYPE--', parent, to_print) to_print = re.sub('--ACT_INST_NAME--', name, to_print) to_print = re.sub('--DOC_INFO--', doc_info, to_print) print to_print
--DOC_INFO-- \""" def __init__(self): --PARENT_TYPE--.__init__(self) self.type = --ACTION_NAME-- self.len = self.__len__() def show(self, prefix=''): outstr = prefix + "action_--TYPE--\\n" outstr += --PARENT_TYPE--.show(self, prefix) return outstr """ 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 print "action_class_list = (" prev = None
def gen_message_wrapper(msg): """ Generate a wrapper for the given message based on above info @param msg String identifying the message name for the class """ msg_name = "OFPT_" + msg.upper() parent = message_class_map[msg] has_match = False has_list = False # Has trailing list has_core_members = False has_string = False # Has trailing string if parent != 'ofp_header': has_core_members = True if msg in match_members: has_match = True if msg in list_members.keys(): (list_var, list_type) = list_members[msg] has_list = True if msg in string_members: has_string = True if has_core_members: print "class " + msg + "(" + parent + "):" else: print "class " + msg + "(object):" _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("@arg " + list_var + ": Variable length array of TBD") else: _p1("@arg " + list_var + ": Object of type " + list_type); if has_string: _p1("@arg data: Binary string following message members") print _p1('"""') print _p1("def __init__(self):") if has_core_members: _p2(parent + ".__init__(self)") _p2("self.header = ofp_header()") _p2("self.header.type = " + msg_name) if has_match: _p2("self.match_fields = match_list()") if has_list: if list_type == None: _p2('self.' + list_var + ' = []') else: _p2('self.' + list_var + ' = ' + list_type + '()') if has_string: _p2('self.data = ""') print """ def pack(self): \""" Pack object into string @return The packed string which can go on the wire \""" self.header.length = len(self) packed = self.header.pack() """ # Have to special case the action length calculation for pkt out if msg == 'packet_out': _p2('self.actions_len = len(self.actions)') if has_core_members: _p2("packed += " + parent + ".pack(self)") if has_match: _p2('packed += self.match_fields.pack()') _p2('self.match.length = len(self.match_fields)') if has_list: if list_type == None: _p2('for obj in self.' + list_var + ':') _p3('packed += obj.pack()') else: _p2('packed += self.' + list_var + '.pack()') if has_string: _p2('packed += self.data') _p2("return packed") print """ def unpack(self, binary_string): \""" Unpack object from a binary string @param binary_string The wire protocol byte string holding the object represented as an array of bytes. @return The remainder of binary_string that was not parsed. \""" binary_string = self.header.unpack(binary_string) """ if has_core_members: _p2("binary_string = " + parent + ".unpack(self, binary_string)") if has_list: if msg == "features_reply": # Special case port parsing # For now, cheat and assume the rest of the message is port list _p2("while len(binary_string) >= OFP_PORT_BYTES:") _p3("new_port = ofp_port()") _p3("binary_string = new_port.unpack(binary_string)") _p3("self.ports.append(new_port)") elif list_type == None: _p2("for obj in self." + list_var + ":") _p3("binary_string = obj.unpack(binary_string)") elif msg == "packet_out": # Special case this _p2('binary_string = self.actions.unpack(' + 'binary_string, bytes=self.actions_len)') else: _p2("binary_string = self." + list_var + ".unpack(binary_string)") if has_string: _p2("self.data = binary_string") _p2("binary_string = ''") else: _p2("# Fixme: If no self.data, add check for data remaining") _p2("return binary_string") print """ def __len__(self): \""" Return the length of this object once packed into a string @return An integer representing the number bytes in the packed string. \""" length = OFP_HEADER_BYTES """ if has_core_members: _p2("length += " + parent + ".__len__(self)") if has_list: if list_type == None: _p2("for obj in self." + list_var + ":") _p3("length += len(obj)") else: _p2("length += len(self." + list_var + ")") if has_string: _p2("length += len(self.data)") _p2("return length") print """ def show(self, prefix=''): \""" Generate a string (with multiple lines) describing the contents of the object in a readable manner @param prefix Pre-pended at the beginning of each line. \""" """ _p2("outstr = prefix + '" + msg + " (" + msg_name + ")\\n'") _p2("prefix += ' '") _p2("outstr += prefix + 'ofp header\\n'") _p2("outstr += self.header.show(prefix + ' ')") if has_core_members: _p2("outstr += " + parent + ".show(self, prefix)") if has_list: if list_type == None: _p2('outstr += prefix + "Array ' + list_var + '\\n"') _p2('for obj in self.' + list_var +':') _p3("outstr += obj.show(prefix + ' ')") else: _p2('outstr += prefix + "List ' + list_var + '\\n"') _p2('outstr += self.' + list_var + ".show(prefix + ' ')") if has_string: _p2("outstr += prefix + 'data is of length ' + str(len(self.data)) + '\\n'") _p2("##@todo Fix this circular reference") _p2("# if len(self.data) > 0:") _p3("# obj = of_message_parse(self.data)") _p3("# if obj != None:") _p4("# outstr += obj.show(prefix)") _p3("# else:") _p4('# outstr += prefix + "Unable to parse data\\n"') _p2('return outstr') print """ def __eq__(self, other): \""" Return True if self and other hold the same data @param other Other object in comparison \""" if type(self) != type(other): return False if not self.header.__eq__(other.header): return False """ if has_core_members: _p2("if not " + parent + ".__eq__(self, other): return False") if has_string: _p2("if self.data != other.data: return False") if has_list: _p2("if self." + list_var + " != other." + list_var + ": return False") _p2("return True") print """
def gen_message_wrapper(msg): """ Generate a wrapper for the given message based on above info @param msg String identifying the message name for the class """ msg_name = "OFPT_" + msg.upper() parent = message_class_map[msg] has_list = False # Has trailing list has_core_members = False has_string = False # Has trailing string if parent != 'ofp_header': has_core_members = True if msg in list_members.keys(): (list_var, list_type) = list_members[msg] has_list = True if msg in string_members: has_string = True if has_core_members: print "class " + msg + "(" + parent + "):" else: print "class " + msg + ":" _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("@arg " + list_var + ": Variable length array of TBD") else: _p1("@arg " + list_var + ": Object of type " + list_type) if has_string: _p1("@arg data: Binary string following message members") print _p1('"""') print _p1("def __init__(self):") if has_core_members: _p2(parent + ".__init__(self)") _p2("self.header = ofp_header()") _p2("self.header.type = " + msg_name) if has_list: if list_type == None: _p2('self.' + list_var + ' = []') else: _p2('self.' + list_var + ' = ' + list_type + '()') if has_string: _p2('self.data = ""') print """ def pack(self): \""" Pack object into string @return The packed string which can go on the wire \""" self.header.length = len(self) packed = self.header.pack() """ # Have to special case the action length calculation for pkt out if msg == 'packet_out': _p2('self.actions_len = len(self.actions)') if has_core_members: _p2("packed += " + parent + ".pack(self)") if has_list: if list_type == None: _p2('for obj in self.' + list_var + ':') _p3('packed += obj.pack()') else: _p2('packed += self.' + list_var + '.pack()') if has_string: _p2('packed += self.data') _p2("return packed") print """ def unpack(self, binary_string): \""" Unpack object from a binary string @param binary_string The wire protocol byte string holding the object represented as an array of bytes. @return The remainder of binary_string that was not parsed. \""" binary_string = self.header.unpack(binary_string) """ if has_core_members: _p2("binary_string = " + parent + ".unpack(self, binary_string)") if has_list: if msg == "features_reply": # Special case port parsing # For now, cheat and assume the rest of the message is port list _p2("while len(binary_string) >= OFP_PHY_PORT_BYTES:") _p3("new_port = ofp_phy_port()") _p3("binary_string = new_port.unpack(binary_string)") _p3("self.ports.append(new_port)") elif list_type == None: _p2("for obj in self." + list_var + ":") _p3("binary_string = obj.unpack(binary_string)") elif msg == "packet_out": # Special case this _p2('binary_string = self.actions.unpack(' + 'binary_string, bytes=self.actions_len)') elif msg == "flow_mod": # Special case this _p2("ai_len = self.header.length - (OFP_FLOW_MOD_BYTES + " + "OFP_HEADER_BYTES)") _p2("binary_string = self.actions.unpack(binary_string, " + "bytes=ai_len)") else: _p2("binary_string = self." + list_var + ".unpack(binary_string)") if has_string: _p2("self.data = binary_string") _p2("binary_string = ''") else: _p2("# Fixme: If no self.data, add check for data remaining") _p2("return binary_string") print """ def __len__(self): \""" Return the length of this object once packed into a string @return An integer representing the number bytes in the packed string. \""" length = OFP_HEADER_BYTES """ if has_core_members: _p2("length += " + parent + ".__len__(self)") if has_list: if list_type == None: _p2("for obj in self." + list_var + ":") _p3("length += len(obj)") else: _p2("length += len(self." + list_var + ")") if has_string: _p2("length += len(self.data)") _p2("return length") print """ def show(self, prefix=''): \""" Generate a string (with multiple lines) describing the contents of the object in a readable manner @param prefix Pre-pended at the beginning of each line. \""" """ _p2("outstr = prefix + '" + msg + " (" + msg_name + ")\\n'") _p2("prefix += ' '") _p2("outstr += prefix + 'ofp header\\n'") _p2("outstr += self.header.show(prefix + ' ')") if has_core_members: _p2("outstr += " + parent + ".show(self, prefix)") if has_list: if list_type == None: _p2('outstr += prefix + "Array ' + list_var + '\\n"') _p2('for obj in self.' + list_var + ':') _p3("outstr += obj.show(prefix + ' ')") else: _p2('outstr += prefix + "List ' + list_var + '\\n"') _p2('outstr += self.' + list_var + ".show(prefix + ' ')") if has_string: _p2("outstr += prefix + 'data is of length ' + str(len(self.data)) + '\\n'" ) _p2("##@todo Fix this circular reference") _p2("# if len(self.data) > 0:") _p3("# obj = of_message_parse(self.data)") _p3("# if obj != None:") _p4("# outstr += obj.show(prefix)") _p3("# else:") _p4('# outstr += prefix + "Unable to parse data\\n"') _p2('return outstr') print """ def __eq__(self, other): \""" Return True if self and other hold the same data @param other Other object in comparison \""" if type(self) != type(other): return False if not self.header.__eq__(other.header): return False """ if has_core_members: _p2("if not " + parent + ".__eq__(self, other): return False") if has_string: _p2("if self.data != other.data: return False") if has_list: _p2("if self." + list_var + " != other." + list_var + ": return False") _p2("return True") print """