aboutsummaryrefslogtreecommitdiffstats
path: root/tools/net/ynl/lib/ynl.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/net/ynl/lib/ynl.py')
-rw-r--r--tools/net/ynl/lib/ynl.py98
1 files changed, 73 insertions, 25 deletions
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index 92995bca14e1..1e10512b2117 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -98,12 +98,12 @@ class NlAttr:
}
def __init__(self, raw, offset):
- self._len, self._type = struct.unpack("HH", raw[offset:offset + 4])
+ self._len, self._type = struct.unpack("HH", raw[offset : offset + 4])
self.type = self._type & ~Netlink.NLA_TYPE_MASK
self.is_nest = self._type & Netlink.NLA_F_NESTED
self.payload_len = self._len
self.full_len = (self.payload_len + 3) & ~3
- self.raw = raw[offset + 4:offset + self.payload_len]
+ self.raw = raw[offset + 4 : offset + self.payload_len]
@classmethod
def get_format(cls, attr_type, byte_order=None):
@@ -154,7 +154,7 @@ class NlAttr:
for m in members:
# TODO: handle non-scalar members
if m.type == 'binary':
- decoded = self.raw[offset:offset+m['len']]
+ decoded = self.raw[offset : offset + m['len']]
offset += m['len']
elif m.type in NlAttr.type_formats:
format = self.get_format(m.type, m.byte_order)
@@ -170,10 +170,9 @@ class NlAttr:
class NlAttrs:
- def __init__(self, msg):
+ def __init__(self, msg, offset=0):
self.attrs = []
- offset = 0
while offset < len(msg):
attr = NlAttr(msg, offset)
offset += attr.full_len
@@ -193,12 +192,12 @@ class NlAttrs:
class NlMsg:
def __init__(self, msg, offset, attr_space=None):
- self.hdr = msg[offset:offset + 16]
+ self.hdr = msg[offset : offset + 16]
self.nl_len, self.nl_type, self.nl_flags, self.nl_seq, self.nl_portid = \
struct.unpack("IHHII", self.hdr)
- self.raw = msg[offset + 16:offset + self.nl_len]
+ self.raw = msg[offset + 16 : offset + self.nl_len]
self.error = 0
self.done = 0
@@ -371,8 +370,8 @@ class NetlinkProtocol:
fixed_header_size = 0
if ynl:
op = ynl.rsp_by_value[msg.cmd()]
- fixed_header_size = ynl._fixed_header_size(op)
- msg.raw_attrs = NlAttrs(msg.raw[fixed_header_size:])
+ fixed_header_size = ynl._fixed_header_size(op.fixed_header)
+ msg.raw_attrs = NlAttrs(msg.raw, fixed_header_size)
return msg
def get_mcast_id(self, mcast_name, mcast_groups):
@@ -549,6 +548,37 @@ class YnlFamily(SpecFamily):
else:
rsp[name] = [decoded]
+ def _resolve_selector(self, attr_spec, vals):
+ sub_msg = attr_spec.sub_message
+ if sub_msg not in self.sub_msgs:
+ raise Exception(f"No sub-message spec named {sub_msg} for {attr_spec.name}")
+ sub_msg_spec = self.sub_msgs[sub_msg]
+
+ selector = attr_spec.selector
+ if selector not in vals:
+ raise Exception(f"There is no value for {selector} to resolve '{attr_spec.name}'")
+ value = vals[selector]
+ if value not in sub_msg_spec.formats:
+ raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'")
+
+ spec = sub_msg_spec.formats[value]
+ return spec
+
+ def _decode_sub_msg(self, attr, attr_spec, rsp):
+ msg_format = self._resolve_selector(attr_spec, rsp)
+ decoded = {}
+ offset = 0
+ if msg_format.fixed_header:
+ decoded.update(self._decode_fixed_header(attr, msg_format.fixed_header));
+ offset = self._fixed_header_size(msg_format.fixed_header)
+ if msg_format.attr_set:
+ if msg_format.attr_set in self.attr_sets:
+ subdict = self._decode(NlAttrs(attr.raw, offset), msg_format.attr_set)
+ decoded.update(subdict)
+ else:
+ raise Exception(f"Unknown attribute-set '{attr_space}' when decoding '{attr_spec.name}'")
+ return decoded
+
def _decode(self, attrs, space):
if space:
attr_space = self.attr_sets[space]
@@ -586,6 +616,8 @@ class YnlFamily(SpecFamily):
value = self._decode_enum(value, attr_spec)
selector = self._decode_enum(selector, attr_spec)
decoded = {"value": value, "selector": selector}
+ elif attr_spec["type"] == 'sub-message':
+ decoded = self._decode_sub_msg(attr, attr_spec, rsp)
else:
if not self.process_unknown:
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
@@ -626,20 +658,23 @@ class YnlFamily(SpecFamily):
return
msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set))
- offset = 20 + self._fixed_header_size(op)
+ offset = 20 + self._fixed_header_size(op.fixed_header)
path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset,
extack['bad-attr-offs'])
if path:
del extack['bad-attr-offs']
extack['bad-attr'] = path
- def _fixed_header_size(self, op):
- if op.fixed_header:
- fixed_header_members = self.consts[op.fixed_header].members
+ def _fixed_header_size(self, name):
+ if name:
+ fixed_header_members = self.consts[name].members
size = 0
for m in fixed_header_members:
- format = NlAttr.get_format(m.type, m.byte_order)
- size += format.size
+ if m.type in ['pad', 'binary']:
+ size += m.len
+ else:
+ format = NlAttr.get_format(m.type, m.byte_order)
+ size += format.size
return size
else:
return 0
@@ -649,12 +684,20 @@ class YnlFamily(SpecFamily):
fixed_header_attrs = dict()
offset = 0
for m in fixed_header_members:
- format = NlAttr.get_format(m.type, m.byte_order)
- [ value ] = format.unpack_from(msg.raw, offset)
- offset += format.size
- if m.enum:
- value = self._decode_enum(value, m)
- fixed_header_attrs[m.name] = value
+ value = None
+ if m.type == 'pad':
+ offset += m.len
+ elif m.type == 'binary':
+ value = msg.raw[offset : offset + m.len]
+ offset += m.len
+ else:
+ format = NlAttr.get_format(m.type, m.byte_order)
+ [ value ] = format.unpack_from(msg.raw, offset)
+ offset += format.size
+ if value is not None:
+ if m.enum:
+ value = self._decode_enum(value, m)
+ fixed_header_attrs[m.name] = value
return fixed_header_attrs
def handle_ntf(self, decoded):
@@ -705,7 +748,7 @@ class YnlFamily(SpecFamily):
return op['do']['request']['attributes'].copy()
- def _op(self, method, vals, flags, dump=False):
+ def _op(self, method, vals, flags=None, dump=False):
op = self.ops[method]
nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK
@@ -721,8 +764,13 @@ class YnlFamily(SpecFamily):
fixed_header_members = self.consts[op.fixed_header].members
for m in fixed_header_members:
value = vals.pop(m.name) if m.name in vals else 0
- format = NlAttr.get_format(m.type, m.byte_order)
- msg += format.pack(value)
+ if m.type == 'pad':
+ msg += bytearray(m.len)
+ elif m.type == 'binary':
+ msg += bytes.fromhex(value)
+ else:
+ format = NlAttr.get_format(m.type, m.byte_order)
+ msg += format.pack(value)
for name, value in vals.items():
msg += self._add_attr(op.attr_set.name, name, value)
msg = _genl_msg_finalize(msg)
@@ -769,7 +817,7 @@ class YnlFamily(SpecFamily):
return rsp[0]
return rsp
- def do(self, method, vals, flags):
+ def do(self, method, vals, flags=None):
return self._op(method, vals, flags)
def dump(self, method, vals):