Commit f036d936 authored by Donald Hunter's avatar Donald Hunter Committed by Jakub Kicinski
Browse files

tools: ynl: Add fixed-header support to ynl



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, which serves as a
default value that can be overridden.

Signed-off-by: default avatarDonald Hunter <donald.hunter@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 26071913
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -261,6 +261,14 @@ 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 defining 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 +301,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
+13 −8
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ class SpecOperation(SpecElement):
        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 name of fixed header struct

        yaml            raw spec as loaded from the spec file
    """
@@ -284,6 +285,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', family.fixed_header)

        # Added by resolve:
        self.attr_set = None
@@ -324,6 +326,7 @@ class SpecFamily(SpecElement):
        msgs_by_value  dict of all messages (indexed by name)
        ops        dict of all valid requests / responses
        consts     dict of all constants/enums
        fixed_header  string, optional name of family default fixed header struct
    """
    def __init__(self, spec_path, schema_path=None):
        with open(spec_path, "r") as stream:
@@ -397,6 +400,7 @@ class SpecFamily(SpecElement):
        self._resolution_list.append(elem)

    def _dictify_ops_unified(self):
        self.fixed_header = self.yaml['operations'].get('fixed-header')
        val = 1
        for elem in self.yaml['operations']['list']:
            if 'value' in elem:
@@ -408,6 +412,7 @@ class SpecFamily(SpecElement):
            self.msgs[op.name] = op

    def _dictify_ops_directional(self):
        self.fixed_header = self.yaml['operations'].get('fixed-header')
        req_val = rsp_val = 1
        for elem in self.yaml['operations']['list']:
            if 'notify' in elem:
+20 −4
Original line number Diff line number Diff line
@@ -278,14 +278,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):
@@ -509,6 +517,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)
@@ -535,7 +550,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:
@@ -545,7 +560,8 @@ 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