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 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_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_list_validator(out, cls, version): ver_name = loxi_utils.version_to_name(version) e_cls = loxi_utils.list_to_entry_type(cls) fixed_len = of_g.base_length[(e_cls, version)] out.write(""" static inline int %(cls)s_%(ver_name)s_validate(uint8_t *buf, int len) { """ % dict(cls=cls, ver_name=ver_name, cls_id=cls.upper(), e_cls=e_cls)) # TLV16 if loxi_utils.class_is_tlv16(e_cls): subclasses = type_maps.inheritance_map[e_cls] out.write("""\ while (len >= %(fixed_len)s) { of_object_id_t e_id; uint16_t e_type, e_len; buf_u16_get(buf, &e_type); buf_u16_get(buf+2, &e_len); e_id = %(e_cls)s_to_object_id(e_type, %(ver_name)s); switch (e_id) { """ % dict(fixed_len=fixed_len, ver_name=ver_name, e_cls=e_cls)) for subcls in subclasses: subcls = e_cls + '_' + subcls if not loxi_utils.class_in_version(subcls, version): continue out.write("""\ case %(subcls_enum)s: if (%(subcls)s_%(ver_name)s_validate(buf, e_len) < 0) { return -1; } break; """ % dict(ver_name=ver_name, subcls=subcls, subcls_enum=loxi_utils.enum_name(subcls))) out.write("""\ default: return -1; } buf += e_len; len -= e_len; } if (len != 0) { return -1; } """ % dict(e_cls=e_cls, ver_name=ver_name)) # U16 len elif loxi_utils.class_is_u16_len(e_cls) or loxi_utils.class_is_action( e_cls): out.write("""\ /* TODO verify U16 len elements */ """ % dict()) # OXM elif loxi_utils.class_is_oxm(e_cls): out.write("""\ /* TODO verify OXM elements */ """ % dict()) # Fixed length elif not loxi_utils.class_is_var_len(e_cls, version): out.write("""\ if ((len / %(fixed_len)s) * %(fixed_len)s != len) { return -1; } """ % dict(fixed_len=fixed_len)) # ??? else: out.write("""\ /* XXX unknown element format */ """ % dict()) out.write(""" return 0; } """)
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); } """)
def gen_list_validator(out, cls, version): ver_name = loxi_utils.version_to_name(version) e_cls = loxi_utils.list_to_entry_type(cls) fixed_len = of_g.base_length[(e_cls, version)]; out.write(""" static inline int %(cls)s_%(ver_name)s_validate(uint8_t *buf, int len) { """ % dict(cls=cls, ver_name=ver_name, cls_id=cls.upper(), e_cls=e_cls)) # TLV16 if loxi_utils.class_is_tlv16(e_cls): subclasses = type_maps.inheritance_map[e_cls] out.write("""\ while (len >= %(fixed_len)s) { of_object_id_t e_id; uint16_t e_type, e_len; buf_u16_get(buf, &e_type); buf_u16_get(buf+2, &e_len); e_id = %(e_cls)s_to_object_id(e_type, %(ver_name)s); switch (e_id) { """ % dict(fixed_len=fixed_len, ver_name=ver_name, e_cls=e_cls)) for subcls in subclasses: subcls = e_cls + '_' + subcls if not loxi_utils.class_in_version(subcls, version): continue out.write("""\ case %(subcls_enum)s: if (%(subcls)s_%(ver_name)s_validate(buf, e_len) < 0) { return -1; } break; """ % dict(ver_name=ver_name, subcls=subcls, subcls_enum=loxi_utils.enum_name(subcls))) out.write("""\ default: return -1; } buf += e_len; len -= e_len; } if (len != 0) { return -1; } """ % dict(e_cls=e_cls, ver_name=ver_name)) # U16 len elif loxi_utils.class_is_u16_len(e_cls) or loxi_utils.class_is_action(e_cls): out.write("""\ /* TODO verify U16 len elements */ """ % dict()) # OXM elif loxi_utils.class_is_oxm(e_cls): out.write("""\ /* TODO verify OXM elements */ """ % dict()) # Fixed length elif not loxi_utils.class_is_var_len(e_cls, version): out.write("""\ if ((len / %(fixed_len)s) * %(fixed_len)s != len) { return -1; } """ % dict(fixed_len=fixed_len)) # ??? else: out.write("""\ /* XXX unknown element format */ """ % dict()) out.write(""" return 0; } """)