Skip to content

Commit d96e48a

Browse files
Jiri Pirkokuba-moo
authored andcommitted
tools: ynl: introduce option to process unknown attributes or types
In case the kernel sends message back containing attribute not defined in family spec, following exception is raised to the user: $ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/devlink.yaml --do trap-get --json '{"bus-name": "netdevsim", "dev-name": "netdevsim1", "trap-name": "source_mac_is_multicast"}' Traceback (most recent call last): File "/home/jiri/work/linux/tools/net/ynl/lib/ynl.py", line 521, in _decode attr_spec = attr_space.attrs_by_val[attr.type] ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ KeyError: 132 During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/jiri/work/linux/./tools/net/ynl/cli.py", line 61, in <module> main() File "/home/jiri/work/linux/./tools/net/ynl/cli.py", line 49, in main reply = ynl.do(args.do, attrs, args.flags) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/jiri/work/linux/tools/net/ynl/lib/ynl.py", line 731, in do return self._op(method, vals, flags) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/jiri/work/linux/tools/net/ynl/lib/ynl.py", line 719, in _op rsp_msg = self._decode(decoded.raw_attrs, op.attr_set.name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/jiri/work/linux/tools/net/ynl/lib/ynl.py", line 525, in _decode raise Exception(f"Space '{space}' has no attribute with value '{attr.type}'") Exception: Space 'devlink' has no attribute with value '132' Introduce a command line option "process-unknown" and pass it down to YnlFamily class constructor to allow user to process unknown attributes and types and print them as binaries. $ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/devlink.yaml --do trap-get --json '{"bus-name": "netdevsim", "dev-name": "netdevsim1", "trap-name": "source_mac_is_multicast"}' --process-unknown {'UnknownAttr(129)': {'UnknownAttr(0)': b'\x00\x00\x00\x00\x00\x00\x00\x00', 'UnknownAttr(1)': b'\x00\x00\x00\x00\x00\x00\x00\x00', 'UnknownAttr(2)': b'\x0e\x00\x00\x00\x00\x00\x00\x00'}, 'UnknownAttr(132)': b'\x00', 'UnknownAttr(133)': b'', 'UnknownAttr(134)': {'UnknownAttr(0)': b''}, 'bus-name': 'netdevsim', 'dev-name': 'netdevsim1', 'trap-action': 'drop', 'trap-group-name': 'l2_drops', 'trap-name': 'source_mac_is_multicast'} Signed-off-by: Jiri Pirko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ff672b9 commit d96e48a

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

tools/net/ynl/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def main():
2727
const=Netlink.NLM_F_CREATE)
2828
parser.add_argument('--append', dest='flags', action='append_const',
2929
const=Netlink.NLM_F_APPEND)
30+
parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction)
3031
args = parser.parse_args()
3132

3233
if args.no_schema:
@@ -36,7 +37,7 @@ def main():
3637
if args.json_text:
3738
attrs = json.loads(args.json_text)
3839

39-
ynl = YnlFamily(args.spec, args.schema)
40+
ynl = YnlFamily(args.spec, args.schema, args.process_unknown)
4041

4142
if args.ntf:
4243
ynl.ntf_subscribe(args.ntf)

tools/net/ynl/lib/ynl.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class NlAttr:
100100
def __init__(self, raw, offset):
101101
self._len, self._type = struct.unpack("HH", raw[offset:offset + 4])
102102
self.type = self._type & ~Netlink.NLA_TYPE_MASK
103+
self.is_nest = self._type & Netlink.NLA_F_NESTED
103104
self.payload_len = self._len
104105
self.full_len = (self.payload_len + 3) & ~3
105106
self.raw = raw[offset + 4:offset + self.payload_len]
@@ -411,10 +412,11 @@ def get_mcast_id(self, mcast_name, mcast_groups):
411412

412413

413414
class YnlFamily(SpecFamily):
414-
def __init__(self, def_path, schema=None):
415+
def __init__(self, def_path, schema=None, process_unknown=False):
415416
super().__init__(def_path, schema)
416417

417418
self.include_raw = False
419+
self.process_unknown = process_unknown
418420

419421
try:
420422
if self.proto == "netlink-raw":
@@ -526,14 +528,41 @@ def _decode_array_nest(self, attr, attr_spec):
526528
decoded.append({ item.type: subattrs })
527529
return decoded
528530

531+
def _decode_unknown(self, attr):
532+
if attr.is_nest:
533+
return self._decode(NlAttrs(attr.raw), None)
534+
else:
535+
return attr.as_bin()
536+
537+
def _rsp_add(self, rsp, name, is_multi, decoded):
538+
if is_multi == None:
539+
if name in rsp and type(rsp[name]) is not list:
540+
rsp[name] = [rsp[name]]
541+
is_multi = True
542+
else:
543+
is_multi = False
544+
545+
if not is_multi:
546+
rsp[name] = decoded
547+
elif name in rsp:
548+
rsp[name].append(decoded)
549+
else:
550+
rsp[name] = [decoded]
551+
529552
def _decode(self, attrs, space):
530-
attr_space = self.attr_sets[space]
553+
if space:
554+
attr_space = self.attr_sets[space]
531555
rsp = dict()
532556
for attr in attrs:
533557
try:
534558
attr_spec = attr_space.attrs_by_val[attr.type]
535-
except KeyError:
536-
raise Exception(f"Space '{space}' has no attribute with value '{attr.type}'")
559+
except (KeyError, UnboundLocalError):
560+
if not self.process_unknown:
561+
raise Exception(f"Space '{space}' has no attribute with value '{attr.type}'")
562+
attr_name = f"UnknownAttr({attr.type})"
563+
self._rsp_add(rsp, attr_name, None, self._decode_unknown(attr))
564+
continue
565+
537566
if attr_spec["type"] == 'nest':
538567
subdict = self._decode(NlAttrs(attr.raw), attr_spec['nested-attributes'])
539568
decoded = subdict
@@ -558,14 +587,11 @@ def _decode(self, attrs, space):
558587
selector = self._decode_enum(selector, attr_spec)
559588
decoded = {"value": value, "selector": selector}
560589
else:
561-
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
590+
if not self.process_unknown:
591+
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
592+
decoded = self._decode_unknown(attr)
562593

563-
if not attr_spec.is_multi:
564-
rsp[attr_spec['name']] = decoded
565-
elif attr_spec.name in rsp:
566-
rsp[attr_spec.name].append(decoded)
567-
else:
568-
rsp[attr_spec.name] = [decoded]
594+
self._rsp_add(rsp, attr_spec["name"], attr_spec.is_multi, decoded)
569595

570596
return rsp
571597

0 commit comments

Comments
 (0)