def gen_unpack_expr(self, reader_expr): pack_fmt = self._pack_fmt() if pack_fmt and not self.is_array: return "%s.read('!%s')[0]" % (reader_expr, pack_fmt) elif pack_fmt and self.is_array: return "list(%s.read('!%d%s'))" % (self.array_length, pack_fmt) elif self.base == 'of_octets_t': return "str(%s.read_all())" % (reader_expr) elif self.base == 'of_mac_addr_t': return "list(%s.read('!6B'))" % (reader_expr) elif self.base == 'of_ipv6_t': return "%s.read('!16s')[0]" % (reader_expr) elif self.base == 'of_match_t': return 'common.match.unpack(%s)' % (reader_expr) elif self.base == 'of_port_desc_t': return 'common.port_desc.unpack(%s)' % (reader_expr) elif self.base == 'of_list_action_t': return 'action.unpack_list(%s)' % (reader_expr) elif self.base == 'of_list_flow_stats_entry_t': return 'common.unpack_list_flow_stats_entry(%s)' % (reader_expr) elif self.base == 'of_list_queue_prop_t': return 'common.unpack_list_queue_prop(%s)' % (reader_expr) elif self.base == 'of_list_packet_queue_t': return 'common.unpack_list_packet_queue(%s)' % (reader_expr) elif self.base == 'of_list_hello_elem_t': return 'common.unpack_list_hello_elem(%s)' % (reader_expr) elif self.base == 'of_list_oxm_t': # HACK need the match_v3 length field return 'oxm.unpack_list(%s.slice(_length-4))' % (reader_expr) elif self.base == 'of_list_bucket_t': return 'common.unpack_list_bucket(%s)' % (reader_expr) elif self.base == 'of_list_group_desc_stats_entry_t': return 'common.unpack_list_group_desc_stats_entry(%s)' % (reader_expr) elif self.base == 'of_list_group_stats_entry_t': return 'common.unpack_list_group_stats_entry(%s)' % (reader_expr) elif self.base == 'of_list_meter_band_t': return 'meter_band.unpack_list(%s)' % (reader_expr) elif self.base == 'of_list_meter_stats_t': return 'common.unpack_list_meter_stats(%s)' % (reader_expr) elif self.base == 'of_port_name_t': return self._gen_string_unpack_expr(reader_expr, 16) elif self.base == 'of_table_name_t' or self.base == 'of_serial_num_t': return self._gen_string_unpack_expr(reader_expr, 32) elif self.base == 'of_desc_str_t': return self._gen_string_unpack_expr(reader_expr, 256) elif self.base == 'of_meter_features_t': return 'common.meter_features.unpack(%s)' % (reader_expr) elif self.base == 'of_list_instruction_t': return 'instruction.unpack_list(%s)' % (reader_expr) elif utils.class_is_list(self.base): element_cls = utils.list_to_entry_type(self.base)[:-2] if ((element_cls, self.version) in of_g.is_fixed_length) \ and not element_cls in loxi_front_end.type_maps.inheritance_map: klass_name = self.base[8:-2] element_size, = of_g.base_length[(element_cls, self.version)], return 'loxi.generic_util.unpack_list(%s, common.%s.unpack)' % (reader_expr, klass_name) else: return "loxi.unimplemented('unpack list %s')" % self.base else: return "loxi.unimplemented('unpack %s')" % self.base
def generate_common(out, name, version): ofclasses = [x for x in build_ofclasses(version) if not utils.class_is_message(x.name) and not utils.class_is_action(x.name) and not utils.class_is_oxm(x.name) and not utils.class_is_list(x.name)] util.render_template(out, 'common.py', ofclasses=ofclasses, version=version)
def gen_init_expr(self): if utils.class_is_list(self.base): v = "[]" elif self.base.find("uint") == 0 or self.base in ["char", "of_port_no_t"]: v = "0" elif self.base == 'of_mac_addr_t': v = '[0,0,0,0,0,0]' elif self.base == 'of_ipv6_t': v = repr('\x00' * 16) elif self.base == 'of_wc_bmap_t': if self.version in [1,2]: v = 'const.OFPFW_ALL' else: v = 0 elif self.base == "of_match_bmap_t": if self.version in [1,2]: v = 'const.OFPFW_ALL' else: v = 0 elif self.base in ['of_octets_t', 'of_port_name_t', 'of_table_name_t', 'of_desc_str_t', 'of_serial_num_t']: v = '""' elif self.base == 'of_match_t': v = 'common.match()' elif self.base == 'of_port_desc_t': v = 'common.port_desc()' elif self.base == 'of_meter_features_t': v = 'common.meter_features()' else: v = "None" if self.is_array: return "[" + ','.join([v] * self.array_length) + "]" else: return v
def class_is_virtual(cls): """ Returns True if cls is a virtual class """ if cls.find("header") > 0: return True if loxi_utils.class_is_list(cls): return True return loxi_globals.unified.class_by_name(cls).virtual
def gen_all_java(out, name): """ Generate all of the java files @param out is an open file handle to a file called README @param name should be 'README' and is ignored for the java driver """ messages = list() actions = list() instructions = list() matches = list() stat_types = list() queue_prop = list() lists = list() for cls in of_g.unified: print "! Classifying %s" % cls if cls in ["of_stats_reply", "of_flow_mod", "of_stats_request"]: continue # doesn't work?! if loxi_utils.class_is_stats_message(cls): stat_types.append(cls) elif loxi_utils.class_is_message(cls): messages.append(cls) elif loxi_utils.class_is_action(cls): actions.append(cls) elif loxi_utils.class_is_instruction(cls): instructions.append(cls) elif loxi_utils.class_is_oxm(cls): matches.append(cls) elif loxi_utils.class_is_queue_prop(cls): queue_prop.append(cls) elif loxi_utils.class_is_list(cls): lists.append(cls) else: print "Skipping Unknown class object %s" % str(cls) print "Parsed " print " Messages: %d" % len(messages) print " Actions: %d" % len(actions) print " Instructions: %d" % len(instructions) print " OXM matches: %d" % len(matches) print " Stat types: %d" % len(stat_types) print " Queue properties: %d" % len(queue_prop) print " Lists: %d" % len(lists) target_dir = "loxi_output/openflowj" basedir = "%s/%s/" % (target_dir, lang_java.file_to_subdir_map["base_java"]) srcdir = "%s/src/main/java/org/openflow/protocol" % basedir print "Outputting to %s" % basedir if not os.path.exists(basedir): os.makedirs(basedir) java_utils.copy_prewrite_tree(basedir) msgs.create_message_interfaces(messages, srcdir) msgs.create_message_by_version(messages, srcdir) msgs.create_of_type_enum(messages, srcdir) with open("README.java-lang") as readme_src: out.writelines(readme_src.readlines()) out.close()
def class_is_virtual(cls): """ Returns True if cls is a virtual class """ if cls in inheritance_map: return True if cls.find("header") > 0: return True if loxi_utils.class_is_list(cls): return True return False
def generate_common(out, name, version): ofclasses = [ x for x in build_ofclasses(version) if not utils.class_is_message(x.name) and not utils.class_is_action( x.name) and not utils.class_is_instruction(x.name) and not utils.class_is_meter_band(x.name) and not utils.class_is_oxm(x.name) and not utils.class_is_list(x.name) ] util.render_template(out, 'common.py', ofclasses=ofclasses, version=version)
def order_and_assign_object_ids(): """ Order all classes and assign object ids to all classes. This is done to promote a reasonable order of the objects, putting messages first followed by non-messages. No assumptions should be made about the order, nor about contiguous numbering. However, the numbers should all be reasonably small allowing arrays indexed by these enum values to be defined. """ # Generate separate message and non-message ordered lists for cls in of_g.unified: if loxi_utils.class_is_message(cls): of_g.ordered_messages.append(cls) elif loxi_utils.class_is_list(cls): of_g.ordered_list_objects.append(cls) else: of_g.ordered_non_messages.append(cls) of_g.ordered_pseudo_objects.append("of_stats_request") of_g.ordered_pseudo_objects.append("of_stats_reply") of_g.ordered_pseudo_objects.append("of_flow_mod") of_g.ordered_messages.sort() of_g.ordered_pseudo_objects.sort() of_g.ordered_non_messages.sort() of_g.ordered_list_objects.sort() of_g.standard_class_order.extend(of_g.ordered_messages) of_g.standard_class_order.extend(of_g.ordered_non_messages) of_g.standard_class_order.extend(of_g.ordered_list_objects) # This includes pseudo classes for which most code is not generated of_g.all_class_order.extend(of_g.ordered_messages) of_g.all_class_order.extend(of_g.ordered_non_messages) of_g.all_class_order.extend(of_g.ordered_list_objects) of_g.all_class_order.extend(of_g.ordered_pseudo_objects) # Assign object IDs for cls in of_g.ordered_messages: of_g.unified[cls]["object_id"] = of_g.object_id of_g.object_id += 1 for cls in of_g.ordered_non_messages: of_g.unified[cls]["object_id"] = of_g.object_id of_g.object_id += 1 for cls in of_g.ordered_list_objects: of_g.unified[cls]["object_id"] = of_g.object_id of_g.object_id += 1 for cls in of_g.ordered_pseudo_objects: of_g.unified[cls] = {} of_g.unified[cls]["object_id"] = of_g.object_id of_g.object_id += 1
def class_is_virtual(cls): """ Returns True if cls is a virtual class """ if cls in inheritance_map: return True if cls.find("header") > 0: return True 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"]: return True return False
def class_is_virtual(cls): """ Returns True if cls is a virtual class """ if cls in inheritance_map: return True if cls.find("header") > 0: return True 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" ]: return True return False
def gen_unpack_expr(self, buf_expr, offset_expr): pack_fmt = self._pack_fmt() if pack_fmt and not self.is_array: return "struct.unpack_from('!%s', %s, %s)[0]" % (pack_fmt, buf_expr, offset_expr) elif pack_fmt and self.is_array: return "list(struct.unpack_from('!%d%s', %s, %s))" % (self.array_length, pack_fmt, buf_expr, offset_expr) elif self.base == "of_octets_t": return "%s[%s:]" % (buf_expr, offset_expr) elif self.base == "of_mac_addr_t": return "list(struct.unpack_from('!6B', %s, %s))" % (buf_expr, offset_expr) elif self.base == "of_match_t": return "common.match.unpack(buffer(%s, %s))" % (buf_expr, offset_expr) elif self.base == "of_port_desc_t": return "common.port_desc.unpack(buffer(%s, %s))" % (buf_expr, offset_expr) elif self.base == "of_list_action_t": return "action.unpack_list(buffer(%s, %s))" % (buf_expr, offset_expr) elif self.base == "of_list_flow_stats_entry_t": return "common.unpack_list_flow_stats_entry(buffer(%s, %s))" % (buf_expr, offset_expr) elif self.base == "of_list_queue_prop_t": return "common.unpack_list_queue_prop(buffer(%s, %s))" % (buf_expr, offset_expr) elif self.base == "of_list_packet_queue_t": return "common.unpack_list_packet_queue(buffer(%s, %s))" % (buf_expr, offset_expr) elif self.base == "of_port_name_t": return self._gen_string_unpack_expr(16, buf_expr, offset_expr) elif self.base == "of_table_name_t" or self.base == "of_serial_num_t": return self._gen_string_unpack_expr(32, buf_expr, offset_expr) elif self.base == "of_desc_str_t": return self._gen_string_unpack_expr(256, buf_expr, offset_expr) elif utils.class_is_list(self.base): element_cls = utils.list_to_entry_type(self.base)[:-2] if (element_cls, self.version) in of_g.is_fixed_length: klass_name = self.base[8:-2] element_size, = (of_g.base_length[(element_cls, self.version)],) return "util.unpack_array(common.%s.unpack, %d, buffer(%s, %s))" % ( klass_name, element_size, buf_expr, offset_expr, ) else: return "None # TODO unpack list %s" % self.base else: return "None # TODO unpack %s" % self.base
def gen_init_expr(self): if utils.class_is_list(self.base): v = "[]" elif self.base.find("uint") == 0 or self.base in ["char", "of_port_no_t"]: v = "0" elif self.base == "of_mac_addr_t": v = "[0,0,0,0,0,0]" elif self.base == "of_wc_bmap_t": v = "const.OFPFW_ALL" elif self.base in ["of_octets_t", "of_port_name_t", "of_table_name_t", "of_desc_str_t", "of_serial_num_t"]: v = '""' elif self.base == "of_match_t": v = "common.match()" elif self.base == "of_port_desc_t": v = "common.port_desc()" else: v = "None" if self.is_array: return "[" + ",".join([v] * self.array_length) + "]" else: return v
def gen_pack_expr(self, expr_expr): pack_fmt = self._pack_fmt() if pack_fmt and not self.is_array: return 'struct.pack("!%s", %s)' % (pack_fmt, expr_expr) elif pack_fmt and self.is_array: return 'struct.pack("!%s%s", *%s)' % (self.array_length, pack_fmt, expr_expr) elif self.base == "of_octets_t": return expr_expr elif utils.class_is_list(self.base): return '"".join([x.pack() for x in %s])' % expr_expr elif self.base == "of_mac_addr_t": return 'struct.pack("!6B", *%s)' % expr_expr elif self.base in ["of_match_t", "of_port_desc_t"]: return "%s.pack()" % expr_expr elif self.base == "of_port_name_t": return self._gen_string_pack_expr(16, expr_expr) elif self.base == "of_table_name_t" or self.base == "of_serial_num_t": return self._gen_string_pack_expr(32, expr_expr) elif self.base == "of_desc_str_t": return self._gen_string_pack_expr(256, expr_expr) else: return "'TODO pack %s'" % self.base
def gen_pack_expr(self, expr_expr): pack_fmt = self._pack_fmt() if pack_fmt and not self.is_array: return 'struct.pack("!%s", %s)' % (pack_fmt, expr_expr) elif pack_fmt and self.is_array: return 'struct.pack("!%s%s", *%s)' % (self.array_length, pack_fmt, expr_expr) elif self.base == 'of_octets_t': return expr_expr elif utils.class_is_list(self.base): return '"".join([x.pack() for x in %s])' % expr_expr elif self.base == 'of_mac_addr_t': return 'struct.pack("!6B", *%s)' % expr_expr elif self.base == 'of_ipv6_t': return 'struct.pack("!16s", %s)' % expr_expr elif self.base in ['of_match_t', 'of_port_desc_t', 'of_meter_features_t']: return '%s.pack()' % expr_expr elif self.base == 'of_port_name_t': return self._gen_string_pack_expr(16, expr_expr) elif self.base == 'of_table_name_t' or self.base == 'of_serial_num_t': return self._gen_string_pack_expr(32, expr_expr) elif self.base == 'of_desc_str_t': return self._gen_string_pack_expr(256, expr_expr) else: return "loxi.unimplemented('pack %s')" % self.base
def gen_obj_show_c(out, name): loxi_utils.gen_c_copy_license(out) out.write(""" /** * * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen. * * Source file for object showing. * */ #define DISABLE_WARN_UNUSED_RESULT #include <loci/loci.h> #include <loci/loci_show.h> #include <loci/loci_obj_show.h> static int unknown_show(loci_writer_f writer, void* cookie, of_object_t *obj) { return writer(cookie, "Unable to print object of type %d, version %d\\n", obj->object_id, obj->version); } """) for version in of_g.of_version_range: ver_name = loxi_utils.version_to_name(version) for cls in of_g.standard_class_order: if not loxi_utils.class_in_version(cls, version): continue if cls in type_maps.inheritance_map: continue out.write(""" int %(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, %(cls)s_t *obj) { int out = 0; """ % dict(cls=cls, ver_name=ver_name)) members, member_types = loxi_utils.all_member_types_get(cls, version) for m_type in member_types: if loxi_utils.type_is_scalar(m_type) or m_type in \ ["of_match_t", "of_octets_t"]: # Declare instance of these out.write(" %s %s;\n" % (m_type, var_name_map(m_type))) else: out.write(""" %(m_type)s %(v_name)s; """ % dict(m_type=m_type, v_name=var_name_map(m_type))) if loxi_utils.class_is_list(m_type): base_type = loxi_utils.list_to_entry_type(m_type) out.write(" %s elt;\n int rv;\n" % base_type) for member in members: m_type = member["m_type"] m_name = member["name"] #emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) + "_" + m_name; if loxi_utils.skip_member_name(m_name): continue if (loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]): out.write(""" %(cls)s_%(m_name)s_get(obj, &%(v_name)s); out += writer(cookie, "%(m_name)s="); out += %(emitter)s(writer, cookie, %(v_name)s); out += writer(cookie, " "); """ % dict(cls=cls, m_name=m_name, m_type=m_type, v_name=var_name_map(m_type), emitter=emitter)) elif loxi_utils.class_is_list(m_type): sub_cls = m_type[:-2] # Trim _t elt_type = loxi_utils.list_to_entry_type(m_type) out.write(""" out += writer(cookie, "%(elt_type)s={ "); %(cls)s_%(m_name)s_bind(obj, &%(v_name)s); %(u_type)s_ITER(&%(v_name)s, &elt, rv) { of_object_show(writer, cookie, (of_object_t *)&elt); } out += writer(cookie, "} "); """ % dict(sub_cls=sub_cls, u_type=sub_cls.upper(), v_name=var_name_map(m_type), elt_type=elt_type, cls=cls, m_name=m_name, m_type=m_type)) else: sub_cls = m_type[:-2] # Trim _t out.write(""" %(cls)s_%(m_name)s_bind(obj, &%(v_name)s); out += %(sub_cls)s_%(ver_name)s_show(writer, cookie, &%(v_name)s); """ % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, v_name=var_name_map(m_type), ver_name=ver_name)) out.write(""" return out; } """) out.write(""" /** * Log a match entry */ int loci_show_match(loci_writer_f writer, void* cookie, of_match_t *match) { int out = 0; """) for key, entry in match.of_match_members.items(): m_type = entry["m_type"] #emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) + "_" + key; out.write(""" if (OF_MATCH_MASK_%(ku)s_ACTIVE_TEST(match)) { out += writer(cookie, "%(key)s active="); out += %(emitter)s(writer, cookie, match->fields.%(key)s); out += writer(cookie, "/"); out += %(emitter)s(writer, cookie, match->masks.%(key)s); out += writer(cookie, " "); } """ % dict(key=key, ku=key.upper(), emitter=emitter, m_type=m_type)) out.write(""" return out; } """) # Generate big table indexed by version and object for version in of_g.of_version_range: out.write(""" static loci_obj_show_f show_funs_v%(version)s[OF_OBJECT_COUNT] = { """ % dict(version=version)) out.write(" unknown_show, /* of_object, not a valid specific type */\n") for j, cls in enumerate(of_g.all_class_order): comma = "" if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma comma = "," if (not loxi_utils.class_in_version(cls, version) or cls in type_maps.inheritance_map): out.write(" unknown_show%s\n" % comma); else: out.write(" %s_%s_show%s\n" % (cls, loxi_utils.version_to_name(version), comma)) out.write("};\n\n") out.write(""" static loci_obj_show_f *show_funs[5] = { NULL, show_funs_v1, show_funs_v2, show_funs_v3, show_funs_v4 }; int of_object_show(loci_writer_f writer, void* cookie, of_object_t *obj) { if ((obj->object_id > 0) && (obj->object_id < OF_OBJECT_COUNT)) { if (((obj)->version > 0) && ((obj)->version <= OF_VERSION_1_2)) { /* @fixme VERSION */ return show_funs[obj->version][obj->object_id](writer, cookie, (of_object_t *)obj); } else { return writer(cookie, "Bad version %d\\n", obj->version); } } return writer(cookie, "Bad object id %d\\n", obj->object_id); } """)
def gen_c(out, name): loxi_utils.gen_c_copy_license(out) out.write(""" /** * * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen. * * Source file for OpenFlow message validation. * */ #include "loci_log.h" #include <loci/loci.h> #include <loci/loci_validator.h> #define VALIDATOR_LOG(...) LOCI_LOG_ERROR("Validator Error: " __VA_ARGS__) """) # Declarations for version in of_g.of_version_range: ver_name = loxi_utils.version_to_name(version) for cls in reversed(of_g.standard_class_order): if not loxi_utils.class_in_version(cls, version): continue if cls in type_maps.inheritance_map: continue out.write(""" static inline int %(cls)s_%(ver_name)s_validate(uint8_t *buf, int len);\ """ % dict(cls=cls, ver_name=ver_name)) out.write("\n") # Definitions for version in of_g.of_version_range: ver_name = loxi_utils.version_to_name(version) for cls in reversed(of_g.standard_class_order): if not loxi_utils.class_in_version(cls, version): continue if cls in type_maps.inheritance_map: continue if loxi_utils.class_is_list(cls): gen_list_validator(out, cls, version) else: gen_validator(out, cls, version) out.write(""" int of_validate_message_%(ver_name)s(of_message_t msg, int len) { of_object_id_t object_id = of_message_to_object_id(msg, len); uint8_t *buf = OF_MESSAGE_TO_BUFFER(msg); switch (object_id) { """ % dict(ver_name=ver_name)) for cls in reversed(of_g.standard_class_order): if not loxi_utils.class_in_version(cls, version): continue if cls in type_maps.inheritance_map: continue if loxi_utils.class_is_message(cls): out.write("""\ case %(cls_id)s: return %(cls)s_%(ver_name)s_validate(buf, len); """ % dict(ver_name=ver_name, cls=cls, cls_id=cls.upper())) out.write("""\ default: VALIDATOR_LOG("%(cls)s: could not map %(cls_id)s"); return -1; } } """ % dict(ver_name=ver_name, cls=cls, cls_id=cls.upper())) out.write(""" int of_validate_message(of_message_t msg, int len) { of_version_t version; if (len < OF_MESSAGE_MIN_LENGTH || len != of_message_length_get(msg)) { VALIDATOR_LOG("message length %d != %d", len, of_message_length_get(msg)); return -1; } version = of_message_version_get(msg); switch (version) { """) for version in of_g.of_version_range: ver_name = loxi_utils.version_to_name(version) out.write("""\ case %(ver_name)s: return of_validate_message_%(ver_name)s(msg, len); """ % dict(ver_name=ver_name)) out.write("""\ default: VALIDATOR_LOG("Bad version %%d", %(ver_name)s); return -1; } } """ % dict(ver_name=ver_name))
def gen_obj_show_c(out, name): loxi_utils.gen_c_copy_license(out) out.write(""" /** * * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen. * * Source file for object showing. * */ #define DISABLE_WARN_UNUSED_RESULT #include <loci/loci.h> #include <loci/loci_show.h> #include <loci/loci_obj_show.h> static int unknown_show(loci_writer_f writer, void* cookie, of_object_t *obj) { return writer(cookie, "Unable to print object of type %d, version %d\\n", obj->object_id, obj->version); } """) for version in of_g.of_version_range: ver_name = loxi_utils.version_to_name(version) for cls in of_g.standard_class_order: if not loxi_utils.class_in_version(cls, version): continue if type_maps.class_is_virtual(cls): continue out.write(""" int %(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, of_object_t *obj) { int out = 0; """ % dict(cls=cls, ver_name=ver_name)) members, member_types = loxi_utils.all_member_types_get(cls, version) for m_type in member_types: if loxi_utils.type_is_scalar(m_type) or m_type in \ ["of_match_t", "of_octets_t"]: # Declare instance of these out.write(" %s %s;\n" % (m_type, var_name_map(m_type))) else: out.write(""" %(m_type)s %(v_name)s; """ % dict(m_type=m_type, v_name=var_name_map(m_type))) if loxi_utils.class_is_list(m_type): out.write(" of_object_t elt;\n int rv;\n") for member in members: m_type = member["m_type"] m_name = member["name"] emitter = gen_emitter(cls, m_name, m_type) if loxi_utils.skip_member_name(m_name): continue if (loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]): out.write(""" %(cls)s_%(m_name)s_get(obj, &%(v_name)s); out += writer(cookie, "%(m_name)s="); out += %(emitter)s(writer, cookie, %(v_name)s); out += writer(cookie, " "); """ % dict(cls=cls, m_name=m_name, m_type=m_type, v_name=var_name_map(m_type), emitter=emitter)) elif loxi_utils.class_is_list(m_type): sub_cls = m_type[:-2] # Trim _t elt_type = loxi_utils.list_to_entry_type(m_type) out.write(""" out += writer(cookie, "%(elt_type)s={ "); %(cls)s_%(m_name)s_bind(obj, &%(v_name)s); %(u_type)s_ITER(&%(v_name)s, &elt, rv) { of_object_show(writer, cookie, (of_object_t *)&elt); } out += writer(cookie, "} "); """ % dict(sub_cls=sub_cls, u_type=sub_cls.upper(), v_name=var_name_map(m_type), elt_type=elt_type, cls=cls, m_name=m_name, m_type=m_type)) else: sub_cls = m_type[:-2] # Trim _t out.write(""" %(cls)s_%(m_name)s_bind(obj, &%(v_name)s); out += of_object_show(writer, cookie, &%(v_name)s); """ % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, v_name=var_name_map(m_type), ver_name=ver_name)) out.write(""" return out; } """) out.write(""" /** * Log a match entry */ int loci_show_match(loci_writer_f writer, void* cookie, of_match_t *match) { int out = 0; """) for key, entry in match.of_match_members.items(): m_type = entry["m_type"] emitter = gen_emitter('of_match', key, m_type) out.write(""" if (OF_MATCH_MASK_%(ku)s_ACTIVE_TEST(match)) { out += writer(cookie, "%(key)s active="); out += %(emitter)s(writer, cookie, match->fields.%(key)s); out += writer(cookie, "/"); out += %(emitter)s(writer, cookie, match->masks.%(key)s); out += writer(cookie, " "); } """ % dict(key=key, ku=key.upper(), emitter=emitter, m_type=m_type)) out.write(""" return out; } """) # Generate big table indexed by version and object for version in of_g.of_version_range: out.write(""" static const loci_obj_show_f show_funs_v%(version)s[OF_OBJECT_COUNT] = { """ % dict(version=version)) out.write(" unknown_show, /* of_object, not a valid specific type */\n") for j, cls in enumerate(of_g.all_class_order): comma = "" if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma comma = "," if (not loxi_utils.class_in_version(cls, version) or type_maps.class_is_virtual(cls)): out.write(" unknown_show%s\n" % comma); else: out.write(" %s_%s_show%s\n" % (cls, loxi_utils.version_to_name(version), comma)) out.write("};\n\n") out.write(""" static const loci_obj_show_f *const show_funs[] = { """) for version in of_g.of_version_range: out.write(" [%(v)d] = show_funs_v%(v)d,\n" % dict(v=version)) out.write("""\ }; int of_object_show(loci_writer_f writer, void* cookie, of_object_t *obj) { if ((obj->object_id > 0) && (obj->object_id < OF_OBJECT_COUNT)) { if (OF_VERSION_OKAY(obj->version)) { return show_funs[obj->version][obj->object_id](writer, cookie, (of_object_t *)obj); } else { return writer(cookie, "Bad version %d\\n", obj->version); } } return writer(cookie, "Bad object id %d\\n", obj->object_id); } """)