Commit 4cd2796f authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

tools: ynl: support pretty printing bad attribute names



One of my favorite features of the Netlink specs is that they
make decoding structured extack a ton easier.
Implement pretty printing bad attribute names in YNL.

For example it will now say:

  'bad-attr': '.header.flags'

rather than the useless:

  'bad-attr-offs': 32

Proof:

  $ ./cli.py --spec ethtool.yaml --do rings_get \
     --json '{"header":{"dev-index":1, "flags":4}}'
  Netlink error: Invalid argument
  nl_len = 68 (52) nl_flags = 0x300 nl_type = 2
	error: -22	extack: {'msg': 'reserved bit set',
				 'bad-attr': '.header.flags'}

Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 90256f3f
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -400,6 +400,40 @@ class YnlFamily(SpecFamily):
                self._decode_enum(rsp, attr_spec)
        return rsp

    def _decode_extack_path(self, attrs, attr_set, offset, target):
        for attr in attrs:
            attr_spec = attr_set.attrs_by_val[attr.type]
            if offset > target:
                break
            if offset == target:
                return '.' + attr_spec.name

            if offset + attr.full_len <= target:
                offset += attr.full_len
                continue
            if attr_spec['type'] != 'nest':
                raise Exception(f"Can't dive into {attr.type} ({attr_spec['name']}) for extack")
            offset += 4
            subpath = self._decode_extack_path(NlAttrs(attr.raw),
                                               self.attr_sets[attr_spec['nested-attributes']],
                                               offset, target)
            if subpath is None:
                return None
            return '.' + attr_spec.name + subpath

        return None

    def _decode_extack(self, request, attr_space, extack):
        if 'bad-attr-offs' not in extack:
            return

        genl_req = GenlMsg(NlMsg(request, 0, attr_space=attr_space))
        path = self._decode_extack_path(genl_req.raw_attrs, attr_space,
                                        20, extack['bad-attr-offs'])
        if path:
            del extack['bad-attr-offs']
            extack['bad-attr'] = path

    def handle_ntf(self, nl_msg, genl_msg):
        msg = dict()
        if self.include_raw:
@@ -455,11 +489,17 @@ class YnlFamily(SpecFamily):
            reply = self.sock.recv(128 * 1024)
            nms = NlMsgs(reply, attr_space=op.attr_set)
            for nl_msg in nms:
                if nl_msg.extack:
                    self._decode_extack(msg, op.attr_set, nl_msg.extack)

                if nl_msg.error:
                    print("Netlink error:", os.strerror(-nl_msg.error))
                    print(nl_msg)
                    return
                if nl_msg.done:
                    if nl_msg.extack:
                        print("Netlink warning:")
                        print(nl_msg)
                    done = True
                    break