162306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci 362306a36Sopenharmony_ciimport collections 462306a36Sopenharmony_ciimport importlib 562306a36Sopenharmony_ciimport os 662306a36Sopenharmony_ciimport yaml 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci# To be loaded dynamically as needed 1062306a36Sopenharmony_cijsonschema = None 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ciclass SpecElement: 1462306a36Sopenharmony_ci """Netlink spec element. 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci Abstract element of the Netlink spec. Implements the dictionary interface 1762306a36Sopenharmony_ci for access to the raw spec. Supports iterative resolution of dependencies 1862306a36Sopenharmony_ci across elements and class inheritance levels. The elements of the spec 1962306a36Sopenharmony_ci may refer to each other, and although loops should be very rare, having 2062306a36Sopenharmony_ci to maintain correct ordering of instantiation is painful, so the resolve() 2162306a36Sopenharmony_ci method should be used to perform parts of init which require access to 2262306a36Sopenharmony_ci other parts of the spec. 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci Attributes: 2562306a36Sopenharmony_ci yaml raw spec as loaded from the spec file 2662306a36Sopenharmony_ci family back reference to the full family 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci name name of the entity as listed in the spec (optional) 2962306a36Sopenharmony_ci ident_name name which can be safely used as identifier in code (optional) 3062306a36Sopenharmony_ci """ 3162306a36Sopenharmony_ci def __init__(self, family, yaml): 3262306a36Sopenharmony_ci self.yaml = yaml 3362306a36Sopenharmony_ci self.family = family 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if 'name' in self.yaml: 3662306a36Sopenharmony_ci self.name = self.yaml['name'] 3762306a36Sopenharmony_ci self.ident_name = self.name.replace('-', '_') 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci self._super_resolved = False 4062306a36Sopenharmony_ci family.add_unresolved(self) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci def __getitem__(self, key): 4362306a36Sopenharmony_ci return self.yaml[key] 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci def __contains__(self, key): 4662306a36Sopenharmony_ci return key in self.yaml 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci def get(self, key, default=None): 4962306a36Sopenharmony_ci return self.yaml.get(key, default) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci def resolve_up(self, up): 5262306a36Sopenharmony_ci if not self._super_resolved: 5362306a36Sopenharmony_ci up.resolve() 5462306a36Sopenharmony_ci self._super_resolved = True 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci def resolve(self): 5762306a36Sopenharmony_ci pass 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ciclass SpecEnumEntry(SpecElement): 6162306a36Sopenharmony_ci """ Entry within an enum declared in the Netlink spec. 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci Attributes: 6462306a36Sopenharmony_ci doc documentation string 6562306a36Sopenharmony_ci enum_set back reference to the enum 6662306a36Sopenharmony_ci value numerical value of this enum (use accessors in most situations!) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci Methods: 6962306a36Sopenharmony_ci raw_value raw value, i.e. the id in the enum, unlike user value which is a mask for flags 7062306a36Sopenharmony_ci user_value user value, same as raw value for enums, for flags it's the mask 7162306a36Sopenharmony_ci """ 7262306a36Sopenharmony_ci def __init__(self, enum_set, yaml, prev, value_start): 7362306a36Sopenharmony_ci if isinstance(yaml, str): 7462306a36Sopenharmony_ci yaml = {'name': yaml} 7562306a36Sopenharmony_ci super().__init__(enum_set.family, yaml) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci self.doc = yaml.get('doc', '') 7862306a36Sopenharmony_ci self.enum_set = enum_set 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if 'value' in yaml: 8162306a36Sopenharmony_ci self.value = yaml['value'] 8262306a36Sopenharmony_ci elif prev: 8362306a36Sopenharmony_ci self.value = prev.value + 1 8462306a36Sopenharmony_ci else: 8562306a36Sopenharmony_ci self.value = value_start 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci def has_doc(self): 8862306a36Sopenharmony_ci return bool(self.doc) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci def raw_value(self): 9162306a36Sopenharmony_ci return self.value 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci def user_value(self, as_flags=None): 9462306a36Sopenharmony_ci if self.enum_set['type'] == 'flags' or as_flags: 9562306a36Sopenharmony_ci return 1 << self.value 9662306a36Sopenharmony_ci else: 9762306a36Sopenharmony_ci return self.value 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciclass SpecEnumSet(SpecElement): 10162306a36Sopenharmony_ci """ Enum type 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci Represents an enumeration (list of numerical constants) 10462306a36Sopenharmony_ci as declared in the "definitions" section of the spec. 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci Attributes: 10762306a36Sopenharmony_ci type enum or flags 10862306a36Sopenharmony_ci entries entries by name 10962306a36Sopenharmony_ci entries_by_val entries by value 11062306a36Sopenharmony_ci Methods: 11162306a36Sopenharmony_ci get_mask for flags compute the mask of all defined values 11262306a36Sopenharmony_ci """ 11362306a36Sopenharmony_ci def __init__(self, family, yaml): 11462306a36Sopenharmony_ci super().__init__(family, yaml) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci self.type = yaml['type'] 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci prev_entry = None 11962306a36Sopenharmony_ci value_start = self.yaml.get('value-start', 0) 12062306a36Sopenharmony_ci self.entries = dict() 12162306a36Sopenharmony_ci self.entries_by_val = dict() 12262306a36Sopenharmony_ci for entry in self.yaml['entries']: 12362306a36Sopenharmony_ci e = self.new_entry(entry, prev_entry, value_start) 12462306a36Sopenharmony_ci self.entries[e.name] = e 12562306a36Sopenharmony_ci self.entries_by_val[e.raw_value()] = e 12662306a36Sopenharmony_ci prev_entry = e 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci def new_entry(self, entry, prev_entry, value_start): 12962306a36Sopenharmony_ci return SpecEnumEntry(self, entry, prev_entry, value_start) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci def has_doc(self): 13262306a36Sopenharmony_ci if 'doc' in self.yaml: 13362306a36Sopenharmony_ci return True 13462306a36Sopenharmony_ci for entry in self.entries.values(): 13562306a36Sopenharmony_ci if entry.has_doc(): 13662306a36Sopenharmony_ci return True 13762306a36Sopenharmony_ci return False 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci def get_mask(self, as_flags=None): 14062306a36Sopenharmony_ci mask = 0 14162306a36Sopenharmony_ci for e in self.entries.values(): 14262306a36Sopenharmony_ci mask += e.user_value(as_flags) 14362306a36Sopenharmony_ci return mask 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciclass SpecAttr(SpecElement): 14762306a36Sopenharmony_ci """ Single Netlink atttribute type 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci Represents a single attribute type within an attr space. 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci Attributes: 15262306a36Sopenharmony_ci value numerical ID when serialized 15362306a36Sopenharmony_ci attr_set Attribute Set containing this attr 15462306a36Sopenharmony_ci is_multi bool, attr may repeat multiple times 15562306a36Sopenharmony_ci struct_name string, name of struct definition 15662306a36Sopenharmony_ci sub_type string, name of sub type 15762306a36Sopenharmony_ci len integer, optional byte length of binary types 15862306a36Sopenharmony_ci display_hint string, hint to help choose format specifier 15962306a36Sopenharmony_ci when displaying the value 16062306a36Sopenharmony_ci """ 16162306a36Sopenharmony_ci def __init__(self, family, attr_set, yaml, value): 16262306a36Sopenharmony_ci super().__init__(family, yaml) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci self.value = value 16562306a36Sopenharmony_ci self.attr_set = attr_set 16662306a36Sopenharmony_ci self.is_multi = yaml.get('multi-attr', False) 16762306a36Sopenharmony_ci self.struct_name = yaml.get('struct') 16862306a36Sopenharmony_ci self.sub_type = yaml.get('sub-type') 16962306a36Sopenharmony_ci self.byte_order = yaml.get('byte-order') 17062306a36Sopenharmony_ci self.len = yaml.get('len') 17162306a36Sopenharmony_ci self.display_hint = yaml.get('display-hint') 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciclass SpecAttrSet(SpecElement): 17562306a36Sopenharmony_ci """ Netlink Attribute Set class. 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci Represents a ID space of attributes within Netlink. 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci Note that unlike other elements, which expose contents of the raw spec 18062306a36Sopenharmony_ci via the dictionary interface Attribute Set exposes attributes by name. 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci Attributes: 18362306a36Sopenharmony_ci attrs ordered dict of all attributes (indexed by name) 18462306a36Sopenharmony_ci attrs_by_val ordered dict of all attributes (indexed by value) 18562306a36Sopenharmony_ci subset_of parent set if this is a subset, otherwise None 18662306a36Sopenharmony_ci """ 18762306a36Sopenharmony_ci def __init__(self, family, yaml): 18862306a36Sopenharmony_ci super().__init__(family, yaml) 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci self.subset_of = self.yaml.get('subset-of', None) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci self.attrs = collections.OrderedDict() 19362306a36Sopenharmony_ci self.attrs_by_val = collections.OrderedDict() 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if self.subset_of is None: 19662306a36Sopenharmony_ci val = 1 19762306a36Sopenharmony_ci for elem in self.yaml['attributes']: 19862306a36Sopenharmony_ci if 'value' in elem: 19962306a36Sopenharmony_ci val = elem['value'] 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci attr = self.new_attr(elem, val) 20262306a36Sopenharmony_ci self.attrs[attr.name] = attr 20362306a36Sopenharmony_ci self.attrs_by_val[attr.value] = attr 20462306a36Sopenharmony_ci val += 1 20562306a36Sopenharmony_ci else: 20662306a36Sopenharmony_ci real_set = family.attr_sets[self.subset_of] 20762306a36Sopenharmony_ci for elem in self.yaml['attributes']: 20862306a36Sopenharmony_ci attr = real_set[elem['name']] 20962306a36Sopenharmony_ci self.attrs[attr.name] = attr 21062306a36Sopenharmony_ci self.attrs_by_val[attr.value] = attr 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci def new_attr(self, elem, value): 21362306a36Sopenharmony_ci return SpecAttr(self.family, self, elem, value) 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci def __getitem__(self, key): 21662306a36Sopenharmony_ci return self.attrs[key] 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci def __contains__(self, key): 21962306a36Sopenharmony_ci return key in self.attrs 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci def __iter__(self): 22262306a36Sopenharmony_ci yield from self.attrs 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci def items(self): 22562306a36Sopenharmony_ci return self.attrs.items() 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciclass SpecStructMember(SpecElement): 22962306a36Sopenharmony_ci """Struct member attribute 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci Represents a single struct member attribute. 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci Attributes: 23462306a36Sopenharmony_ci type string, type of the member attribute 23562306a36Sopenharmony_ci byte_order string or None for native byte order 23662306a36Sopenharmony_ci enum string, name of the enum definition 23762306a36Sopenharmony_ci len integer, optional byte length of binary types 23862306a36Sopenharmony_ci display_hint string, hint to help choose format specifier 23962306a36Sopenharmony_ci when displaying the value 24062306a36Sopenharmony_ci """ 24162306a36Sopenharmony_ci def __init__(self, family, yaml): 24262306a36Sopenharmony_ci super().__init__(family, yaml) 24362306a36Sopenharmony_ci self.type = yaml['type'] 24462306a36Sopenharmony_ci self.byte_order = yaml.get('byte-order') 24562306a36Sopenharmony_ci self.enum = yaml.get('enum') 24662306a36Sopenharmony_ci self.len = yaml.get('len') 24762306a36Sopenharmony_ci self.display_hint = yaml.get('display-hint') 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciclass SpecStruct(SpecElement): 25162306a36Sopenharmony_ci """Netlink struct type 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci Represents a C struct definition. 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci Attributes: 25662306a36Sopenharmony_ci members ordered list of struct members 25762306a36Sopenharmony_ci """ 25862306a36Sopenharmony_ci def __init__(self, family, yaml): 25962306a36Sopenharmony_ci super().__init__(family, yaml) 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci self.members = [] 26262306a36Sopenharmony_ci for member in yaml.get('members', []): 26362306a36Sopenharmony_ci self.members.append(self.new_member(family, member)) 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci def new_member(self, family, elem): 26662306a36Sopenharmony_ci return SpecStructMember(family, elem) 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci def __iter__(self): 26962306a36Sopenharmony_ci yield from self.members 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci def items(self): 27262306a36Sopenharmony_ci return self.members.items() 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ciclass SpecOperation(SpecElement): 27662306a36Sopenharmony_ci """Netlink Operation 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci Information about a single Netlink operation. 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci Attributes: 28162306a36Sopenharmony_ci value numerical ID when serialized, None if req/rsp values differ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci req_value numerical ID when serialized, user -> kernel 28462306a36Sopenharmony_ci rsp_value numerical ID when serialized, user <- kernel 28562306a36Sopenharmony_ci is_call bool, whether the operation is a call 28662306a36Sopenharmony_ci is_async bool, whether the operation is a notification 28762306a36Sopenharmony_ci is_resv bool, whether the operation does not exist (it's just a reserved ID) 28862306a36Sopenharmony_ci attr_set attribute set name 28962306a36Sopenharmony_ci fixed_header string, optional name of fixed header struct 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci yaml raw spec as loaded from the spec file 29262306a36Sopenharmony_ci """ 29362306a36Sopenharmony_ci def __init__(self, family, yaml, req_value, rsp_value): 29462306a36Sopenharmony_ci super().__init__(family, yaml) 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci self.value = req_value if req_value == rsp_value else None 29762306a36Sopenharmony_ci self.req_value = req_value 29862306a36Sopenharmony_ci self.rsp_value = rsp_value 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci self.is_call = 'do' in yaml or 'dump' in yaml 30162306a36Sopenharmony_ci self.is_async = 'notify' in yaml or 'event' in yaml 30262306a36Sopenharmony_ci self.is_resv = not self.is_async and not self.is_call 30362306a36Sopenharmony_ci self.fixed_header = self.yaml.get('fixed-header', family.fixed_header) 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci # Added by resolve: 30662306a36Sopenharmony_ci self.attr_set = None 30762306a36Sopenharmony_ci delattr(self, "attr_set") 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci def resolve(self): 31062306a36Sopenharmony_ci self.resolve_up(super()) 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if 'attribute-set' in self.yaml: 31362306a36Sopenharmony_ci attr_set_name = self.yaml['attribute-set'] 31462306a36Sopenharmony_ci elif 'notify' in self.yaml: 31562306a36Sopenharmony_ci msg = self.family.msgs[self.yaml['notify']] 31662306a36Sopenharmony_ci attr_set_name = msg['attribute-set'] 31762306a36Sopenharmony_ci elif self.is_resv: 31862306a36Sopenharmony_ci attr_set_name = '' 31962306a36Sopenharmony_ci else: 32062306a36Sopenharmony_ci raise Exception(f"Can't resolve attribute set for op '{self.name}'") 32162306a36Sopenharmony_ci if attr_set_name: 32262306a36Sopenharmony_ci self.attr_set = self.family.attr_sets[attr_set_name] 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ciclass SpecMcastGroup(SpecElement): 32662306a36Sopenharmony_ci """Netlink Multicast Group 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci Information about a multicast group. 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci Value is only used for classic netlink families that use the 33162306a36Sopenharmony_ci netlink-raw schema. Genetlink families use dynamic ID allocation 33262306a36Sopenharmony_ci where the ids of multicast groups get resolved at runtime. Value 33362306a36Sopenharmony_ci will be None for genetlink families. 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci Attributes: 33662306a36Sopenharmony_ci name name of the mulitcast group 33762306a36Sopenharmony_ci value integer id of this multicast group for netlink-raw or None 33862306a36Sopenharmony_ci yaml raw spec as loaded from the spec file 33962306a36Sopenharmony_ci """ 34062306a36Sopenharmony_ci def __init__(self, family, yaml): 34162306a36Sopenharmony_ci super().__init__(family, yaml) 34262306a36Sopenharmony_ci self.value = self.yaml.get('value') 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ciclass SpecFamily(SpecElement): 34662306a36Sopenharmony_ci """ Netlink Family Spec class. 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci Netlink family information loaded from a spec (e.g. in YAML). 34962306a36Sopenharmony_ci Takes care of unfolding implicit information which can be skipped 35062306a36Sopenharmony_ci in the spec itself for brevity. 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci The class can be used like a dictionary to access the raw spec 35362306a36Sopenharmony_ci elements but that's usually a bad idea. 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci Attributes: 35662306a36Sopenharmony_ci proto protocol type (e.g. genetlink) 35762306a36Sopenharmony_ci msg_id_model enum-model for operations (unified, directional etc.) 35862306a36Sopenharmony_ci license spec license (loaded from an SPDX tag on the spec) 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci attr_sets dict of attribute sets 36162306a36Sopenharmony_ci msgs dict of all messages (index by name) 36262306a36Sopenharmony_ci ops dict of all valid requests / responses 36362306a36Sopenharmony_ci ntfs dict of all async events 36462306a36Sopenharmony_ci consts dict of all constants/enums 36562306a36Sopenharmony_ci fixed_header string, optional name of family default fixed header struct 36662306a36Sopenharmony_ci mcast_groups dict of all multicast groups (index by name) 36762306a36Sopenharmony_ci """ 36862306a36Sopenharmony_ci def __init__(self, spec_path, schema_path=None, exclude_ops=None): 36962306a36Sopenharmony_ci with open(spec_path, "r") as stream: 37062306a36Sopenharmony_ci prefix = '# SPDX-License-Identifier: ' 37162306a36Sopenharmony_ci first = stream.readline().strip() 37262306a36Sopenharmony_ci if not first.startswith(prefix): 37362306a36Sopenharmony_ci raise Exception('SPDX license tag required in the spec') 37462306a36Sopenharmony_ci self.license = first[len(prefix):] 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci stream.seek(0) 37762306a36Sopenharmony_ci spec = yaml.safe_load(stream) 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci self._resolution_list = [] 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci super().__init__(self, spec) 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci self._exclude_ops = exclude_ops if exclude_ops else [] 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci self.proto = self.yaml.get('protocol', 'genetlink') 38662306a36Sopenharmony_ci self.msg_id_model = self.yaml['operations'].get('enum-model', 'unified') 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if schema_path is None: 38962306a36Sopenharmony_ci schema_path = os.path.dirname(os.path.dirname(spec_path)) + f'/{self.proto}.yaml' 39062306a36Sopenharmony_ci if schema_path: 39162306a36Sopenharmony_ci global jsonschema 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci with open(schema_path, "r") as stream: 39462306a36Sopenharmony_ci schema = yaml.safe_load(stream) 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if jsonschema is None: 39762306a36Sopenharmony_ci jsonschema = importlib.import_module("jsonschema") 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci jsonschema.validate(self.yaml, schema) 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci self.attr_sets = collections.OrderedDict() 40262306a36Sopenharmony_ci self.msgs = collections.OrderedDict() 40362306a36Sopenharmony_ci self.req_by_value = collections.OrderedDict() 40462306a36Sopenharmony_ci self.rsp_by_value = collections.OrderedDict() 40562306a36Sopenharmony_ci self.ops = collections.OrderedDict() 40662306a36Sopenharmony_ci self.ntfs = collections.OrderedDict() 40762306a36Sopenharmony_ci self.consts = collections.OrderedDict() 40862306a36Sopenharmony_ci self.mcast_groups = collections.OrderedDict() 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci last_exception = None 41162306a36Sopenharmony_ci while len(self._resolution_list) > 0: 41262306a36Sopenharmony_ci resolved = [] 41362306a36Sopenharmony_ci unresolved = self._resolution_list 41462306a36Sopenharmony_ci self._resolution_list = [] 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci for elem in unresolved: 41762306a36Sopenharmony_ci try: 41862306a36Sopenharmony_ci elem.resolve() 41962306a36Sopenharmony_ci except (KeyError, AttributeError) as e: 42062306a36Sopenharmony_ci self._resolution_list.append(elem) 42162306a36Sopenharmony_ci last_exception = e 42262306a36Sopenharmony_ci continue 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci resolved.append(elem) 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if len(resolved) == 0: 42762306a36Sopenharmony_ci raise last_exception 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci def new_enum(self, elem): 43062306a36Sopenharmony_ci return SpecEnumSet(self, elem) 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci def new_attr_set(self, elem): 43362306a36Sopenharmony_ci return SpecAttrSet(self, elem) 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci def new_struct(self, elem): 43662306a36Sopenharmony_ci return SpecStruct(self, elem) 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci def new_operation(self, elem, req_val, rsp_val): 43962306a36Sopenharmony_ci return SpecOperation(self, elem, req_val, rsp_val) 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci def new_mcast_group(self, elem): 44262306a36Sopenharmony_ci return SpecMcastGroup(self, elem) 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci def add_unresolved(self, elem): 44562306a36Sopenharmony_ci self._resolution_list.append(elem) 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci def _dictify_ops_unified(self): 44862306a36Sopenharmony_ci self.fixed_header = self.yaml['operations'].get('fixed-header') 44962306a36Sopenharmony_ci val = 1 45062306a36Sopenharmony_ci for elem in self.yaml['operations']['list']: 45162306a36Sopenharmony_ci if 'value' in elem: 45262306a36Sopenharmony_ci val = elem['value'] 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci op = self.new_operation(elem, val, val) 45562306a36Sopenharmony_ci val += 1 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci self.msgs[op.name] = op 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci def _dictify_ops_directional(self): 46062306a36Sopenharmony_ci self.fixed_header = self.yaml['operations'].get('fixed-header') 46162306a36Sopenharmony_ci req_val = rsp_val = 1 46262306a36Sopenharmony_ci for elem in self.yaml['operations']['list']: 46362306a36Sopenharmony_ci if 'notify' in elem or 'event' in elem: 46462306a36Sopenharmony_ci if 'value' in elem: 46562306a36Sopenharmony_ci rsp_val = elem['value'] 46662306a36Sopenharmony_ci req_val_next = req_val 46762306a36Sopenharmony_ci rsp_val_next = rsp_val + 1 46862306a36Sopenharmony_ci req_val = None 46962306a36Sopenharmony_ci elif 'do' in elem or 'dump' in elem: 47062306a36Sopenharmony_ci mode = elem['do'] if 'do' in elem else elem['dump'] 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci v = mode.get('request', {}).get('value', None) 47362306a36Sopenharmony_ci if v: 47462306a36Sopenharmony_ci req_val = v 47562306a36Sopenharmony_ci v = mode.get('reply', {}).get('value', None) 47662306a36Sopenharmony_ci if v: 47762306a36Sopenharmony_ci rsp_val = v 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci rsp_inc = 1 if 'reply' in mode else 0 48062306a36Sopenharmony_ci req_val_next = req_val + 1 48162306a36Sopenharmony_ci rsp_val_next = rsp_val + rsp_inc 48262306a36Sopenharmony_ci else: 48362306a36Sopenharmony_ci raise Exception("Can't parse directional ops") 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if req_val == req_val_next: 48662306a36Sopenharmony_ci req_val = None 48762306a36Sopenharmony_ci if rsp_val == rsp_val_next: 48862306a36Sopenharmony_ci rsp_val = None 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci skip = False 49162306a36Sopenharmony_ci for exclude in self._exclude_ops: 49262306a36Sopenharmony_ci skip |= bool(exclude.match(elem['name'])) 49362306a36Sopenharmony_ci if not skip: 49462306a36Sopenharmony_ci op = self.new_operation(elem, req_val, rsp_val) 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci req_val = req_val_next 49762306a36Sopenharmony_ci rsp_val = rsp_val_next 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci self.msgs[op.name] = op 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci def find_operation(self, name): 50262306a36Sopenharmony_ci """ 50362306a36Sopenharmony_ci For a given operation name, find and return operation spec. 50462306a36Sopenharmony_ci """ 50562306a36Sopenharmony_ci for op in self.yaml['operations']['list']: 50662306a36Sopenharmony_ci if name == op['name']: 50762306a36Sopenharmony_ci return op 50862306a36Sopenharmony_ci return None 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci def resolve(self): 51162306a36Sopenharmony_ci self.resolve_up(super()) 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci definitions = self.yaml.get('definitions', []) 51462306a36Sopenharmony_ci for elem in definitions: 51562306a36Sopenharmony_ci if elem['type'] == 'enum' or elem['type'] == 'flags': 51662306a36Sopenharmony_ci self.consts[elem['name']] = self.new_enum(elem) 51762306a36Sopenharmony_ci elif elem['type'] == 'struct': 51862306a36Sopenharmony_ci self.consts[elem['name']] = self.new_struct(elem) 51962306a36Sopenharmony_ci else: 52062306a36Sopenharmony_ci self.consts[elem['name']] = elem 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci for elem in self.yaml['attribute-sets']: 52362306a36Sopenharmony_ci attr_set = self.new_attr_set(elem) 52462306a36Sopenharmony_ci self.attr_sets[elem['name']] = attr_set 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if self.msg_id_model == 'unified': 52762306a36Sopenharmony_ci self._dictify_ops_unified() 52862306a36Sopenharmony_ci elif self.msg_id_model == 'directional': 52962306a36Sopenharmony_ci self._dictify_ops_directional() 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci for op in self.msgs.values(): 53262306a36Sopenharmony_ci if op.req_value is not None: 53362306a36Sopenharmony_ci self.req_by_value[op.req_value] = op 53462306a36Sopenharmony_ci if op.rsp_value is not None: 53562306a36Sopenharmony_ci self.rsp_by_value[op.rsp_value] = op 53662306a36Sopenharmony_ci if not op.is_async and 'attribute-set' in op: 53762306a36Sopenharmony_ci self.ops[op.name] = op 53862306a36Sopenharmony_ci elif op.is_async: 53962306a36Sopenharmony_ci self.ntfs[op.name] = op 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci mcgs = self.yaml.get('mcast-groups') 54262306a36Sopenharmony_ci if mcgs: 54362306a36Sopenharmony_ci for elem in mcgs['list']: 54462306a36Sopenharmony_ci mcg = self.new_mcast_group(elem) 54562306a36Sopenharmony_ci self.mcast_groups[elem['name']] = mcg 546