Commit 6511743e authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'tools-ynl-couple-of-cmdline-enhancements'

Jiri Pirko says:

====================
tools: ynl: couple of cmdline enhancements

This is part of the original "netlink: specs: devlink: add the rest of
missing attribute definitions" set which was rejected [1]. These three
patches enhances the cmdline user comfort, allowing to pass flag
attribute with bool values and enum names instead of scalars.

[1] https://lore.kernel.org/all/20240220181004.639af931@kernel.org/
====================

Link: https://lore.kernel.org/r/20240222134351.224704-1-jiri@resnulli.us


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 5c4e0f3a e8a6c515
Loading
Loading
Loading
Loading
+34 −9
Original line number Diff line number Diff line
@@ -438,6 +438,26 @@ class YnlFamily(SpecFamily):
        self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP,
                             mcast_id)

    def _encode_enum(self, attr_spec, value):
        enum = self.consts[attr_spec['enum']]
        if enum.type == 'flags' or attr_spec.get('enum-as-flags', False):
            scalar = 0
            if isinstance(value, str):
                value = [value]
            for single_value in value:
                scalar += enum.entries[single_value].user_value(as_flags = True)
            return scalar
        else:
            return enum.entries[value].user_value()

    def _get_scalar(self, attr_spec, value):
        try:
            return int(value)
        except (ValueError, TypeError) as e:
            if 'enum' not in attr_spec:
                raise e
        return self._encode_enum(attr_spec, value);

    def _add_attr(self, space, name, value, search_attrs):
        try:
            attr = self.attr_sets[space][name]
@@ -459,6 +479,9 @@ class YnlFamily(SpecFamily):
                attr_payload += self._add_attr(attr['nested-attributes'],
                                               subname, subvalue, sub_attrs)
        elif attr["type"] == 'flag':
            if not value:
                # If value is absent or false then skip attribute creation.
                return b''
            attr_payload = b''
        elif attr["type"] == 'string':
            attr_payload = str(value).encode('ascii') + b'\x00'
@@ -471,16 +494,18 @@ class YnlFamily(SpecFamily):
                attr_payload = self._encode_struct(attr.struct_name, value)
            else:
                raise Exception(f'Unknown type for binary attribute, value: {value}')
        elif attr.is_auto_scalar:
            scalar = int(value)
            real_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64')
            format = NlAttr.get_format(real_type, attr.byte_order)
            attr_payload = format.pack(int(value))
        elif attr['type'] in NlAttr.type_formats:
            format = NlAttr.get_format(attr['type'], attr.byte_order)
            attr_payload = format.pack(int(value))
        elif attr['type'] in NlAttr.type_formats or attr.is_auto_scalar:
            scalar = self._get_scalar(attr, value)
            if attr.is_auto_scalar:
                attr_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64')
            else:
                attr_type = attr["type"]
            format = NlAttr.get_format(attr_type, attr.byte_order)
            attr_payload = format.pack(scalar)
        elif attr['type'] in "bitfield32":
            attr_payload = struct.pack("II", int(value["value"]), int(value["selector"]))
            scalar_value = self._get_scalar(attr, value["value"])
            scalar_selector = self._get_scalar(attr, value["selector"])
            attr_payload = struct.pack("II", scalar_value, scalar_selector)
        elif attr['type'] == 'sub-message':
            msg_format = self._resolve_selector(attr, search_attrs)
            attr_payload = b''