Merge branch 'tools-net-ynl-add-support-for-nlctrl-netlink-family'

Donald Hunter says:

====================
tools/net/ynl: Add support for nlctrl netlink family

This series adds a new YNL spec for the nlctrl family, plus some fixes
and enhancements for ynl.

Patch 1 fixes an extack decoding bug
Patch 2 gives cleaner netlink error reporting
Patch 3 fixes an array-nest codegen bug
Patch 4 adds nest-type-value support to ynl
Patch 5 fixes the ynl schemas to allow empty enum-name attrs
Patch 6 contains the nlctrl spec
====================

Link: https://lore.kernel.org/r/20240306231046.97158-1-donald.hunter@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-03-07 20:28:41 -08:00
commit 196febcb82
8 changed files with 265 additions and 29 deletions

View File

@ -126,8 +126,9 @@ properties:
Prefix for the C enum name of the attributes. Default family[name]-set[name]-a-
type: string
enum-name:
description: Name for the enum type of the attribute.
type: string
description: |
Name for the enum type of the attribute, if empty no name will be used.
type: [ string, "null" ]
doc:
description: Documentation of the space.
type: string
@ -261,14 +262,16 @@ properties:
the prefix with the upper case name of the command, with dashes replaced by underscores.
type: string
enum-name:
description: Name for the enum type with commands.
type: string
description: |
Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
async-prefix:
description: Same as name-prefix but used to render notifications and events to separate enum.
type: string
async-enum:
description: Name for the enum type with notifications/events.
type: string
description: |
Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
list:
description: List of commands
type: array

View File

@ -168,8 +168,9 @@ properties:
Prefix for the C enum name of the attributes. Default family[name]-set[name]-a-
type: string
enum-name:
description: Name for the enum type of the attribute.
type: string
description: |
Name for the enum type of the attribute, if empty no name will be used.
type: [ string, "null" ]
doc:
description: Documentation of the space.
type: string
@ -304,14 +305,16 @@ properties:
the prefix with the upper case name of the command, with dashes replaced by underscores.
type: string
enum-name:
description: Name for the enum type with commands.
type: string
description: |
Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
async-prefix:
description: Same as name-prefix but used to render notifications and events to separate enum.
type: string
async-enum:
description: Name for the enum type with notifications/events.
type: string
description: |
Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
# Start genetlink-legacy
fixed-header: &fixed-header
description: |

View File

@ -189,8 +189,9 @@ properties:
Prefix for the C enum name of the attributes. Default family[name]-set[name]-a-
type: string
enum-name:
description: Name for the enum type of the attribute.
type: string
description: |
Name for the enum type of the attribute, if empty no name will be used.
type: [ string, "null" ]
doc:
description: Documentation of the space.
type: string
@ -371,14 +372,16 @@ properties:
the prefix with the upper case name of the command, with dashes replaced by underscores.
type: string
enum-name:
description: Name for the enum type with commands.
type: string
description: |
Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
async-prefix:
description: Same as name-prefix but used to render notifications and events to separate enum.
type: string
async-enum:
description: Name for the enum type with notifications/events.
type: string
description: |
Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
# Start genetlink-legacy
fixed-header: &fixed-header
description: |

View File

@ -0,0 +1,206 @@
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
name: nlctrl
protocol: genetlink-legacy
uapi-header: linux/genetlink.h
doc: |
genetlink meta-family that exposes information about all genetlink
families registered in the kernel (including itself).
definitions:
-
name: op-flags
type: flags
enum-name:
entries:
- admin-perm
- cmd-cap-do
- cmd-cap-dump
- cmd-cap-haspol
- uns-admin-perm
-
name: attr-type
enum-name: netlink-attribute-type
type: enum
entries:
- invalid
- flag
- u8
- u16
- u32
- u64
- s8
- s16
- s32
- s64
- binary
- string
- nul-string
- nested
- nested-array
- bitfield32
- sint
- uint
attribute-sets:
-
name: ctrl-attrs
name-prefix: ctrl-attr-
attributes:
-
name: family-id
type: u16
-
name: family-name
type: string
-
name: version
type: u32
-
name: hdrsize
type: u32
-
name: maxattr
type: u32
-
name: ops
type: array-nest
nested-attributes: op-attrs
-
name: mcast-groups
type: array-nest
nested-attributes: mcast-group-attrs
-
name: policy
type: nest-type-value
type-value: [ policy-id, attr-id ]
nested-attributes: policy-attrs
-
name: op-policy
type: nest-type-value
type-value: [ op-id ]
nested-attributes: op-policy-attrs
-
name: op
type: u32
-
name: mcast-group-attrs
name-prefix: ctrl-attr-mcast-grp-
enum-name:
attributes:
-
name: name
type: string
-
name: id
type: u32
-
name: op-attrs
name-prefix: ctrl-attr-op-
enum-name:
attributes:
-
name: id
type: u32
-
name: flags
type: u32
enum: op-flags
enum-as-flags: true
-
name: policy-attrs
name-prefix: nl-policy-type-attr-
enum-name:
attributes:
-
name: type
type: u32
enum: attr-type
-
name: min-value-s
type: s64
-
name: max-value-s
type: s64
-
name: min-value-u
type: u64
-
name: max-value-u
type: u64
-
name: min-length
type: u32
-
name: max-length
type: u32
-
name: policy-idx
type: u32
-
name: policy-maxtype
type: u32
-
name: bitfield32-mask
type: u32
-
name: mask
type: u64
-
name: pad
type: pad
-
name: op-policy-attrs
name-prefix: ctrl-attr-policy-
enum-name:
attributes:
-
name: do
type: u32
-
name: dump
type: u32
operations:
enum-model: directional
name-prefix: ctrl-cmd-
list:
-
name: getfamily
doc: Get / dump genetlink families
attribute-set: ctrl-attrs
do:
request:
value: 3
attributes:
- family-name
reply: &all-attrs
value: 1
attributes:
- family-id
- family-name
- hdrsize
- maxattr
- mcast-groups
- ops
- version
dump:
reply: *all-attrs
-
name: getpolicy
doc: Get / dump genetlink policies
attribute-set: ctrl-attrs
dump:
request:
value: 10
attributes:
- family-name
- family-id
- op
reply:
value: 10
attributes:
- family-id
- op-policy
- policy

View File

@ -6,7 +6,7 @@ import json
import pprint
import time
from lib import YnlFamily, Netlink
from lib import YnlFamily, Netlink, NlError
class YnlEncoder(json.JSONEncoder):
@ -66,12 +66,16 @@ def main():
if args.sleep:
time.sleep(args.sleep)
if args.do:
reply = ynl.do(args.do, attrs, args.flags)
output(reply)
if args.dump:
reply = ynl.dump(args.dump, attrs)
output(reply)
try:
if args.do:
reply = ynl.do(args.do, attrs, args.flags)
output(reply)
if args.dump:
reply = ynl.dump(args.dump, attrs)
output(reply)
except NlError as e:
print(e)
exit(1)
if args.ntf:
ynl.check_ntf()

View File

@ -2,7 +2,7 @@
from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \
SpecFamily, SpecOperation
from .ynl import YnlFamily, Netlink
from .ynl import YnlFamily, Netlink, NlError
__all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet",
"SpecFamily", "SpecOperation", "YnlFamily", "Netlink"]
"SpecFamily", "SpecOperation", "YnlFamily", "Netlink", "NlError"]

View File

@ -353,6 +353,9 @@ class NetlinkProtocol:
raise Exception(f'Multicast group "{mcast_name}" not present in the spec')
return mcast_groups[mcast_name].value
def msghdr_size(self):
return 16
class GenlProtocol(NetlinkProtocol):
def __init__(self, family_name):
@ -378,6 +381,8 @@ class GenlProtocol(NetlinkProtocol):
raise Exception(f'Multicast group "{mcast_name}" not present in the family')
return self.genl_family['mcast'][mcast_name]
def msghdr_size(self):
return super().msghdr_size() + 4
class SpaceAttrs:
@ -590,6 +595,16 @@ class YnlFamily(SpecFamily):
decoded.append({ item.type: subattrs })
return decoded
def _decode_nest_type_value(self, attr, attr_spec):
decoded = {}
value = attr
for name in attr_spec['type-value']:
value = NlAttr(value.raw, 0)
decoded[name] = value.type
subattrs = self._decode(NlAttrs(value.raw), attr_spec['nested-attributes'])
decoded.update(subattrs)
return decoded
def _decode_unknown(self, attr):
if attr.is_nest:
return self._decode(NlAttrs(attr.raw), None)
@ -681,6 +696,8 @@ class YnlFamily(SpecFamily):
decoded = {"value": value, "selector": selector}
elif attr_spec["type"] == 'sub-message':
decoded = self._decode_sub_msg(attr, attr_spec, search_attrs)
elif attr_spec["type"] == 'nest-type-value':
decoded = self._decode_nest_type_value(attr, attr_spec)
else:
if not self.process_unknown:
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
@ -721,7 +738,7 @@ class YnlFamily(SpecFamily):
return
msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set))
offset = 20 + self._struct_size(op.fixed_header)
offset = self.nlproto.msghdr_size() + self._struct_size(op.fixed_header)
path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset,
extack['bad-attr-offs'])
if path:

View File

@ -1667,7 +1667,7 @@ def _multi_parse(ri, struct, init_lines, local_vars):
aspec = struct[anest]
ri.cw.block_start(line=f"if (n_{aspec.c_name})")
ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
ri.cw.p('i = 0;')
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")