@@ -261,6 +261,13 @@ properties:
async-enum:
description: Name for the enum type with notifications/events.
type: string
+ # Start genetlink-legacy
+ fixed-header: &fixed-header
+ description: |
+ Name of the structure defininig the optional fixed-length protocol header. This header is
+ placed in a message after the netlink and genetlink headers and before any attributes.
+ type: string
+ # End genetlink-legacy
list:
description: List of commands
type: array
@@ -293,6 +300,9 @@ properties:
type: array
items:
enum: [ strict, dump ]
+ # Start genetlink-legacy
+ fixed-header: *fixed-header
+ # End genetlink-legacy
do: &subop-type
description: Main command handler.
type: object
@@ -257,18 +257,19 @@ class SpecOperation(SpecElement):
Information about a single Netlink operation.
Attributes:
- value numerical ID when serialized, None if req/rsp values differ
+ value numerical ID when serialized, None if req/rsp values differ
- req_value numerical ID when serialized, user -> kernel
- rsp_value numerical ID when serialized, user <- kernel
- is_call bool, whether the operation is a call
- is_async bool, whether the operation is a notification
- is_resv bool, whether the operation does not exist (it's just a reserved ID)
- attr_set attribute set name
+ req_value numerical ID when serialized, user -> kernel
+ rsp_value numerical ID when serialized, user <- kernel
+ is_call bool, whether the operation is a call
+ is_async bool, whether the operation is a notification
+ is_resv bool, whether the operation does not exist (it's just a reserved ID)
+ attr_set attribute set name
+ fixed_header string, optional fixed header structure name
- yaml raw spec as loaded from the spec file
+ yaml raw spec as loaded from the spec file
"""
- def __init__(self, family, yaml, req_value, rsp_value):
+ def __init__(self, family, yaml, req_value, rsp_value, default_fixed_header):
super().__init__(family, yaml)
self.value = req_value if req_value == rsp_value else None
@@ -278,6 +279,7 @@ class SpecOperation(SpecElement):
self.is_call = 'do' in yaml or 'dump' in yaml
self.is_async = 'notify' in yaml or 'event' in yaml
self.is_resv = not self.is_async and not self.is_call
+ self.fixed_header = self.yaml.get('fixed-header', default_fixed_header)
# Added by resolve:
self.attr_set = None
@@ -384,24 +386,26 @@ class SpecFamily(SpecElement):
def new_struct(self, elem):
return SpecStruct(self, elem)
- def new_operation(self, elem, req_val, rsp_val):
- return SpecOperation(self, elem, req_val, rsp_val)
+ def new_operation(self, elem, req_val, rsp_val, default_fixed_header):
+ return SpecOperation(self, elem, req_val, rsp_val, default_fixed_header)
def add_unresolved(self, elem):
self._resolution_list.append(elem)
def _dictify_ops_unified(self):
+ default_fixed_header = self.yaml['operations'].get('fixed-header')
val = 1
for elem in self.yaml['operations']['list']:
if 'value' in elem:
val = elem['value']
- op = self.new_operation(elem, val, val)
+ op = self.new_operation(elem, val, val, default_fixed_header)
val += 1
self.msgs[op.name] = op
def _dictify_ops_directional(self):
+ default_fixed_header = self.yaml['operations'].get('fixed-header')
req_val = rsp_val = 1
for elem in self.yaml['operations']['list']:
if 'notify' in elem:
@@ -426,7 +430,7 @@ class SpecFamily(SpecElement):
else:
raise Exception("Can't parse directional ops")
- op = self.new_operation(elem, req_val, rsp_val)
+ op = self.new_operation(elem, req_val, rsp_val, default_fixed_header)
req_val = req_val_next
rsp_val = rsp_val_next
@@ -277,14 +277,22 @@ def _genl_load_families():
class GenlMsg:
- def __init__(self, nl_msg):
+ def __init__(self, nl_msg, fixed_header_members = []):
self.nl = nl_msg
self.hdr = nl_msg.raw[0:4]
- self.raw = nl_msg.raw[4:]
+ offset = 4
self.genl_cmd, self.genl_version, _ = struct.unpack("BBH", self.hdr)
+ self.fixed_header_attrs = dict()
+ for m in fixed_header_members:
+ format, size = NlAttr.type_formats[m.type]
+ decoded = struct.unpack_from(format, nl_msg.raw, offset)
+ offset += size
+ self.fixed_header_attrs[m.name] = decoded[0]
+
+ self.raw = nl_msg.raw[offset:]
self.raw_attrs = NlAttrs(self.raw)
def __repr__(self):
@@ -496,6 +504,13 @@ class YnlFamily(SpecFamily):
req_seq = random.randint(1024, 65535)
msg = _genl_msg(self.family.family_id, nl_flags, op.req_value, 1, req_seq)
+ fixed_header_members = []
+ if op.fixed_header:
+ fixed_header_members = self.consts[op.fixed_header].members
+ for m in fixed_header_members:
+ value = vals.pop(m.name)
+ format, _ = NlAttr.type_formats[m.type]
+ msg += struct.pack(format, value)
for name, value in vals.items():
msg += self._add_attr(op.attr_set.name, name, value)
msg = _genl_msg_finalize(msg)
@@ -522,7 +537,7 @@ class YnlFamily(SpecFamily):
done = True
break
- gm = GenlMsg(nl_msg)
+ gm = GenlMsg(nl_msg, fixed_header_members)
# Check if this is a reply to our request
if nl_msg.nl_seq != req_seq or gm.genl_cmd != op.rsp_value:
if gm.genl_cmd in self.async_msg_ids:
@@ -532,7 +547,7 @@ class YnlFamily(SpecFamily):
print('Unexpected message: ' + repr(gm))
continue
- rsp.append(self._decode(gm.raw_attrs, op.attr_set.name))
+ rsp.append(self._decode(gm.raw_attrs, op.attr_set.name) | gm.fixed_header_attrs)
if not rsp:
return None
Add support for netlink families that add an optional fixed header structure after the genetlink header and before any attributes. The fixed-header can be specified on a per op basis, or once for all operations. Signed-off-by: Donald Hunter <donald.hunter@gmail.com> --- Documentation/netlink/genetlink-legacy.yaml | 10 +++++++ tools/net/ynl/lib/nlspec.py | 30 ++++++++++++--------- tools/net/ynl/lib/ynl.py | 23 +++++++++++++--- 3 files changed, 46 insertions(+), 17 deletions(-)